陕西省省赛 wp & 复现
陕西游玩
一道签到题吧,选项1栈溢出,partial overwrite到后⻔位置,爆破即可getshell
exp:
1 | #!/usr/bin/env python3 |
easy_printf
checksec
看到保护全开,IDA打开
看到需要先通过比较,然后才能进入12次格式化字符串漏洞,比较直接解码base64就行,输入TokameinE_is_the_best_pwner\x00
即可
然后就是格式化字符串了,可以先把栈地址,pie基址,libc基址同时泄露出来。栈中肯定是栈地址最多了,而且因为用了for循环,所以栈帧不会一直变换,因此就直接在栈里面找一个可以被修改的栈地址,然后指向返回地址,再修改返回地址对应字节为one_gadget,1/16爆破一下就行了
exp:
1 | #!/usr/bin/env python3 |
babycvm
这道题是一道vm,输入相应的机器码,程序会进行翻译并执行。关键在于逆向,可我一看到要逆就头大。。。
这里是看着Wings的wp复现的
首先将输入指令设为 123456789abcdef0,然后分析代码
1 | __int64 *__fastcall fetch_and_decode(__int64 a1, __int64 *a2) |
则a2[0] = e, a2[1] = f, a2[2] = f0, a2[3] = d, a2[4] = 123456789abcf0
到这里分析完了指令的解码,然后看译码部分
1 | int __fastcall evaluate(_DWORD *a1, _QWORD *a2) |
分析函数可以发现,函数中的case由a2[3]即d决定,接下来以d分类分析
- d = 0, noop
- d = 1, a1[2 * a2[0] + 4] = a2[4]
- d = 2, a1[2 * a2[0] + 4] = a1[2 * a2[1] + 4] + a1[2 * a2[2] + 4]
- d = 3, a1[2 * a2[0] + 4] = a1[2 * a2[1] + 4] >> a2[2]
- d = 4, a1[2 * a2[0] + 4] = a1[2 * a2[4] + 12]
- d = 5, a1[2 * a2[4] + 12] = a1[2 * a2[0] + 4]
- d = 6, puts( a1[2 * a1[2 * (100 - a1[2]) + 12] + 12] )
- d = 7, a1[2 * a2[0] + 4] = a1[2 * a2[1] + 4] << a2[2]
- d = 8, *a1 = 0
- d = 9, a1[2] += 1, a1[2 * (100 - a1[2]) + 12] = a1[2 * a2[0] + 4]
- d = 10, a1[2] -= 1, a1[2 * a2[0] + 4] = a1[2 * (100 - a1[2]) + 12]
- d = 11, a1[1] = a2[4]
我们注意到,d = 1 时由于a2[0]的值有限制,因此不能有很大能力修改栈内存,但是如果和d = 5配合起来就可以实现对栈的修改即a1[2*a2[4]+12] = a1[2*a2[0]+4] = a2[4]
。然后来看run
函数,该函数中的s就是上面分析的a1,如果能精确控制某些值,那么我们就能覆盖返回地址
1 | unsigned __int64 __fastcall run(const void *a1, size_t a2) |
只需要进行简单的动态调试就可以发现只需要用d = 1
和d = 5
两种就可以构造ROP。并且在输入name部分可以直接泄露libc地址,而不需要使用指令中的puts
来泄露(当然使用了也可以
exp为:
1 | #!/usr/bin/env python3 |
Information_System
这道题风水用的时间比较长,导致赛后半小时才出
checksec
看到保护全开,然后IDA打开看到实际上是一个堆题,不过前面还加了个登录部分
程序⾸先需要login,先在name和passwd输⼊时填满前0x10个字节,后⾯再跟上root和t00r。然后需 要输⼊正确的verification code,这个在得到时会有⼀些随机数操作,可以直接通过c程序模拟,也可 以⽤ctypes。模拟的c程序为
1 |
|
然后在程序的输入部分存在off-by-one
漏洞
1 | __int64 __fastcall sub_147A(__int64 a1, unsigned __int64 a2) |
程序只有add() show() delete()
三个功能,libc版本为2.35,因此考虑堆风水+house of cat
程序在开始时会让你选择一个key,这个key决定了后面你可以申请多大的堆块,函数逻辑如下
1 | int sub_16BE() |
在add函数中(最多可以申请12个堆块),有如下逻辑
1 | my_write("******************************"); |
因此在选择key>0x10时,可add的大小有1:0x108 2:0x150 3:0x400
,在key<=0x10时,可add的大小有1:0x18 2:0x60 3:0x40
,由于是off-by-one漏洞,考虑key>0x10
然后就是堆风水泄露堆基址和libc基址,堆风水构造tcache poison
打house of cat
这里详细来看一下如何对该题进行堆风水
以泄露堆基址为例,只需要3个堆块即可,首先申请0x108大小的chunk0, chunk1, chunk2,chunk2的对应位置填充上大小,来绕过之后的size检查,然后删除chunk0,再将chunk0重新add回来并通过off-by-one修改chunk1的size末字节为0x61,然后删除chunk2,删除chunk1,将chunk1拿回来的同时覆盖到要泄露的地址位置,然后直接show(1)就可以了
为了不破坏堆块结构,可以选择在泄露完成后恢复chunk2的chunk头结构,恢复方式也十分简单,直接删除chunk2再申请回chunk2编辑就可以了
后续泄露libc就仿照这个思路先填充6个0x108的tcache,然后后面可以申请4个chunk,设为chunk0,chunk1,chunk2,chunk3,先不管chunk3,然后把chunk0,chunk1,chunk2按照之前的思路弄一下,chunk3用来填充tcache成7个
tcache poison也是这个思路,就是修改fd后再复原下chunk头,然后再申请出来
exp:
1 | #!/usr/bin/env python3 |
- Title: 陕西省省赛 wp & 复现
- Author: Static
- Created at : 2024-03-10 16:34:57
- Updated at : 2024-03-10 16:34:51
- Link: https://staticccccccc.github.io/2024/03/10/CTFS-wp/陕西省省赛 wp & 复现/
- License: This work is licensed under CC BY-NC-SA 4.0.