强网杯2019 pwn babymimic writeup
TOC
一道考验综合能力的pwn题。
源程序、相关文件下载:babymimic.zip。
爆破
ex@Ex:~/test$ nc 49.4.51.149 25391 |
首先题目需要我们进行sha256爆破,开始时用Python的多线程总是速度不够快,经常被check,所以我就用C语言重新写了一遍。
// compiled: gcc -O3 -pthread crack.c sha256.c -o crack |
sha256
源码来自:https://github.com/ilvn/SHA256 。
编译出来之后,配合下面的脚本就能过检查:
sh = remote('49.4.51.149', 25391) |
flag加密
[+]teamtoken:[+]proof completed |
爆破之后,程序提示了flag是加了密的,再加上我们的token
是32位的,所以就能确定flag文件
应该是64字节
。
flag加密很简单,只需要一个脚本就能跑出来。
#!/usr/bin/python |
正题
题目给了我们两个程序,一个32位程序,一个64位程序,题目的考点就是让我们用一个脚本同时打通两个程序。
这里我说一下它的检查原理,在我们连上靶机之后,靶机会利用脚本同时启动32位程序和64位程序,我们的输入流会被脚本复制成两份,每个程序一份,然后脚本会检测输出流,若是两个程序的输出流不一致,则会被脚本check
,若其中任意一个程序crash
或者退出,则脚本会同时结束两个程序,直接断开链接。
所以我们要做的就是用同一个脚本,打32位程序和64位程序的时候,要保证输入流和输出流完全一致,这就考验我们构造payload的能力。
思路
两个程序都是标准的栈溢出,但是32位程序的溢出偏移是272字节
,64位程序的溢出偏移是280字节
,正是这个差别,使得我们可以构造出同时适用于两个程序的payload。
第一次读取payload
new_stack_x86 = 0x80db000 - 0x400 |
这里我将32位程序
进行栈转移
,64位程序
正常ROP
,否则一个ROP链
是不能让两个程序同时兼容的,所以我分成了两次进行读取ROP,这是第一次发送64位的ROP链
,之后会发送32位的。
这里0x8048902
的地址主要是为了重新读取payload进行32的ROP。
► 0x8048902 <vul+93> push 0x300 |
第二次读取payload
sh.send( |
\0\n
是为了保持两个ROP链有相同的输出流,因为32位的程序跳到0x8048902
之后,有把读取到的内容puts
出来,这里我将第一个字符设置为\0
就是为了让32位的程序在运行puts
时只输出一个换行,而第二字符\n
是给64位程序用的,目的就是为了让两个程序同时输出一个换行字符。
64位的ROP
这个ROP链必须要保证和32位的ROP链的输出结果保持一致。
new_space_x64 = 0x6a4000-0x400 |
new_space_x64 + 1
就是对应\0\n
中的\n
,这样就能保证两个程序同时输出一个换行,保证不会被check
,之后就是从输入流读取flag
文件名,然后打开,再读取,再输出,为了保证输入流、输出流一致,我们只需要把32位程序的ROP
链也按照这个流程设计,那么就不会被check
。
32位的ROP
# 0x08055f54 : pop eax ; pop edx ; pop ebx ; ret |
和64位的ROP链保持一致,这样就能保持输入流、输出流一致,不会被check。
读取flag
之后就只需要发送我们的flag文件
名,就能得到flag。
sh.sendline('./flag\x00') |
完整脚本
#!/usr/bin/python2 |
运行实例
32位程序
ex@Ex:~/test$ python -c 'print("E" * 64)' > flag |
64位程序
ex@Ex:~/test$ python -c 'print("E" * 64)' > flag |
可以看到,两个程序的输入流、输出流完全一致。
总结
主要是考验我们构造ROP的能力。