第五空间安全大赛
前言
比赛给了5道web,15道pwn,队里师傅做的很快,自己做了1之后看了3 10 和 12,12的chunk shrink大概是第一次做到这种题,记录一下通用的思路
pwn3
前言
这道题的漏洞看到了,但是因为自己想当然的问题没有搞出来,记录一下做题的思路
漏洞分析
程序有Create、Delete、Show三个功能,每次固定分配0x14大小的chunk。注意bss里有个pFunc函数指针会被调用,其调用条件可以查看其引用,在while循环的最后判断choice!=3或4即会跳转到这里,我们的目标就定为覆盖这个函数指针为one_gadget地址。
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
一个漏洞是free的时候是从后往前覆盖,当add 0x30个堆块时,Free(index)会造成bss存在两个相同的堆地址。
另一个漏洞存在于free的时候可以输入负数的index,我当时尝试-2、-3之类的不好使就放弃了,后来才注意到这里用的不是atoi而是自己实现的转换函数my_to_num,识别的ascii为0-9,不包含’-‘,因此应该直接输入0xffffffff-1的十进制表示,而Free(0)是不会报错的,我们可以Free cnt前面的地址,从而让pFunc覆盖cnt为一个很大的数字,这样输入index可以绕过检查,造成double free。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26ssize_t free_chunk()
{
ssize_t index; // rax
signed int i; // [rsp+8h] [rbp-8h]
signed int index1; // [rsp+Ch] [rbp-4h]
write(1, "id: ", 4uLL);
index = read_int();
index1 = index;
if ( (_DWORD)index != -1 )
{
if ( (signed int)index <= cnt[0] ) // 负数
{
free((void *)list[(signed int)index]);
--cnt[0];
for ( i = index1; i <= 0x2E; ++i )
list[i] = list[i + 1]; // ?
index = write(1, "dele successfully\n", 0x14uLL);
}
else
{
index = write(1, "out of range.\n", 0x14uLL);
}
}
return index;
}
同理Show可以输入负数泄露list之前的数据,这里很巧妙的是list[-19]处存在一个Libc地址,地址里的值为程序加载基地址,Show即可泄露出来
堆地址其实不必泄露,但是有了UAF也很简单
libc地址的泄露需要我们在bss上构造一个函数的got表地址,因为我们的chunk大小都是0x21,我们通过free将cnt[0]减为0x21,构造fake chunk,即可覆写bss地址,从而泄露libc
再来一次double free,覆写pFunc为one_gadget即可
17.py
1 | #coding=utf-8 |
pwn10
前言
这个题比较巧妙,程序的Add会添加一个node一个chunk,node里放chunk,分配大小固定为0x20。
1 | unsigned __int64 Add() |
漏洞存在于Edit,可以edit的次数是三次,第一次Edit,程序会把index处的node里的chunk地址写在0x602100处,第二次Edit就会输入这个chunk里的值。如果我们Add几个chunk,Edit其中一个,则0x602100会有其chunk地址,释放其中一个,则node和chunk进入fastbins[0x30],我们再去编辑chunk,可以malloc到我们设计的地方,这里我们修改低字节为’\x60’,为chunk1 node的堆地址。free的顺序是node->chunk,Add的顺序是一样的,因此第二次Add的node为第一次的chunk,第二次的chunk为fake chunk,即node1,我们修改chunk2内容,即修改了node1的chunk1_addr。
之后show(1)即可泄露地址,注意这里只能泄露俩字节,需要爆破0xff,但是有意思的是a64l这个函数的前几位和system一样的,只有后面俩字节不一样,因此可以通过它泄露后两个字节,进而Edit其为system地址,输入choice的时候输入/bin/sh即可拿到shell。
1 | unsigned __int64 __fastcall Edit(_DWORD *edit_num) |
exp.py
1 | #coding=utf-8 |
pwn12
前言
pwn12是一道很典型的chunk shrink题目,似乎是第一次做到类似的题目,非常有必要整理做题的套路。
前言
这道题上来就mallopt禁止了fastbin,让我想起来RCTF那道难到吐血的large bin attack的题目,到最后也没什么好思路,最后照着17师傅的exp做了一遍,是非常典型的chunk shrink题目emm。
程序逻辑
程序有Add、Edit、Show、Delete,只能分配0x78及以下的chunk。Edit有off-by-null,由于不能分配0xf0的chunk,不能构造chunk extend。这里使用shrink来构造Overlap chunk。又因为没开PIE,最后可以unlink。
chunk shrink构造:
chunk0(0x80)#0
chunk1(0x80)#1
chunk2(0x80)#2
chunk3(0x80)#3
chunk4(0x80)#4
chunk4(0x80)#5
Free掉1-3,Edit(0)通过off-by-one修改chunk1的size为0x100,注意我们Free这三个堆块之后,chunk4的prev_size是0x180。
Malloc(0x78)*2,我们会分配到chunk1和chunk2。Free(1)和Free(4),Free(1)的时候1和2不会合并,而Free(4)的时候由于chunk4的prev_size为0x180,因此其寻找上一个chunk会找到chunk1,因为我们释放了chunk1,所以chunk2的prev_in_use为0,chunk1-chunk4合并,重新分配,造成chunk2的ovelapping。
exp.py
1 | #coding=utf-8 |