今年网鼎杯不说啥了,没打进前130,我是菜B比不过各位师傅
本文包括四场网鼎的部分WEB和PWN,本着菜鸡应该多练习的原则四场都看了看,除第一场外均为复现。
青龙组
PWN-boom1
[*] '/home/Railgun/Desktop/2020wdb/pwn1'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
有点复杂,但是大概是实现了一个编译器的功能,有点像这个
但是可以看到全局变量限制了次数,只能用一个函数,并且只有一次机会。
思路:定义变量,调出变量相对于free_hook、libc_base偏移,定义另一个变量地址为free_hook,然后覆写为one_shot即可。
版本是libc-2.23,但是好像不同2.23的libc中偏移也稍微有点差别。
关于变量地址,printf调试下断在这里即可。
计算libc_base以及free_hook即可。
我本地强加libc同pwndbg调试的有点问题,但是最后用pwngdb还是可以调出来的。
PWN-boom2
又是一个VM PWN,下面大概可以看出模拟了栈,上图部分是栈的初始化,一个用chunk来存储指令,一个用来模拟栈,其中v3为模拟栈,看到模拟栈底(stack_bp )指向30(0x1e),stack_bp – 1指向13(0xd)。同时可以看出v37=v3,v37也就是stack+0x8000,在栈最底部(stack_bp + 1)。
总觉得干看有点复杂,调试看一下。
真实栈
上图是输入指令14后模拟栈初始化完成后的真实栈,对比一下:
模拟栈
真实栈中的buf确实存储了14,以它为基准且同时分析代码可以确定:
v37--->stack_bp
var_38(v36)--->stack_sp(根据每次stack都--并且最后再-1确定为sp) ---> stack_bp - 4
stack_bp - 1 = 0x1e
stack_bp - 2 = 0xd
stack_bp - 3 = 0
stack_bp - 4 = 真实栈地址
接着就分析下面的具体的指令,我是结合代码和动态调试确定功能。
菜鸡第一次分析这种,如果有错误请各位师傅斧正:
动调观察真实栈、虚拟栈并结合代码分析得出如上结果(其中command 11为leave ret).
后补,觉得应该给出一个调试例,以11为例把:
给出此时真实栈与虚拟栈环境,此时是刚刚通过指令25计算出one_gadget地址。
可以看到,此时是取出了sp的值也就是刚刚使sp指向栈上libc_start_main的地址(ret)给RAX。
然后把RAX给了RDX
可以看到RDX此时就是ret了,接下来是将rbp – 0x28处地址的值(one_gadget)赋给rax:
再然后就是将RAX的值赋给RDX指向的地址,也就是完成了把one_gadget写入ret的操作。
思考如何利用,再看一下初始化后虚拟栈环境。
可以看到,初始化完成后的虚拟栈sp指向0x7ffff7fd8fe8,而0x7ffff7fd8ff0处有存放着一个真实栈的地址,而真实栈上存在__libc_start_main+offset,我们虽然不能打印,但是可以运算,考虑把这个真实栈的地址经过运算变为指向libc_start_main的地址。
先pop一下,令sp指向真实栈地址然后使其减0xe8(相对libc_start_main):
pwndbg> distance 0x00007fffffffdd80 0x7fffffffdc98
0x7fffffffdd80->0x7fffffffdc98 is -0xe8 bytes (-0x1d words)
使用指令1令v38为0xe8,再用指令26让sp减0xe8,同时执行了pop,再用指令13执行push把刚才的地址再push进去。
可以看到虚拟栈sp指向了指向libc_start_main的地址(同时是ret地址)。
此时用指令9取得libc_start_main的地址,然后计算出偏移,指令1存储偏移,再用指令26让它减去偏移得到libc基地址,然后用13入栈,再用指令25使sp加one_gadget偏移,再用13入栈。
此时sp指向了libc基地址
one_gadget入栈成功
现在我们拿到了one_gadget,考虑覆盖ret,使用指令11,发现出错了,后面看是不应该把one_gadget入虚拟栈。
总结就是这种题多调试。
PWN-fast0