Nested SQL Injections ⚓
09 Jun 2012I recently did something along this line, and this technique is really cool. (I prefer to call it “inception” injection). Its pretty easy once you figure it out, so here it goes.
If the result of the first query is used as an input in the second query, and the first query is vulnerable, we can use the output as a “input variable” into the second query itself. This would be useful in places where the second query has a better display method than the first one (for instance length restrictions).
Query 1:
This query is usually accompanied with:
Query 2:
Assuming something like a profile page:
#Injection
Injecting the first query (basic)
Everything after # should be treated as a comment. Hence forward, I would not write stuff after # for brevity.
Thinking backwards, we could create a custom query for user_details:
This would show the details of the first user in the profile page. Let’s think a bit larger:
Usually, this won’t work (different number of columns in results). You’d have to use ORDER BY to guess the number of columns. Writing only the UNION
part now:
So we realize that user_details has 3 columns. Coming back, we could do:
That would give us details upto 1000 characters (GROUP_CONCAT limits). To mitigate those limits:
Change the OFFSET and you’re ready to roll.
Inception Injection
This was all a theoritical attack on the second query. Granted you could do lots of stuff from here on the first query, but it is far less responsive (Doesn’t give much output). The only thing you can modify is the email, which offers you a single field.
However, the only attack vector ($_SESSION
) for the second query is not directly controlled, but comes instead from the result of the first query. So to perform this attack on the second query, we take the second injection, and use it inside the first one.
Although we have been writing injection code starting with UNION, it actually would start with ‘ UNION… Using our last injection code for the second query here, it becomes:
What happens on the server side:
and the second query becomes:
Note that we still have to keep a # at the end of the inner query. There are portions after # which we still need to discard. Feel free to contact me if you have any further doubts. I am sure this is a well-known and used by people already, but this was something new to me.
Published on June 09, 2012