Threat Level: green Handler on Duty: Guy Bruneau

SANS ISC: SQL injection and division by zero exceptions - SANS Internet Storm Center SANS ISC InfoSec Forums


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!
SQL injection and division by zero exceptions

SQL injections are my favorite vulnerabilities. Of course, every penetration tester loves them since they are (in most cases) critical, however what I like with them is that there are so many ways to exploit even the apparently-looking remote or unexploitable cases.

The particular case I will describe below is very closely related to a previous diary I posted in 2016 – you can read it here. Let’s dig into it!
Again, our target is a web application which, in this case, accepted a POST HTTP request containing JSON. The request looked something like this:

POST /api/customers HTTP/1.1

{"contact_name":"something","company_name":"something else","internal_id":"3298"}

As shown above, we have three parameters which we should test for SQL injection. Due to specifics of the tested web application, and the way the results are displayed back (i.e. it is partially out of band), automated tools such as Burp or sqlmap did not find any vulnerable parameters.

Manual testing, however, indicated that the last parameter, internal_id, is potentially vulnerable to SQL injection. By inserting our favorite character it was possible to cause an error (displayed on a different web page). Enough to make every penetration tester’s hand sweat!

The next step is typically to get sqlmap working with this – no point in doing all the extraction manually. Now that we know where is the SQL injection, the easiest way to pass this to sqlmap is to save the request with Burp and then mark the injection place with * - this will indicate sqlmap where the injection is.

Even with this, sqlmap did not work correctly, so I had to dig further manually. It turned out that there was some kind of filtering on the server side – attempts to add delays (i.e. WAITFOR DELAY) or CASE keywords all failed: the only keyword that actually worked was SELECT.

On the other (out of band) web page I was able to see some errors – in cases when a banned keyword was used there was a generic error. Also, it was possible to induce the division by zero error by modifying the SQL query to something like this:

3298’ AND 1=1/0 --

Ok, so we’re getting somewhere. As with all blind SQL injection vulnerabilities, we need to have a true and a false case. By being able to cause a division by zero error we have a false case (and the true case is when the application works).

How to extract a byte now? Let’s see: when we guess a byte, we want to cause a division by zero error, while in other cases we want the application to work OK. Another limitation is that we can use only the SELECT keyword (for some reason it was not blocked/filtered by the backend application). And this is the solution:

3298’ OR 1=1/(SELECT ASCII(SUBSTRING(HOST_NAME(),1,1))-X) --

What are we doing here? We are taking the first character returned from the HOST_NAME() method which returns (obviously) the local host’s name. Then we convert that character to its ASCII value and subtract a number X from it.
This allows us to cycle through all ASCII values – once we guess the value of the first character of the host’s name, we will cause a division by zero error allowing us to conclude the first character’s value. With this, we can further extract practically anything from the database, as long as the user that the web application is using to connect to the database has rights to read the data.

As with previous SQL injection examples, this again shows how proper, strict filtering (and using parametrized queries) is the only way to prevent exploitation.

Want to learn more about web application security? Join me in Paris, 12th -17th of March for the fantastic SEC542: Web App Penetration Testing and Ethical Hacking (GWAPT) course!

--
Bojan
@bojanz
INFIGO IS

I will be teaching next: Web App Penetration Testing and Ethical Hacking - SANS London February 2019

Bojan

375 Posts
ISC Handler
Not sure what I'm missing, but why not just pull the ASCII value of the first character and see what it is so you have the first character of the host name rather than subtract X and cycle through? It is early and my brain may still need coffee. :-) I'm absolutely certain that you will enlighten me as to what I'm missing shortly.
Anonymous
It's a blind SQL injection vulnerability so we can't simply pull the values because we do not see (directly) results of the SQL query we inject.
So we needed a true/false case to determine one by one the value of the character we want to extract.
Hope this clears it a bit? If not - just shoot and I'll write further :)

Bojan
Bojan

375 Posts
ISC Handler
Got it. It was early, no coffee, and I was focusing so much on the ASCII substring part of the query, that I neglected to remember that the goal was to get the divided by zero error. So if the host name starts with "S", then once we cycle to where X = 83, then I believe we'd have our error.
Anonymous
That's it! Coffee always helps :)
Bojan

375 Posts
ISC Handler

Sign Up for Free or Log In to start participating in the conversation!