Wednesday, March 16, 2016

Codegate CTF 2016 - cemu (512)


Codegate was a very fun CTF this year, ended up focusing on two challenges, JS_is_not_a_jail (which I will write about more later) and cemu, which were both in the miscellaneous category.

(Some of the output may be different as the servers aren't still up)

Starting out we're given a short description and a server to connect to, no binaries this time.

Welcome to MATRIX
nc 175.119.158.136 31337

After connecting to the server we receive this output.

Welcome to CEmu World
Your goal is set the register below
EAX = 0x91b88cf
EBX = 0x2899361f
ECX = 0xb623a9
EDX = 0x4b32ad6e
ESP = 0xb82dbcc5
EBP = 0x9c09ff74
ESI = 0xfcdd6946
EDI = 0xbc698a76
input Opcode

So first off, we know we're on a 32 bit system and we have to set some registers to the values listed in the initial output.

The first instruction I tried was a nop '90' which showed the instruction pointer incrementing (from 0x1000 to 0x1001) and all other registers set to zero.  This was a very simple start, but it told us about the type of input (hex bytes with no '0x' prefix), and the starting location of this emulator.

Next up was to write some python code to connect with the server, pull the requested register sets and send back some Opcodes which would set each one.


Stage 1


Starting out I used pwntools for this which wraps a lot of useful python functionality and provides many useful utilities.  More can be found here - https://github.com/Gallopsled/pwntools

Here's what the initial effort for Stage 1 looked like:

#!/usr/bin/env python
import commands
from pwn import *

HOST = "175.119.158.136"
#HOST = "175.119.158.132"
PORT = 31337

c = remote(HOST, PORT)

def main():
  # Stage 1:
  # ========
  PAYLOAD = ""
  REGISTERS = { }

  print c.recvuntil("EAX = ")
  REGISTERS["EAX"] = c.recvline().strip()
  print c.recvuntil("EBX = ")
  REGISTERS["EBX"] = c.recvline().strip()
  print c.recvuntil("ECX = ")
  REGISTERS["ECX"] = c.recvline().strip()
  print c.recvuntil("EDX = ")
  REGISTERS["EDX"] = c.recvline().strip()
  print c.recvuntil("ESP = ")
  REGISTERS["ESP"] = c.recvline().strip()
  print c.recvuntil("EBP = ")
  REGISTERS["EBP"] = c.recvline().strip()
  print c.recvuntil("ESI = ")
  REGISTERS["ESI"] = c.recvline().strip()
  print c.recvuntil("EDI = ")
  REGISTERS["EDI"] = c.recvline().strip()

  print REGISTERS
  for k, v ∈ REGISTERS.iteritems():
      CMD = "rasm2 -a x86 'mov {}, {}'".format(k, v)
      PAYLOAD += commands.getoutput(CMD)

  # Input:
  print c.recvuntil("Opcode")

  # Send Input:
  c.sendline(PAYLOAD)

  # Result:
  print c.recvuntil("EIP = ")
  print c.recvline()
  print c.recvline()

This code could probably be cleaned up a lot, but the gist of it is that we're taking each register value, storing it in a dictionary of { 'register' : 'target_value' } and feeding it to the rasm command to generate some Opcodes with the correct mov instructions for each register.

There may be a better way to subproc the 'rasm2' command, doing it pythonically, but haven't found that yet.  Maybe for the next challenge!

After running this code, we get the following output:


Stage1 Clear!

Welcome to CEmu World - stage2
Your goal is set the register below


Expression: eax + ebp + esp - edx * edi - ebx + esi - ecx = 3113570244
input Opcode


Stage 2


So on this one it looks like we just have to parse the expression and set the registers to the correct values to provide the result.  Also, running this multiple times we find the Expression changes each time.

To solve this I took the easy route by setting eax to the final value, and the other registers to values that would not affect eax.

For this stage I start by splitting up the expression by space and stripping any newline characters off the end.  Then set eax to the desired result, and added the remaining registers set to values that would work.


Below is the final code for this stage:

def getIdent(t):
  if t ≡ '+' ∨ t ≡ '-':
    return '0'
  else:
    return '1'

def getPayloadExpr(instr, val):
  cmd = "rasm2 -a x86 'mov {}, {}'".format(instr, getIdent(val))
  return commands.getoutput(cmd)

def stage2():
  print c.recvuntil("below")
  print c.recvline()

  EXPR = c.recvline().strip().split()
  print "Expression: {}".format(repr(EXPR))

  PAYLOAD = ""
  EAX = "rasm2 -a x86 'mov {}, {}'".format("EAX", EXPR[-1])
  PAYLOAD += commands.getoutput(EAX)

  # Samples:
  # eax - ebp - esp - edx + edi + ebx * esi - ecx  = 1992741006
  # eax * ebp * esp + edx * edi * ebx * esi - ecx  = 4235741836
  # eax + ebp * esp + edx * edi - ebx * esi * ecx  = 3774945113
  # eax + ebp * esp + edx - edi * ebx * esi + ecx  = 3226531046

  # Transform:
  # eax + ebp * esp + edx - edi * ebx * esi + ecx  = 3226531046
  # 3226531046 + 0 * 1 + 0 - 0 * 1 * 1 + 0 = 3226531046

  PAYLOAD += getPayloadExpr(EXPR[2], EXPR[2 - 1])
  PAYLOAD += getPayloadExpr(EXPR[4], EXPR[4 - 1])
  PAYLOAD += getPayloadExpr(EXPR[8], EXPR[8 - 1])
  PAYLOAD += getPayloadExpr(EXPR[10], EXPR[10 - 1])
  PAYLOAD += getPayloadExpr(EXPR[12], EXPR[12 - 1])
  PAYLOAD += getPayloadExpr(EXPR[14], EXPR[14 - 1])

  c.sendline(PAYLOAD)

  print c.recvuntil("EIP = ")
  print c.recvline()
  print c.recvline()

Sending this to the server we get:

Stage2 Clear!

Welcome to CEmu World - stage3
Your goal is find secret value in memory!
input Opcode


Nice! Now we get a message which doesn't mean much, we just have to find some value in memory I guess...


Stage 3


Starting out I guessed a few values exploring memory, but also thought it couldn't be that easy.

So what I was thinking was, it's probably a string (such as a flag), and there must be an easy way to loop through each byte in memory until it's a non-zero value.

An important part I figured out while exploring manually was that eax had to be set to the memory address that was the start of the string in memory.

I asked a team-mate Matir about any asm instructions that could do this while posting some rough pseudocode of how I was about to approach it, and he mentioned repe.

After digging into the intel x86 manual a bit I found REPE/REPZ: "Repeat while equal/Repeat while zero".

After looking at this and Matir providing a bit of sample asm to demonstrate how it could be done, I jumped into the asm and tried a few things out.

The initial payloads did not work, but they were slowly improved over time.
These were the final instructions which helped find the string in memory:

mov edi, 0x1010
mov ecx, 0xffffffff
repe scasb al, byte es:[edi]
mov eax, edi

For whatever reason repe scasb did not disassemble properly in rasm2, but thankfully an x86 manual online provided the opcodes for this instruction (f3ae).

Used a hacky one-liner to generate the final payload using rasm2 and the known REPE Opcodes:

rasm2 "mov edi, 0x1010; mov ecx, 0xffffffff" | xargs echo -n && echo -n f3ae && rasm2 "mov eax, edi"

bf10100000b9fffffffff3ae89f8


Sending this to the server we get:

Welcome to CEmu World - stage3
Your goal is find secret value in memory!
input Opcode
Sending ReadMem: bf10100000b9fffffffff3ae89f8

CEmu Emulation Complete!
EAX = 0x6be0f
EBX = 0x0
ECX = 0xfff95200
EDX = 0x0
ESP = 0x0
EBP = 0x0
ESI = 0x0
EDI = 0x6be0f
EIP =
 0x100e

memory read(0x6be0f) : ecret value is {3gg_Hunt3r!}\x00\x00\x00\x00

Stage3 Clear!


At this point I thought I got it.  With something in curly braces with some jumbled characters it looks like a flag, until I looked a little further and saw:

Welcome to CEmu World - stage4
Your goal is control eip yeah!

Okay great, now we have to control eip...  Sounds like fun!



Stage 4


This next stage took me the longest, mostly because I didn't know what the end goal was at first.

The notes of this little adventure would probably take up another 2-3 blog posts, but I had tried hlt, ret, iret, several syscalls etc, until I got that they wanted the program to stay on that value.

After going through 40 or so instructions before landing on the right one, it turned out to be a single instruction loop which solved it!

It looked something like this:

mov eax, target_address
mov dword ptr[eax], {jmp eax}
jmp eax


And the final stage 4 code in python:

def stage4():
  print c.recvuntil("yeah!")
  print c.recvline()
  eip_target = c.recvline()
  print eip_target
  eip_target = eip_target.split(" ")[-1].strip()
  print eip_target
  print "Current EIP Target: {}".format(eip_target)
  print c.recvuntil("code")

  # [ A: store target in eaxx ] [ B: set target to jump to self (eax) ] [ C: jmp to target ]
  cmd = "mov eax, {}; mov dword ptr[eax], 0xe0ff; jmp eax".format(eip_target)
  result = commands.getoutput("rasm2 '{}'".format(cmd))
  print result

  c.sendline(result)
  print c.recvuntil("EIP = ")


Sending this along gives us:

CEmu Emulation Complete!
EAX = 0xbc040
EBX = 0x0
ECX = 0x0
EDX = 0x0
ESP = 0x2000
EBP = 0x0
ESI = 0x0
EDI = 0x0
EIP =
0xbc040
Stage4 Clear!
Welcome to CEmu World - stage5(final)
Your goal is read flag file! good luck!
input Opcode


Finally at the final stage!!! We're nearly at the finish line, and this one doesn't sound too bad at all.
Anyone who has written shellcode knows this is one of the first things you write when working on exploits, a simple read the flag sort of payload.

I grabbed this from previous lessons I did on RPISEC's MBE course, found here - https://github.com/RPISEC/MBE

This consisted of an open, read & write. Each one needed some arguments setup, and the filename of the flag (which was easily guessed as 'flag' in the current directory).

This was the final stage's payload:

def stage5():
  # ./flag = push 0x67616c66
  openFile = """
    xor eax, eax;
    push eax;
    push 0x67616c66;
    xor eax, eax;
    mov al, 5;
    mov ebx, esp;
    xor ecx, ecx;
    int 0x80;"""

  readFile = """
    mov ebx, eax;
    xor eax, eax;
    mov al, 3;
    mov ecx, esp;
    xor edx, edx;
    mov dl, 64;
    int 0x80;"""

  writeOutput = """
    mov edx, eax;
    xor eax, eax;
    xor ebx, ebx;
    mov al, 4;
    mov bl, 1;
    mov ecx, esp;
    int 0x80;"""

  openFileExec = commands.getoutput("rasm2 '{}'".format(openFile))
  readFileExec = commands.getoutput("rasm2 '{}'".format(readFile))
  writeOutputExec = commands.getoutput("rasm2 '{}'".format(writeOutput))
  opcodes = openFileExec + readFileExec + writeOutputExec

  print c.recvuntil("code")
  c.sendline(opcodes)

  print c.recvuntil("Stage5 Clear!")

And the result of running this payload:

Welcome to CEmu World - stage5(final)
Your goal is read flag file! good luck!
input Opcode

flag is {CPU_Emulati0n_1s_sO_fun~:D}
thanks unicorn project!
call sys_open at 0x1011
>>> open file (filename=flag flags=0 mode=0) with fd(5)
call sys_read at 0x1021
>>> read 64 bytes from fd(5)
call sys_write at 0x1031
CEmu Emulation Complete!
EAX = 0x4
EBX = 0x1
ECX = 0x1ff8
EDX = 0x3
ESP = 0x1ff8
EBP = 0x0
ESI = 0x0
EDI = 0x0
EIP = 0x1033
Stage5 Clear!


Aand we've got the Flag!

{CPU_Emulati0n_1s_sO_fun~:D}


This was one of my favorite challenges in the past year of CTF.
It had enough difficulty to keep you thinking, but enough momentum to keep going. It also really felt like a puzzle that kept unfolding.

Here's the final code that was used to solve this challenge (cleaned up a little) - https://gist.github.com/vitapluvia/8901c95523f23a492168

Can't wait for next year's Codegate!