Automating Blind SQL Injection
Tuesday 27th September 2022
SQL vulnerabilities have always been a weakness for me. Numerous boxes have left me looking for hints or falling back to writeups because I've missed a blatant injection attack. So, feeling a bit weary of OffSec's Proving Ground boxes, I decided to work my way through PortSwigger's Learning Path and potentially work towards getting certified for Burp Suite...
One method I've found that always help's me retain knowledge is automating a manual attach somehow, combining my background as a software engineer with PenTesting. My latest experiment was automating a Blind SQL injection using conditional errors. The testbed for this was a lab over at PortSwigger, and you can find my PoC Python script on my GitHub. The motivation for writing this was twofold: to increase my Python and SQL knowledge and speed up the process instead of relying on Burp Suite Community's throttled Repeater. I must point out that I fully believe Burp Suite Pro is worth the £399 yearly fee, but since I only use it in a hobbyist capacity at the moment, I can't quite justify it.
Required Input
The easiest/quickest way to get this tool working was to capture a request in Burp's Proxy, inject a string to mark the place for SQL injection and save it to a text file.
GET /filter HTTP/1.1
Host: 0a2100af03b0c51bc13f5497001f0067.web-security-academy.net
Cookie: TrackingId=xyz[[INJECTION_POINT]]; session=UYHRV9XYKEfDLShUUbvMrkIZ0ofL1jBd
Test this out!
If you want somewhere to test this tool out, have a look at this lab on PortSwigger.
Execution
The script executes the following stages.
Firstly, it checks that inputting invalid SQL to the target field triggers an error. If it doesn't, w assume the field used is not susceptible to this type of injection.
Then It checks that whatever table name is passed in actually e.
Next, it checks that a row with a specified column value (e.g. username = 'admin') exists.
Finally, we enumerate the length of the value we are aiming to enumerate. To do this, we check LENGTH(fieldToEnumerate)=x until it returns true and doesn't throw an error. Then we repeat the process for each character, checking it for a match with each character in our wordlist.
The output looks something like this:
After finishing the first PoC, I thought of a few ways it could be improved in the future.
My Python is rather rusty, so I expect there are heaps of better ways to rewrite this tool.
Expand it to support conditional UI errors, rather than just "Internal Server Error". The main challenge is adding another set of SQL queries that return true/false for the same actions as an error would be thrown.
The code should be split up into smaller, reusable modules. For example, the code that checks a table, column etc. does exist could be helpful to a whole load of different attacks, not just conditional errors.
When I get the time, I'll work on adding the above. It would be great to flesh this out into more of a reliable tool than just a PoC. In the meantime, feel free to tear the code apart and use it for whatever!