DDCTF2020 && 柏鹭杯2020 && 北京市网络安全宣传周技能赛 PWN wp
前言
这几个比赛连着打的,PWN题也比较少,写到一个里了,后两场比赛队友带飞拿了第一。
DDCTF
we love free
漏洞利用
程序模拟了vector的逻辑,这种分配是按照0x20 0x30 0x50 … n*0x20-0x10的顺序分配的。在vector的存储位置里有几个指针变量,其中start是分配的一个大堆块的起始位置,在存储的空间够用时都会使用这样一个大堆块。后面有个curretnt_ptr,指向输入,如果调用Add,则cureent每次加8,直到等于end指针,再开辟新的堆空间。
在edit的时候先malloc一个新堆块,free旧堆块,再edit旧堆块,编辑的长度是新堆块的大小,因此会造成UAF和溢出。
这里作者默认认为旧堆块和新堆块是连续的,因而即使溢出也不过只能溢出到下一个堆块一半以内的部分,这一点也很好理解,因为正常来说释放后如果ub和top_chunk相连,malloc_consolidate会使得整个堆块合并回去,之后的Add情形和之前相同,即使没有ub,因为fastbin的关系,也会按之前堆排布的方式进行分配,然而如果利用堆溢出改掉下一个ub(0x110)的sz,比如说0x51,再次释放就不会触发malloc_consolidate,且因为0x50进了fastbin,第二次的Add就会优先分配到这个块,那么0x30在原始位置,0x50到了一个靠后的位置,中间构造出unsorted bin,在edit的时候就可以编辑此ub的sz和bk,进而FSOP了。
注意最后编辑sz/bk的时候长度有限,因此在之前的输入里布置一下fake_vtable和system_addr,释放后仍有残留数据,构造出满足的条件,最后Add触发FSOP。
exp.py
1 | #coding:utf-8 |
柏鹭杯2020
note
程序逻辑
程序开始先用随机数做了种子,因而之后的随机数无法预测。可以add两种类型的堆块,在free里释放了*node_addr
存储的chunk2,并用循环移位赋值的方式将原堆块的值覆写成后一个堆块的值。
1 | void **new1() |
漏洞利用
因为type1_list和type2_list紧挨着,当分配0x20个块时调用Delete,函数的移位赋值使得type1_list上出现了type2_list[0]
。我们通过edit1函数部分修改type2_chunk,从而leak出Heap,再利用type1+type2的任意地址写将type2_chunk的sz改大,释放后放入unsorted bin(注意此前修改tcache_perthread_struct的对应的count大于7),再和之前一样部分写低字节leak出libc地址。最后用这个任意地址写将__free_hook改为system,再释放一个包含/bin/sh
的块即可。
exp.py
1 | #coding=utf-8 |
MineSweeper
漏洞利用
在Game里有四个选项,A继续,B删除,C插旗子,D挖雷。其中B存在double free。首先通过B的UAF分配到存储name的sz部分,改成0xa1之后释放(注意因为这里被置为了非0所以直接win了,在此之前要绕过一个0x202010处的check),之后分配大堆块触发malloc_consolidate,使得name以及下面的堆块进行合并,从而可以写包含有存储地雷的堆块的堆块,从而可以覆写其地址,leak出任意堆块的内容,这里首先leak出heap倒数第二字节的内容,从而可以改写其到unsorted bin的地址leak出libc,最后由于可以改写name_addr又可以改写name,所以地址任意写改__free_hook到system,释放包含/bin/sh的块即可get shell。
exp.py
1 | #coding=utf-8 |
北京市网络安全宣传周技能赛
vmpwn
程序逻辑
模拟了一个小vm,通过指针递减+write泄露出libc。通过指针增加到stderr伪造_IO_2_1_stderr_
,修改其vtable里+0x10处的指针,fclose时触发调用。这里有两个地方需要注意,一是参数位于_flags
,但是后面会对其前4字节进行异或处理,这里用;sh\x00
做注入;二是抄完stderr的值后发现有错误,跟着源码调一下到某个位置发现指定的值需要是0x20,因而下面有个值是0x0000002000000002
,后四字节对应fd,前四字节为绕过此检查。
1 | __int64 __fastcall main(__int64 a1, char **a2, char **a3) |
exp.py
1 | #coding=utf-8 |