Windows pwn學習筆記

2021-02-21 邑安全
安裝winpwn

pip install winpwn
pip install pefile
pip install keystone-engine
pip install capstone

棧溢出相關結構體

32為系統下SEH結構體

//sehFrame
_EH3_EXCEPTION_REGISTRATION struc ; (sizeof=0x10, align=0x4, copyof_4)
0x0 Next dd ? ; offset
0x4 ExceptionHandler dd ? ; offset
0x8 ScopeTable dd ? ; XREF: _main+21/w ; offset
0xC TryLevel dd ? ; XREF: _main+57/w
0x10 _EH3_EXCEPTION_REGISTRATION ends

//scopeTable
_EH4_SCOPETABLE struc ; (sizeof=0x10, align=0x4, copyof_9, variable size)
0x0 GSCookieOffset dd ?
0x4 GSCookieXOROffset dd ?
0x8 EHCookieOffset dd ?
0xC EHCookieXOROffset dd ?
0x10 ScopeRecord _EH4_SCOPETABLE_RECORD 0 dup(?)
0x10 _EH4_SCOPETABLE ends

//scopeTable_Record
_EH4_SCOPETABLE_RECORD struc ; (sizeof=0xC, align=0x4, copyof_8)
0x0 EnclosingLevel dd ?
0x4 FilterFunc dd ? ; offset
0x8 HandlerFunc dd ? ; offset
0xC _EH4_SCOPETABLE_RECORD ends

觸發異常源碼

GS Cookies 驗證代碼

void __cdecl ValidateLocalCookies(void (__fastcall *cookieCheckFunction)(unsigned int), _EH4_SCOPETABLE *scopeTable, char *framePointer)
{
unsigned int v3; // esi@2
unsigned int v4; // esi@3

if ( scopeTable->GSCookieOffset != -2 )
{
v3 = *(_DWORD *)&framePointer[scopeTable->GSCookieOffset] ^ (unsigned int)&framePointer[scopeTable->GSCookieXOROffset];
__guard_check_icall_fptr(cookieCheckFunction);
((void (__thiscall *)(_DWORD))cookieCheckFunction)(v3);
}
v4 = *(_DWORD *)&framePointer[scopeTable->EHCookieOffset] ^ (unsigned int)&framePointer[scopeTable->EHCookieXOROffset];
__guard_check_icall_fptr(cookieCheckFunction);
((void (__thiscall *)(_DWORD))cookieCheckFunction)(v4);
}

會驗證兩個條件:

1、framePointer[scopeTable->GSCookieOffset] ^ framePointer[scopeTable->GSCookieXOROffset]== __security_cookie
2、framePointer[scopeTable->EHCookieOffset] ^ framePointer[scopeTable->EHCookieXOROffset]== __security_cookie

要繞過這檢查1,可以偽造scopeTable->GSCookieOffset=0xfffffffe。但是對於條件2,還沒有辦法。

異常觸發函數

int __cdecl _except_handler4_common(unsigned int *securityCookies, void (__fastcall *cookieCheckFunction)(unsigned int), _EXCEPTION_RECORD *exceptionRecord, unsigned __int32 sehFrame, _CONTEXT *context)
{
// 異或解密 scope table
scopeTable_1 = (_EH4_SCOPETABLE *)(*securityCookies ^ *(_DWORD *)(sehFrame + 8));

// sehFrame=Next, framePointer=ebp
framePointer = (char *)(sehFrame + 16);
scopeTable = scopeTable_1;

// 驗證 GS
ValidateLocalCookies(cookieCheckFunction, scopeTable_1, (char *)(sehFrame + 16));
__except_validate_context_record(context);

if ( exceptionRecord->ExceptionFlags & 0x66 )
{
.
}
else
{
exceptionPointers.ExceptionRecord = exceptionRecord;
exceptionPointers.ContextRecord = context;
tryLevel = *(_DWORD *)(sehFrame + 12);
*(_DWORD *)(sehFrame - 4) = &exceptionPointers;
if ( tryLevel != -2 )
{
while ( 1 )
{
v8 = tryLevel + 2 * (tryLevel + 2);
filterFunc = (int (__fastcall *)(_DWORD, _DWORD))*(&scopeTable_1->GSCookieXOROffset + v8);
scopeTableRecord = (_EH4_SCOPETABLE_RECORD *)((char *)scopeTable_1 + 4 * v8);
encloseingLevel = scopeTableRecord->EnclosingLevel;//-2跳出後面的循環
scopeTableRecord_1 = scopeTableRecord;
if ( filterFunc )
{
// 調用 FilterFunc
filterFuncRet = _EH4_CallFilterFunc(filterFunc);
.
if ( filterFuncRet > 0 )
{
.
// 調用 HandlerFunc
_EH4_TransferToHandler(scopeTableRecord_1->HandlerFunc, v5 + 16);
.
}
}
.
tryLevel = encloseingLevel;
if ( encloseingLevel == -2 )
break;
scopeTable_1 = scopeTable;
}
.
}
}
.
}

