二进制安全之堆溢出(系列)—— house of spirit
本文是二进制安全之堆溢出系列的第四章节,主要介绍house of spirit。
原理
目的:通过任意地址free达到篡改任意地址的目的
条件
在目标地址周围能够伪造一个堆块
能够对伪造的堆块进行一次free
free之后能够重新申请得到这个堆块并篡改目标地址内容
流程
从任意地方伪造一个堆块
将堆块释放到bin链
将伪造的堆块malloc取出
达到通过堆实现任意地址写入的效果
Demo
#include<stdio.h>
#include<malloc.h>
#include<unistd.h>
#include<string.h>
int main(){
malloc(0);
int size = 0x40;
long p = 0;
char s[10];
*((&p)+1) = size+1+0x10;
sleep(0);
*((&p)+3+size/8) = 0x71; //更改一个chunk的size位,避免前向合并,因为是fastbin,故不用再构造第三个堆块
free((&p)+2); //free掉第一个堆块的数据空间
sleep(0);
void *q = malloc(size);
printf("%p\n",q);
sleep(0);
strcpy(q,"aaaaaaaa");
sleep(0);
return 0;
}
调试
初始化p指针(伪造p堆块)
pwndbg> stack
00:0000│ rsp 0x7fffffffdbc8 —? 0x4006b4 (main+78) ?— mov eax, dword ptr [rbp - 0x34]
01:0008│ 0x7fffffffdbd0 ?— 0x1
02:0010│ 0x7fffffffdbd8 ?— 0x40004007bd
03:0018│ 0x7fffffffdbe0 ?— 0x0 ==>p
04:0020│ rax 0x7fffffffdbe8 ?— 0x51 /* 'Q' */
?
pwndbg> x/20gz 0x7fffffffdbe0
0x7fffffffdbe0: 0x0000000000000000 0x0000000000000051 ==>伪造的size位
0x7fffffffdbf0: 0x0000000000400770 0x0000000000400570
伪造下一个堆块
pwndbg> x/20gz 0x7fffffffdbe0
0x7fffffffdbe0: 0x0000000000000000 0x0000000000000051
0x7fffffffdbf0: 0x0000000000400770 0x0000000000400570
0x7fffffffdc00: 0x00007fffffffdcf0 0x675fd3aa65176f00
0x7fffffffdc10: 0x0000000000400770 0x00007ffff7a2d830
0x7fffffffdc20: 0x0000000000000000 0x00007fffffffdcf8
0x7fffffffdc30: 0x0000000100000000 0x0000000000000071 ==>伪造的下一个堆块的size
free 第一个堆块的数据空间
0x50: 0x7fffffffdbe0 ?— 0x0
相当于把栈上伪造的堆块,释放到了bin链里面
将以上 free 的堆块malloc出来
0x60: 0x0 此时bins中的chunk被分配给了 q
之前伪造的p堆块
pwndbg> x/20gz 0x7fffffffdbe0
0x7fffffffdbe0: 0x0000000000000000 0x0000000000000051 ==>伪造的size位
0x7fffffffdbf0: 0x0000000000400770 0x0000000000400570
此时的 q 堆块
pwndbg> x/20gz 0x7fffffffdbe0
0x7fffffffdbe0: 0x0000000000000000 0x00007fffffffdbf0
0x7fffffffdbf0: 0x0000000000000000 0x0000000000400570 ==>fastbin的第一个堆块,fd指向0
为什么size位原本是0x51,现在变成0x00007fffffffdbf0了呢
从汇编代码来看,malloc之后,这个位置被重新赋值了
0x400700 <main+154> call malloc@plt <0x400540>
0x400705 <main+159> mov qword ptr [rbp - 0x28], rax ==> 重新赋值
? 0x400709 <main+163> mov rax, qword ptr [rbp - 0x28]
?
RBP 0x7fffffffdc10
RAX 0x7fffffffdbf0 ?— 0x0
即如下过程
02:0010│ 0x7fffffffdbe0 ?— 0x0
03:0018│ 0x7fffffffdbe8 —? 0x7fffffffdbf0 ?— 0x0
04:0020│ rax rdx 0x7fffffffdbf0 ?— 0x0
05:0028│ 0x7fffffffdbf8 —? 0x400570 (_start) ?— xor ebp, ebp
06:0030│ 0x7fffffffdc00 —? 0x7fffffffdcf0 ?— 0x1
07:0038│ 0x7fffffffdc08 ?— 0x400ae2129b1e7e00
向 q 中写入 aaaaaaaa
pwndbg> x/20gz 0x7fffffffdbe0
0x7fffffffdbe0:0x00000000000000000x00007fffffffdbf0
0x7fffffffdbf0:0x61616161616161610x0000000000400500