2024mapna
这算是赛后总结吧,学长说对新手很友好,我看不出来,只能说真的很”友好”。
这次虽然只做出一道题,但是总的来说收获还是非常多的
ninipwn
这道题思路还是比较清晰的,主要还是脚本十分难写
首先check一下
发现是64位的然后保护全开,主要是注意PIE和Canary保护
IDA静态分析
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
没什么东西,就一个初始化和加密函数
显然加密函数才是我们要注意的位置
1 | unsigned __int64 encryption_service() |
首先能我们会看到一些比较显眼的漏洞,就是第一个printf(key);
这个明显key是可控的,有着一个格式化字符串漏洞
然后key是一个char[8]型的然而能输入0xA个字符,显然数组越界
再深入探查的话
会发现text_length的前两位是可以覆盖的,然后由于是小端存储 而且题目限定text_length我们输入进去的要小于0x101,因此覆盖的两位就是我们的text_length大小这点很重要,是整道题目的核心
这里插入一点:
在ida里,一个指针长度存储两个16进制值,例如0x4050上可能存储的是0x19等,因此上面text_length覆盖两个指针长度其实覆盖了4个16进制数
1 | read(0, buf, text_length); |
有了text_length的覆盖那么这段的text_length的大小就是可控的,而buf段位于栈上,因此有显然的栈溢出的漏洞,所以本题的核心就是覆盖返回地址
但是其中还有很多细节需要注意,就是本题开启了Canary保护,我们要绕过该保护,而PIE保护也要绕过,PIE使得整个可执行文件可以被加载到随机的地址,但是后12位(64位)无论是ASLR或者PIE都不会改变
但是本题目,覆盖的时候,只需要覆盖后8位即可更简便
可以看到只有后8位不一样,因此只需要覆盖后八位即可,这样既方便又可以绕过PIE保护
1 | __int64 __fastcall encrypt(__int64 a1) |
这是其中的加密函数,可以看到会加密text_length大小的内容,因此我们输入多少它加密多少,而这个是异或,就可以通过二次异或来返回原值
而Canary则通过那个格式化字符串漏洞泄露,Canary一般是在ebp-0x8的位置
因此可以通过%xxx$p来泄露Canary的值
大致的思路就这样
附上exp
1 | python |
写exp的总结:
- recv下来的东西,是字符串,不是整数,例如0x273437,他是一个长度8的字符串,因此需要等到0x再切片
- send的东西,最后是字节序列,但字符串也是可以的
- b’内容’该内容全部被转换位ASCII码的形式,如果想要输出01那么需要使用
\x01
来实现、 - 字节序列就是0到ff的整形构成的数组
- canary截取下来是字符串类型,而其中的值需要转换成qword的形式,那么先用int来将将十六进制字符串转换为64位整数,之后再用p64一步搞定
最后,虽然只能做出一题,但是其中的过程还是值得回味的,无论是失败还是成功,享受这个过程就可以,这道题能做出来学长居功至伟,解答了我非常多的问题,让我成长了许多,我将会继续学习,继续进步的。