這裡要劫持filterFunc,就需要劫持scopeTable。這需要滿足兩個條件:需要能覆蓋掉sehFrame結構體,並且能洩露securityCookies。

payload

#偽造scopeTable
scopeTable = [
0x0FFFFFFFE, #GSCookieOffset
0, #GSCookieXOROffset
0x0FFFFFFCC, #EHCookieOffset
0 #EHCookieXOROffset
]
scopeTable_Record = [
0xfffffffe, #EnclosingLevel=-2
system('cmd'), #FilterFunc
0
]
sehFrame = [
Next, #original
ExceptionHandler, #original
scopeTable_addr, #fake
trylevel #如果要偽造trylevel,就需要修改scopeTable,否則就不篡改,維持original
]
payload = flat(scopeTable + scopeTable_Record)
payload += padding
paylaod += GS#___security_cookie 相當於canary
payload += Next + ExceptionHandler +scopeTable_addr + flat(sehFrame)#覆蓋sehFrame結構

其中GS的位置計算方法如下:要滿足[ebp + scopeTable->EHCookieOffset] ^ [ebp + scopeTable->EHCookieXOROffset]=GS,scopeTable結構體的EHCookieOffset變量和EHCookieXOROffset變量所對應的ebp的偏移的位置的值抑或後等於GS。因此通常將EHCookieXOROffset設置為0,那麼GS放置的位置就等於ebp + scopeTable->EHCookieOffset。

64位與32位的區別

1、windows 64位程序函數調用的參數順序依次為rcx,rdx,r8,r9
2、在調用system(cmd.exe)過程中,若出現MOVAPS [rsp+0x4f0],xmm0之類的錯誤而導致不能反彈shell,這是因為MOVAPS指令需要16位元組對齊,因此需要在rop鏈中修改gadget來調整棧空間

堆溢出相關結構體

32位下,chunk頭部欄位信息

ntdll!_HEAP_FREE_ENTRY
+0 Size #chunk的大小,實際大小為Size*8
+2 PreviousSize #前一個chunk的大小,實際大小*8
+4 SmallTagIndex #用於檢查堆溢出的Cookie
+5 Flags #標誌位
+6 UnusedBytes #用於對齊的字節數
+7 SegmentIndex #所屬堆段號
+8 FreeList :[FD-BK]

Flags標誌位:
0x01 Busy #該塊處於佔用狀態
0x02 Extra present #該塊存在額外描述
0x04 Fill pattern #使用固定模式填充堆塊
0x08 Virtual Alloc #虛擬分配
0x10 Last entry #該段最後一個堆塊

SmallTagIndex 實際上是安全cookie,算法如下:_HEAP._HEAP_ENTRY.cookie=_HEAP_ENTRY.cookie^((BYTE)&_HEAP_ENTRY/8)

Heap Entry相當於Linux下的chunk,windows對前8個字節進行了加密,加密方式:與HEAP結構0x50偏移處8個字節抑或

例題:2020強網杯wingame


例如0xE50000處為HEAP結構,其HEAP+0x50為解密密鑰0C5FBB3EFE5600,而一般密鑰都是00結尾

將chunk的前8個字節與密鑰逐位異或,得到21000120 01020008。size=0x21*8=0x108

利用方式1、修改棧返回地址ROP(最常用)

首先需要實現任意讀寫,洩露棧地址的過程如下:
ntdll -> ntdll!PebLdr洩露peb ->計算處teb -> 棧地址 ->遍歷查找ret地址

ret_content = base + 0x239a
ret_addr = 0
for i in range(stackbase,stackbase-0x1000,-4):
if ret_addr==0:
tmp = re(i)
if tmp==ret_content:
ret_addr = i
break
assert ret_addr>0

一段有用的gadget : mov [rcx],rdx; ret
這段gadget可以在ntdll.dll中可以找到,如果配合上pop rcx;ret以及pop rdx;ret可以實現任意地址寫並且在rop中傳參時也能發揮很好的作用

在ida中搜索peb偏移的方法:

現在微軟應該是把在線符號表給牆了,因為某些原因不能科學上網(懶),所以在用windbg的時候無法下載符合本地系統的pdb。這裡我使用x64dbg進行調試。
1、在ida中打開ntdll,搜索函數LdrQueryImageFileExecutionOptions,交叉引用找到調用它的地方,如下圖所示:

2、在上面可以發現一個位於.data的全局變量peb_44(我自己命名的),然後找到它在.data中的位置,如下圖所示:

3、可以看到peb_44的偏移為ntdll+0x11dc54(這個偏移是我本機win10 版本號為18363的32位ntdll的偏移)
4、最後在調試器中定位到ntdll+0x11dc54,可以看到一個peb+0x44的值,從而可以洩露peb。

在NT內核系統中fs寄存器指向TEB結構,TEB+0x30處指向PEB結構,PEB+0x0c處指向PEB_LDR_DATA結構,PEB_LDR_DATA+0x1c處存放一些指向動態連結庫信息的鍊表地址,win7下第一個指向ntdl.dll,第三個就是kernel32.dll的。可以通過查看線程TEB+0x30的內容檢查是否為正確的PEB地址或者查看PEB+0xc是否為ntdll中的地址。
5、洩露棧地址
PEB->TEB->stack
PEB和TEB的偏移是固定的,在本地調試中的偏移為TEB=PEB+0x3000
在TEB前三個指針都是棧的指針,第一個估計是ebp附近的SEH_RECODE[1]的地址指針,第二個估計是stack base,第三個估計是stack end。我們搜索棧空間尋找返回地址時,大概從stack base-0x1000開始搜索到stack base這一個頁面的內容就行了。

從kernel32.dll洩露ntdll

如果原程序中沒有ntdll的導入表,可以從kernel32.dll中洩露,方法如下(源自https://xz.aliyun.com/t/6319#toc-4) :
可以從kernel32.dll中定位到NtCreateFile函數的偏移,因為NtCreateFile函數是從ntdll.dll的導入函數。在我win10 18363虛擬機中,偏移為kernel32.dll+0x819BC。
再進一步,如果只洩露了一個dll動態庫的地址,只要其有其他dll庫的導入函數,我們就有可能從其內存空間中洩露處其他dll庫的地址。

2、篡改PEB中的函數指針

PEB結構中存放了RtlEnterCriticalSection()和RtlLeaveCriticalSection()函數指針,在程序正常退出時會調用ExitProcess(),為了同步線程該函數又會調用RtlEnterCriticalSection()及RtlLeaceCriticalSection()進行處理。

//32位
RtlEnterCriticalSection = &PEB + 0x20;
RtlLeaveCriticalSection = &PEB + 0x24;

3、UEF

系統默認異常處理函數(UEF,Unhandler Exception Filter)是系統處理異常時最後調用的一個異常處理例程,在堆溢出中,只需將這一地址覆蓋為我們的shellcode地址即可。獲取UEF地址的方法可以通過查看SetUnhandledExceptionFilter()的代碼來定位,接著再找到操作UnhandledExceptionFilter指針的MOV指令

77E93114 A1 B473ED77 MOV EAX,DWORD PTR DS:[77ED73B4] ;UnhandledExceptionFilter指針
77E93119 3BC6 CMP EAX,ESI
77E9311B 74 15 JE SHORT kernel32.77E93132
77E9311D 57 PUSH EDI
77E9311E FFD0 CALL EAX

原文來自:先知社區

原文連結: https://xz.aliyun.com/t/8531

歡迎掃描關注我們,及時了解最新安全動態、學習最潮流的安全姿勢!

相關焦點

  • windows pwn學習筆記(附wingame下載地址)
    安裝winpwnpip install winpwn
  • PWN學習指南
    作業系統原理 :找網課看看CTF中大部分的pwn題都是linux平臺上的,那麼懂得linux的基本操作也是必不可少的.常用的命令,權限控制,linux的系統調用等…百度和b站找找教程就行了.參考書籍《鳥哥的Linux私房菜基礎篇》(真的是只是參考書籍,太厚了…,遇到了不懂的就翻翻就好了)懂的上面這些就可以學習基本的二進位漏洞了.
  • Linux pwn入門學習到放棄
    本文記錄菜鳥學習linux pwn入門的一些過程,詳細介紹linux上的保護機制,分析一些常見漏洞如棧溢出,堆溢出,use after free等,以及一些常見工具介紹等。Linux程序的常用保護機制先來學習一些關於linux方面的保護措施,作業系統提供了許多安全機制來嘗試降低或阻止緩衝區溢出攻擊帶來的安全風險,包括DEP、ASLR等。
  • Linux Kernel Pwn 學習筆記 (UAF)
    (在linux kernel pwn裡面一般開了多線程就很有可能是利用條件競爭)。cred:當我們fork一個新的進程的時候會產生cred結構體,在task_struct中大小為0xa8,注意當cred的uid,gid為0的話,我們就提權成功。
  • pwn工具安裝和pip換源
    然後用記事本打開輸入這一串代碼然後保存即可(Windows永久換源就完成了)[global]timeout = 6000index-url = https://pypi.tuna.tsinghua.edu.cn/simpletrusted-host = pypi.tuna.tsinghua.edu.cnLinux永久換源(其實原理和windows
  • 各種學習環境更新macOS虛擬機
    # study_learn_environment學習中的一些各種環境問題* 連結: https://pan.baidu.com
  • PWN:fastbin attack學習
    然後通過把 0x0x804A2A8 的地方改成某個函數的 got 表項再通過 Leave a Message 功能往改掉的那個地址上寫內容以此來覆蓋 got 表項的內容:payload = p32(elf.got['strlen']).ljust(20, 'a')add('b' * 20,payload)leave(p32(sys_addr) + ';/bin
  • CTF學習之PWN入坑指南(贈IDA工具)
    CTF的PWN題想必是很多小夥伴心裡的痛,大多小夥伴不知道PWN該如何入門,不知道該如何系統性學習,本期開始,鬥哥將輸出PWN的一系列文章,手把手帶小夥伴們入坑 。0×01開篇介紹PWN 是一個黑客語法的俚語詞 ,是指攻破設備或者系統 。
  • 第一個PWN:棧溢出原理以及EXP的編寫
    ,那麼我將用一個簡單的例子,手把手的來演示一個非常簡單的棧溢出利用,順便學習用下我們的pwntools,萬事開頭難,但如果你跟著流程走一遍的話,會開啟一個新世界的大門。第一次調試代碼寫好了,我們先來編譯運行一下[root@localhost pwn]# gcc stack_overflow.c -o stack_overflow[root@localhost pwn]# .
  • 深度學習筆記15:ubuntu16.04 下深度學習開發環境搭建與配置
    作者:魯偉一個數據科學踐行者的學習日記。
  • Docker搭建pwn環境
    ruby和gem是為了後面安裝one_gadgetdocker build -t pwn:latest .2.2 運行容器-v:映射數據卷。目的是為了將來把文件放入容器中,當然這裡需要你自己建一個空目錄,然後映射到容器中。不停止運行退出:先按 ctrl+p ,然後按 ctrl+q。
  • 實例講解支持多種架構指令集編解碼的 pwntools 工具
    然後看了一下,multiverse 的 asm 部分實際是用的 pwntools,而且 pwntools 支持的架構更多,所以轉而直接用 pwntools 就好了:初試 pwntools安裝這個工具的穩定版本僅支持到 python 2.7,可以參考以下文檔安裝:"Installation — pwntools 3.12.1 documentation": https://
  • Kali linux 學習筆記(十一)
    Kali linux 學習筆記(十一)
  • Kali linux 學習筆記(十)
    Kali linux 學習筆記(十)
  • TensorFlow2.0學習筆記
    向AI轉型的程式設計師都關注了這個號👇👇👇機器學習AI算法工程   公眾號:datayxensorFlow2.0學習筆記地址3.1、ubuntu系統解決方法3.1、windows系統解決方法TensorFlow2.0筆記10:全連接層和輸出方式!
  • 論菜雞PWN手如何在無網環境下生存
    沒準備好,那時碰巧我下了ctf-challenge,在那裡碰巧弄到了libc,可能有人喜歡用libc-searcher那個py版本的項目,我不怎麼喜歡,用那個導入庫查找感覺較慢,還是喜歡手動洩露後到網頁查找,於是有了這篇文章pwntools安裝pip install pwntools出錯自己解決啊,那些個錯誤都查得到one_gadgetgem
  • 內網學習筆記 | 2、PowerShell
    4.0.30319.42000WSManStackVersion 3.0PSRemotingProtocolVersion 2.3SerializationVersion 1.1.0.1Windows 作業系統對應的 PowerShell 版本信息:1.0        windows
  • Windows域內密碼憑證獲取學習記錄
    前期學習筆記ntds.dit:活動目錄資料庫,包括有關域用戶、組合組成員身份的信息。
  • Linux定時任務Crontab學習筆記
    來自:標點符的《Linux定時任務Crontab學習筆記》連結:http://www.biaodianfu.com
  • Kali linux 學習筆記(十二)
    Kali linux 學習筆記(十二)