由于是第一次作为出题人,有许多不足的地方,比如这题忘记关相应输出了,导致 fmt 可以 leak,从而绕过随机数(QWQ)。
开启了 PIE 保护,关闭了 NX 保护,大概率能打 shellcode,拖入 IDA 里面看。

login
先是一个登录,输入 user_name 与 114514 编码后的结果。熟悉的师傅应该能看出是 Base64 编码,不熟悉的师傅可以通过 gdb 调试得知。

root
接着看一下 root 函数的汇编,发现有一个全局变量 target,需要将 target 的值与 0x2918(即 10520)进行对比,如果一样就能打 shellcode。
在打 shellcode 时发现限制了输入的字节数,这里可以靠师傅们自己发挥。我是先搓出 read 函数,再使用 shellcraft.sh()。
|

edit 与 game
再看看 edit 函数与 game 函数。在 game 函数中,发现 20 次输入中每次输入的数与生成的随机数一样,最后就会给出 main 的地址,这样就能得到基址。
在 edit 函数中发现存在 fmt。由于没有关闭相应的输出,即使没有绕过随机数判断,也可以 leak 得到基址,然后再修改 target 的值,从而进入 root 函数打 shellcode。
下面分别说明这两种获取基址的做法。


leak 获取地址
第一种是 leak 的做法。因为存在 fmt 且没有关闭相应的输出,所以在 edit 函数中不仅能修改 target 的值,也能泄漏地址。
找到相应的偏移,然后先泄漏地址再修改值,当然泄漏地址时也可以找其他位置。
|


伪随机数
第二种是随机数判断的做法。在 game 函数中会给我们 main 函数的地址,只需要在 20 次输入中每次输入与生成的随机数一样即可。因为题目给了种子,可以编写一个生成随机数的程序。
|
|
修改 target 的值
最后利用 fmt 修改 target 的值,有两种写法。
第一种是使用 fmtstr_payload,这种方法比较简单:
|
另一种是不使用 pwntools 自带的 fmtstr_payload,自己构造 payload。这种方法更复杂,但有助于理解 fmt 漏洞:
|
%10520c 表示输出 10520 个字符,%hn 表示将当前已输出的字符数作为 2 字节值写入指定地址,22$ 表示使用第 22 个参数作为目标地址,这个地址就是我们写入的 target 地址,AAA 用于对齐。
关于第二种写法,可以在 gdb 中观察:


这是输入后的栈上情况,可以看出输入的 target 地址在第 22 个参数处,这就是为什么使用 22$。

最后是 printf 后的栈上情况,可以看出值确实写入了 target。
总结
exp 可以根据上述过程自行编写。由于过程比较简单且已经说明得比较详细,原文没有给出完整 exp.