Friday, September 27, 2013

CSAW CTF Quals: Recon All

Jordan Wiens (100):


The Jordan Wiens recon began where 2012's recon ended, at key.psifertex.com. 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 (pgp.mit.edu, any database works) showed a public key with the User ID "Jordan Wiens (CSAW folks: getting warmer) <csaw@psifertex.com>"   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 (keyserver.gazzang.net). Searching Jordan Wiens in this data base resulted in a picture with the key handwritten out.      
key{mvarioisnotmyhomeboy}
-wardawg

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. 
key{cookies_are_for_csaw}
-wardawg, 

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
key{a959962111ea3fed179eb044d5b80407}
-hawkeye

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 omnom.nom.co" visiting the site's IP address gave the key 
key{1a8024a820bdc7b31b79a2d3a9ae7c02}
-wardawg, lilniqy



Theodore Reed (100):

A hint was that it was within 3 clicks of prosauce.org, 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 prosauce.org with
wget -e robots=off --tries=40 -r -H -l 4 prosauce.org
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.

http://www.youtube.com/all_comments?v=RCTRSK45bS4
key{shmoonconrocksglhfwithcsaw}

-albinotomato

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",
                "Wrong..",
                "Google \"do a barrel roll\"",
                "Did you see: https://www.youtube.com/watch?v=I6OXjnBIW-4"
                "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_ᜄ;
        {
            try
            {
                this.eval_ᜂ();
            }

            catch
            {
                base.Dispose(true);
                throw;
            }
        }

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_ᜀ(this.eval_ᜀ(107));
      this.eval_ᜁ();
      this.eval_ᜂ.Text = string.Format(this.eval_ᜂ.Text, this.eval_ᜀ(resourceManager));
      this.eval_ᜃ.Image = (Bitmap)resourceManager.GetObject("Sorry You Suck");
    }
    else
    {
      this.eval_ᜃ.Image = (Bitmap)resourceManager.GetObject("Almost There");
      this.eval_ᜀ();
    }

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}”



-hackarali


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.

Key{TheISISPasswordIs}



-zlouity

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.

do_csaw




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.

key={SPREYOADPC}

-albinotomato
 Im

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(('128.238.66.219', 14549))
temp = so.recv(1024)
print(temp)
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'
 f.write(writeString)
 f.close()
 a = Popen('gdb', shell=True, stdout=PIPE, stderr=PIPE)
 temp = a.communicate()[0].split(' ')[-21].split('\t')
 #print(temp) 
 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")
 print(result1)
 print(result2)
 output = str(int(result1,0)) + " " + str(int(result2,0)) + "\n"
 so.send(output)
 print("output is " + output)

 print(so.recv(1024))
 print(so.recv(1024))
 print("##########################################################")

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.

key{#r3vers1ng_emul4t3d_cpuz_a1n7_h4rd}

-albinotomato

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 onlythisprogram.py 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:
header=open('header','w+')
header.write('\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00')
header.seek(0)

...

while 1:
    byte1, byte2 = args.infile1.read(1), args.infile2.read(1)
    if not byte1 or not byte2:
        break
    temp.write(chr(ord(byte1) ^ ord(byte2)))

temp.flush()
temp.seek(0)

while 1:
    byte1, byte2 = args.infile1.read(1), temp.read(1)
    if not byte1 or not byte2:
        break
    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
file7 - DOC, DOT, PPS, PPT, XLA, XLS, WIZ
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 = args.infile1.read(1), '\xff'
    if not byte1 or not byte2:
        break
    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 onlythisprogram.py script with the following code commented out:
#args.secretkey.truncate()

#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

secretkeycorrect
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+')
temp.truncate()
header=open('header','w+')
header.write('\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00')
header.seek(0)
key=open('key', 'w+')
key.write('\x40\x50\x3A\xC8\x2D\x69\xF7\xD3\x02\x3A\xF4\xAC')
key.seek(0)
#fuzz.open('fuzz', 'w+')
#fuzz.write('\xff'*256)

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

#temp.flush()
#temp.seek(0)

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


sys.stderr.write('Done.\n')

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

--dotKasper