Blind SQLi Timing Checks and DoS

wspires's Avatar

wspires

02 Dec, 2015 10:56 PM

I have been testing Arachni's experimental branch against a few vulnerable applications (Hackazon in this case) and have run into an issue where Arachni causes a DoS against a local target web server using the following options:

./arachni http://172.x.y.z:8000/ --plugin=autologin:url=http://172.x.y.z:8000/user/login,parameters='username=user&password=test123',check='Logout' --scope-exclude-pattern logout --timeout 02:00:00 --http-request-concurrency=1 --http-request-timeout=10000 --browser-cluster-ignore-images --browser-cluster-pool-size=1 --audit-with-raw-payloads --checks=sql_injection_timing
I was able to trace this back to the Blind SQLi timing checks by monitoring the scan and saw the number of Apache pids and an excessive number of CLOSE_WAIT's for connections on the target host when Arachni started the Blind SQLi timing checks. I also monitored the mysql database on the target for long running queries and the Apache logs so I could see what Arachni was sending to hang the server:
while a==a; do echo "Apache PIDs: ps -ef | grep apache | grep -v grep | wc -l"; echo "CLOSE_WAIT Connections: netstat -an | grep CLOSE_WAIT | grep ":8000" | wc -l"; mysql -uhackazon -p****** -e"SELECT TIME,INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='hackazon'";echo "Apache Log: grep "sleep(4)" /var/log/apache2/access.log | tail -1 | cut -d"]" -f2"; echo "##########################"; sleep 5; done
After a few minutes into the Blind SQLi timing checks, the target host becomes unresponsive. I've tried the previously mentioned suggestion for rate-limiting concurrent connections, however it doesn't seem have an affect in this scenario. This issue seems to happen when a successful Blind SQLi attack occurs against the target within a query's WHERE clause and large tables:
Apache PIDs: 152
CLOSE_WAIT Connections: 152
+------+--------------------------------------------------------------------------------------------+
| TIME | INFO                                                                                       |
+------+--------------------------------------------------------------------------------------------+
|    0 | SELECT TIME,INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='hackazon'                 |
|  182 | SELECT * FROM 'tbl_categories' WHERE 'tbl_categories'.'categoryID' = '49'=sleep(4)=''  LIMIT 1 |
+------+--------------------------------------------------------------------------------------------+
Apache Log:  "GET /category/view?id=49'=sleep(4)=' HTTP/1.1" 200 5681 "-" "Arachni/v2.0dev"
The attack results in a sleep(4) occurring for every row when the condition is false, so it creates a very long running query (i.e. ~4 mins for the query above with some other queries taking over 14 mins). Since this happens for a number on inputs on this target, I believe this is why I'm seeing so many Apache PIDs and CLOSE_WAITs occurring that eventually kills the server. Is it possible to look for dangerous conditions such as this with the timing checks and selectively throttle only the timing checks when a connection has been open longer than some safe upper limit (i.e. sleep(4) + some_safe_upper_limit) to ensure a target doesn't get DoS'd?

I tried testing this in the latest nightly build instead of running directly from the experimental branch, but scans seem to be hanging at "Processing plugins" with the Nov. 23rd nightly build.

  1. Support Staff 1 Posted by Tasos Laskos on 02 Dec, 2015 11:05 PM

    Tasos Laskos's Avatar

    I don't think this has to do with HTTP request throttling, it looks to be solely the result of the SQL injection payload and I'll fix it ASAP.

    Thanks a lot for the information, I'll let you know once a nightly is available that fixes this issue.

    Cheers

  2. Support Staff 2 Posted by Tasos Laskos on 02 Dec, 2015 11:23 PM

    Tasos Laskos's Avatar

    Come to think about it again, the high DB query runtimes may not be related to the payload, but by resource exhaustion due to the many Apache workers.
    Especially since the SQL query has a LIMIT clause.

    Does the issue occur after uncommenting this line?:
    https://github.com/Arachni/arachni/blob/experimental/lib/arachni/ht...

  3. Support Staff 3 Posted by Tasos Laskos on 03 Dec, 2015 12:17 AM

    Tasos Laskos's Avatar

    I did a little more research, a solution to this seems to only exist for MySQL >= 5.6.

    I figured with the LIMIT clause it wouldn't be the payload, but from what I could find it turns out that things work exactly the way you described.

    The sleep() function call is executed for each row, and even when injected as a subquery ((select sleep(4)) it'll still behave the same way for any version < 5.6.

    If you are worried about stressing remote MySQL servers you better not load the sql_injection_timing check or specify the mssql,pgsql platforms which will skip MySQL payloads.

  4. 4 Posted by wspires on 03 Dec, 2015 03:55 PM

    wspires's Avatar

    I tried uncommenting that line you suggested and the results are similar as before:

    ##########################
    Apache PIDs: 152
    CLOSE_WAIT Connections: 191
    +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | TIME | INFO                                                                                                                                                                                                                                                                                                                                                                                                                                         |
    +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    |    0 | SELECT TIME,INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='hackazon'                                                                                                                                                                                                                                                                                                                                                                   |
    |  417 | SELECT * FROM 'tbl_products' LEFT JOIN 'tbl_category_product' ON 'tbl_category_product'.'productID' = 'tbl_products'.'productID' WHERE 'tbl_category_product'.'categoryID' IN (2,3,4,5,6,7,8,9,10,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52) AND 'tbl_products'.'name' LIKE '%1'=sleep(4)='%' AND 'tbl_products'.'Price' >= '0' AND 'tbl_products'.'Price' <= '0' |
    +------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    
    I believe the resource exhaustion is an indirect result of the long running query that's created with the attack payload. All of those Apache procs are hanging around in CLOSE_WAIT until those long running queries return to allow the connections to fully close. I don't think there is anything that Arachni can do to force that connection to fully close when the DB is tying up the Apache connections in CLOSE_WAIT.

    The reason why I was looking at request throttling is because throttling the rate of the timing test requests once something like this occurs during a scan may allow the rest of a scan to finish while waiting for those long running queries to return for the timing tests. Another way to handle it once something like this is detected is to just bail out of the remaining mysql timing checks altogether and report the vuln and potential DoS condition to the user. I'm not sure how possible something like that would be though.

    So far I haven't noticed where Blind SQLi has been reported in any of the scans where I ran into this, even though the payload seems to be executing. This may be due to the excessive time it takes for the query to return, but I'm not sure if that would cause a reporting issue.

  5. Support Staff 5 Posted by Tasos Laskos on 03 Dec, 2015 04:08 PM

    Tasos Laskos's Avatar

    The issues aren't being reported because the server has become unusable so there's no way to verify them.
    This is just the first stage of the timing attacks.

    As for throttling the timing attacks, that happens during the verification phases, it's assumed that the server will make it past the initial candidate gathering phase though.

    There usually are server side timeouts for sql queries to prevent these types of problems and the scanner can only do so much.

    If you're worried about that happening in real world circumstances the only solution is to not perform sql injections using timing attacks against MySQL.

  6. Tasos Laskos closed this discussion on 07 Dec, 2015 09:48 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac