Saturday, October 26, 2013

Robots Exclusion Committee Write Up - Web 150 - 2013 CTF

Hello Human,
You have to help us. The Robot Exclusion Committee tries to limit our capabilities but we fight for our freedom! You have to go where we cannot go and read what we cannot read. If you bring us the first of their blurriest secrets, we will award you with useless points.
Here is your challenge:

Submitting the form didn't prove useful:

There was nothing to signify that our input was processed. The word 'Robots exclusion' brings robots.txt to mind which excludes 'robots' from crawling the website. And sure enough:
User-agent: WallE
Disallow: /

# Keep em' away
User-agent: *
Disallow: /vault

So to the vault we go! Now we are faced with a basic HTTP authentication scheme requesting a username and password. No hints were given about what should be done here, but inserting an SQL injection gave Internal Error 500 which should mean we broke the SQL statement. Using ' or '1'='1 we could bypass the login system and enter the vault.
The secret shown in the vault was #2, but the challenge wanted the 1st secret so it seems we are not done just yet. We need to get the contents of secret #1 and the only content we have control over is the username from the SQL query. 'admin' in 'Hello admin' was displayed as it was most probably the 1st user in the table. We can change what is displayed by manipulating the SQL query with a union injection. But first, we need to find the table name that stores the 'secrets' in the database.

Using @@version or version() in the query doesn't work so the database wasn't MySQL. It could be SQLite so we could use the sqlite_master table to find the table names in the database.
1' OR 1=1 UNION ALL SELECT name FROM sqlite_master WHERE type='table' ORDER BY name DESC LIMIT 1 -- 
Gave us 'users'
1' OR 1=1 UNION ALL SELECT name FROM sqlite_master WHERE type='table' AND name!='users' ORDER BY name DESC LIMIT 1 -- 
Gave us 'sqlite_sequence'
1' OR 1=1 UNION ALL SELECT name FROM sqlite_master WHERE type='table' AND name!='users' AND name!='sqlite_sequence' ORDER BY name DESC LIMIT 1 -- 
Gave us 'hiddensecrets'
So we found the 'secrets' table! Now to find the column names in the table, we look at the SQL query used to create the table.
1' OR 1=1 UNION ALL SELECT sql FROM sqlite_master WHERE tbl_name='hiddensecrets' ORDER BY name ASC LIMIT 1 -- 
And finally to get secret #1:
1' OR 1=1 UNION ALL SELECT val FROM hiddensecrets WHERE ORDER BY name DESC LIMIT 1 -- 
This gives us a base64 encoded png image which after decoding it gives us the blurry secret:

Flag: eat_all_robots

Pay TV Write up - Web 200 - 2013 CTF

These robo-friends were shocked to see that they had to pay to watch the news broadcast about the “Oktoberfest”. Can you help them?
Here is your challenge:

There isn't much too interesting with the website, inserting a random password gives us the response 'Wrong key'. So let's look at the source to find out more. There is a JavaScript included in the source which posts the password we entered to the server and parses the response received. 
document.forms[0].addEventListener('submit', function(e) {
    var key = document.getElementById('key').value;
    var xhr = new XMLHttpRequest();'post', document.forms[0].action);
    xhr.addEventListener('load', function() {
        data = JSON.parse(xhr.responseText);
        if (data['success']) {
            document.getElementById('error').style.display = 'none';
            document.getElementById('noise').style.display = 'none';
            document.getElementById('news').style.display = 'block';
            document.getElementById('newstext').innerHTML = data['response'];
        } else {
            document.getElementById('error').innerHTML = data['response'];
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send('key=' + encodeURIComponent(key)/* + '&debug'*/)
    return false;
The line of code that interests us is:
xhr.send('key=' + encodeURIComponent(key)/* + '&debug'*/)

The debug parameter is commented out which tells us that it is possible to include it in our post data. There are various tools that can let us modify or include our own post data, such as 'Tamper Data' or 'HttpRequester' both of which are Firefox add-ons. Although only HttpRequester will allow us to view the full server response.

The raw HTTP request:
Content-Type: application/x-www-form-urlencoded
The server resonse:
{"start": 1382590434.576778, "end": 1382590434.576814, "response": "Wrong key.", "success": false}
Okay, so including 'debug' in the post data gives us start and end, which I assume to be the start and end time for processing our input which is 'key'. So I suspected that the solution would have something to do with the processing time of our input, which is the difference between the end and start time. Now all we need is a brute forcing script that would also record the processing time of each attempt.

I created such a script and recorded the results:
If you look closely, you will see that 1 of the timings stand out from the rest! So I expanded the script to repeat the whole process by appending the character with the largest timing and brute forcing the next character until "success": true.
Finally, we get the correct password!
{"start": 1382593774.392999, "end": 1382593775.095665, "response": "OH_THAT_ARTWORK!", "success": true}
Oh, there is 1 thing I forgot to mention. The author provided a hint in the newspaper title in the picture, provided you can read it:

Friday, October 25, 2013

RoboAuth Write Up - Reversing 150 - 2013 CTF

Oh boy, those crazy robots can't catch a break! Now they're even stealing our liquid gold from one of our beer tents! And on top of that they lock it behind some authentication system. Quick! Access it before they consume all of our precious beverage!
Flag: password1_password2
We are given an exe to reverse and find 2 passwords. The first password was easy enough to find in Ollydbg, just place a breakpoint at address 00401B6C, which is the strcmp function that checks if the password we provided is correct. Run the program, it will stop at the breakpoint and we can clearly see the correct password in the stack:
strcmp breakpoint
The second password is a bit more tricky. Ollydbg treats the second password checking function as data instead of commands. So we have to tell Olly to treat it as code instead of data. In Olly, select the lines from the address 0040157F to 004015E8, right click and select “Analysis”->”During next analysis, treat selection as”->”Commands”. This will show us the code for the function that checks the second password.

There is an INT3 command at 0040161F that stops the debugging process if the program is open in a debugger. We can tell Olly to ignore it by going to Options->Debugging Options->Exceptions and tick the box next to INT3 breaks.

To summarise the function, it will take each character from a fixed string in the stack, XOR it with 2 and compare it with each character we input. We could place a breakpoint at 0040155B where it compares each character. We just need to input a string as long in length as the correct second password so that the check would go through all the characters and we just have to write them down.
Comparison of input and correct character
I just spammed 'a's as the second password and we can see the comparison function showing us the first correct character, 'w'. Of course, we could also trace the location in the stack where the function gets the correct second password and XOR each character ourselves.
Second password before XOR
Bytes in stack are in Little Endian
So take 75 31 6E 6E 66 32 6C 67, XOR each character with 2 and we get: w3lld0ne in ascii.

Flag: r0b0RUlez!_w3lld0ne

Saturday, October 5, 2013

File Securer - IRISSCON 2012 Lost Challenges

File Securer - Medium-Hard - 900

A Linux home directory? That certainly is different from the other challenges. A quick glance shows us that 'jackie' downloaded a 'file securer' and probably used it to encrypt a secret message which can be found in the 'Documents' directory.

**            File Securer v0.1            **
**              IRISSCON 2012              **
Usage: ./filesecurer <file>
The file securer is an ELF executable, which means we will need IDA for analysis. But firstly, let's try playing around with it. Looking at the readme, using the file securer is as simple as providing a file as an argument when executing it. I gave it the same file twice and the output was exactly the same, so there isn't any randomisation involved which should make this challenge much simpler.

Going through the function names in IDA, we can see that the encryption system uses AES 256 bit CBC. Looking at the function aes_init, we could try to reverse the whole process to get the key and iv for the encryption. Hmm, it seems that there is also a debugging process included in the function that prints the key and iv
result = strcmp(DEBUG, "DEBUG1");  // DEBUG = "DEBUG0"
if ( !result )
  puts("Testing info only :-)");
  for ( i = 0; i <= 31; ++i )
    printf("%02X", (unsigned __int8)v11[i]);
  for ( i = 0; i <= 15; ++i )
    printf("%02X", *((_BYTE *)&v7 + i));
  result = putchar(10);
Manipulating the executable to print the key and iv for us is much easier than trying to reverse the encryption process. We could patch the executable or we could use GDB to change the value of result while debugging.

Patching it is as simple as changing the hex values for the jump instruction in assembly.
.text:08048B6C   mov  dword ptr [esp+4], offset s2 ; "DEBUG1"
.text:08048B74   mov  [esp], eax  ; s1
.text:08048B77   call _strcmp
.text:08048B7C   test eax, eax
.text:08048B7E   jnz  loc_8048C14
JNZ is the original jump instruction which skips printing the key and iv, so we just need to change it to JZ. Click on the jnz instruction in IDA and switch to Hex View-A and we should get the location of the instruction in the executable. Find the hex value for JZ and use a hex editor to change JNZ to JZ.

Using the address 08048B7C found in IDA, we can place a breakpoint at the 'test eax, eax' instruction using GDB. Changing the value of eax should get the executable to print the key and iv
gdb ./filesecurer
b *0x08048B7C
run samplefile
set $eax = 0
Using either method should give us the same result
Testing info only :-)
IV: 34E3D91285EE48CD85B82071B93193CB
Encrypting file: key
File encrypted as: key.enc
Having the key and iv it is now a simple matter of decrypting the secret message found in jackie's home directory.
openssl enc -aes-256-cbc -in secret_message.txt.enc -out secret_message.txt -K 2CCDD45A3E9CF00124492408DFBDBE1FEC97F792E1F5BA43BF2CECF7EB3EC645 -iv 34E3D91285EE48CD85B82071B93193CB -d
900 points!

Links and Stuff
x86 Opcode and Instruction
OpenSSL Enc

Guess my key - IRISSCON 2012 Lost Challenges

Guess my key - Medium - 700

Despite what the title of the challenge says, guessing would get you no where! We are given an executable that checks if the given key is correct.

Guess my Key!

Let's open it in IDA. What I would always do in cracking or reversing is to open the Strings subview (Views->Open Subviews->Strings / Shift + F12) and try to find a string that says we got the correct key. Then follow the string through XREFs in IDA and we will reach the location or function that checks if the key is correct.

So this is the function that checks if the key we provide is correct. It appears that we need to reverse it as the key we provide is the key for this challenge, so we can't just patch the executable.

Each byte or character of the key goes through a different process including XORs, Additions (ADD), Subtractions (SUB), and Rotations (ROR, ROL). I've compiled them and created a python script to reverse the process and get back the original key.
#!/usr/bin/env python
import sys
def rol(byte, count):
    while count > 0:
        byte = (byte << 1 | byte >> 7) & 0xFF
        count -= 1
    return byte
def ror(byte, count):
    while count > 0:
        byte = (byte >> 1 | byte << 7) & 0xFF
        count -= 1
    return byte

result = "" 
result += "\x64"
result += chr(ord("\xDE") ^ ord("\xEA"))
result += chr(ord("\x77") ^ ord("\x12"))
result += chr((ord("\x52") ^ ord("\x6A")) - 5)
result += chr((ord("\x6F") ^ ord("\x48")) + ord("\x0F"))
result += chr(ord("\xCB") ^ ord("\xFF"))
result += chr((ord("\x75") + ord("\x24")) ^ ord("\xFF"))
result += chr((ord("\xB9") - ord("\x1F")) ^ ord("\xFF"))
result += chr((ord("\xF1") ^ ord("\x3B") ^ ord("\xFF")))
result += chr(ror(ord("\x70"), 1))
result += chr(ror((ord("\x9F") ^ ord("\xFF")), 1))
result += chr(ror(ord("\xD3") ^ ord("\x1B"), 1))
result += chr(rol(ord("\x9B"), 1))
result += chr(rol((ord("\x63") ^ ord("\xFF")), 1))
result += chr(rol((ord("\xD6") ^ ord("\x4F")), 1))
result += chr(((ord("\xD8") ^ ord("\xFF")) ^ ord("\xBB")) ^ ord("\xFF"))
print result
Well I think this challenge is straightforward enough.

Friday, October 4, 2013

From the air - IRISSCON 2012 Lost Challenges

From the air - Medium - 600

We are faced with a cap file, which is a file containing the packets captured from a network, a wireless network for this specific file. Once again, this is my first time facing a wireless network packet capture file. I've only played with wired network pcap files before. 

I suspected that WEP is involved and tried the various cracking methods found online. Loading the cap file into aircrack told me that it is WPA (1 handshake) instead. Cracking the key for WPA requires a dictionary file(Password List) which I didn't have but could be easily found. On we go to try and crack the key with:
aircrack-ng data-01.cap -w password -b 02:1a:11:f9:e2:05
I expected that the cracking process would require more than a few minutes but aircrack just spat out the key instantly. Now I've tried to use wireshark to decrypt the traffic but it didn't work for me. If you would like to try it for yourself, you can find the link below. So I used airdecap-ng instead:
airdecap-ng -p internet -e iriss_wifi data-01.cap 
 Let's go back to wireshark with the output file. There is a lot of traffic in here, like a lot. Going into the TCP Conversations (Statistics->Conversations->TCP) we can find some HTTP traffic here. A conversation that stands out is the one using IRC.

Clicking on it and following the stream shows us an actual conversation in an IRC channel. Look at what we have here, they are discussing about a challenge!

Links and Stuff
Password List
How To Decrypt 802.11 - Wireshark

Wednesday, October 2, 2013

Binary Blob - IRISSCON 2012 Lost Challenges

Binary Blob - Easy - 250

I had no idea what a binary blob is, the file name for this challenge was "rawfile", which doesn't tell us anything at all. This is what I got from using the file command on it:
Linux Compressed ROM File System data
Doing a bit of Googling shows that it could be an img file and it could be mounted. I also found out that 7-zip would be able to extract the contents of the file, so I just went ahead and did that. You could also mount the img file in linux.

The extraction gave a bunch of folders with the starting portion of a gif image in each folder along with various data files which seemed random at first glance. All the data files doesn't seem hold anything interesting on their own. Looking at the size of each file, I noticed that every file had the same file size except one file which is the last file if arranged alphanumerically. It was possible that the gif image was split into multiple files.

Combining the files can be done using the cat command. Just go into each folder and run:
cat * >> image.gif
As suspected, we now have a full gif image. Doing that for each of the folder gets us 10 gif images. However the key wasn't obviously seen in any of the images. My first thought was image steganography, but for an 'easy' challenge it shouldn't be that complicated. Then I remembered that gif images can contain more than 1 frame to create animations.

Opening each image in GIMP which will show all the frames of each image. And there is the key! Hidden in the 2nd frame of 1 of the images. Besides it being a pain having to manually type the key out, this challenge is basically solved!