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.
After connecting to the server we receive this output.
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.
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:
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:
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:
Sending this to the server we get:
Nice! Now we get a message which doesn't mean much, we just have to find some value in memory I guess...
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:
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:
Sending this to the server we get:
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:
Okay great, now we have to control eip... Sounds like fun!
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:
And the final stage 4 code in python:
Sending this along gives us:
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:
And the result of running this payload:
Aand we've got the Flag!
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!
(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!