fmt_got
你好,又见面了…
也有可能是第一次见面?
算了今天不废话了,直接看题目吧
1 | |
还悄悄藏了一个函数…
1 | |
保护为NX和canary found,但是不好意思,今天不打返回地址,注意到题目存在格式化字符串漏洞,同时保护为partial RELRO,因此GOT表可写,直接利用%n任意写覆盖exit的GOT表地址为read_flag即可
在此之前,你可能需要一些前置知识
1.什么是格式化字符串漏洞,本人词不达意,还请参考如下链接(直接点,放心)
(2026.2.11复盘时吐槽:你不是词不达意,你是懒得写…)
2.什么是got表,什么是plt,动态链接器(ld,哈哈哈)和共享库是什么,程序第一次调用puts这个函数时到底发生了什么,想必经过ret2libc的洗礼,前两个问题的答案你已知晓,但是后两个问题将回到更底层的维度,等待着你去探索(我也在探索中…),也许我后面会写一篇关于此和ret2dlresolve的文章,等我先沉淀沉淀吧…
OK,还是回到题目本身
先观察我们格式化字符的写入点

可以看到,我们的AAAA从第十个%p的第低三位个字节开始写起,我们的目标是将exit的got(0x403430)覆写为read_flag(0x401236),采用%hhn逐字节写的方式
先将0x403430的最低字节0x30覆写为0x36(注意小端序地址表示法),注意builtin_strncpy(local_118,"That\'s what you want to say... ",0x23);已经给了local_11834字节的长度,所以再补20个字节得到0x36(54)便可达到目的
然后将0x403431,即第低二位字节0x34覆写为0x12即可,注意此时local_118的长度已经是54,而目标是0x12(18),因此先补202个字节至256(你懂的),再补18个字节回到0x12,一共220个字节,便成功覆写了exit的GOT为read_flag
先大致写出payload
1 | |
?即写入地址0x403430和0x403431的位置,我们推理一下,首先?必定为两位数,因此payload所占字节长度为23,而我们输入的字符从第十个%p的第低三位个字节开始写起,因此发送payload后先是6个字节写完了10,而后还有17个字节分别完了11,12,并写了13的1个字节,因此再补7个字节的长度填满13,最后输入要覆写的地址0x403430,0x403431即在14,15的位置,真是一场酣畅淋漓的构造啊…
当时的我只是傻傻地对着wp猜偏移,经过很长时间的分析(真的很长时间,没人问,纯自己瞎折腾 (╥﹏╥) )才终于理解了本质,现在写下来,希望能帮到困惑的你…
最后贴一下完整exp(真的很短,但是也真的很值得深思…)
1 | |
好了,又写一篇,感谢阅读,天天开心…
2026.2.12吐槽:
虽然写得挺唐
不过好在思路是正确的
不过我也没资格说你唐就是了
毕竟你就是我嘛…