哎呦喂,这坑我替你们踩过了!
开头先唠两句
兄弟们,姐妹们,大家好!今天咱们不聊那些高大上的云渗透、域渗透,咱就踏踏实实聊聊格式化字符串本地搭建这档子事儿,说实话,我刚接触这玩意儿的时候,那叫一个头大如斗,感觉比追女朋友还难搞!但是呢,踩的坑多了,反而摸出点门道来了,今儿个我就把格式化字符串本地搭建的整个过程,包括我那些笨拙的实验记录,一股脑儿倒给你们听,希望能让刚入门的兄弟少走点弯路。

为啥非要搞“本地搭建”?不能直接拿公网机器练手吗?
哎呀,说到这个我就来气!刚学的时候,我寻思着直接找个有漏洞的靶场或者公网环境练练手,结果呢?要么是权限不够,要么是环境被人改得乱七八糟,最气人的是,很多时候连个格式化字符串的触发点都找不到,净在那瞎猜!这感觉就像你拿着菜谱想做红烧肉,结果发现锅是漏的,火是小的,肉还是注水的,你说气不气人?
所以说啊,格式化字符串本地搭建简直是救命稻草,咱自己在家用虚拟机搭一个环境,想怎么折腾就怎么折腾,不怕搞崩,不怕封IP,更重要的是,你能完全掌控程序的编译选项、系统架构、防护机制,这对于理解漏洞的本质,那帮助可不是一星半点,这就像学车,你总得先在驾校的场地里练熟了,才敢上马路牙子飙车吧?本地搭建就是你的“驾校”,安全又自由,还能让你把每个细节都看得清清楚楚,明明白白。
搭建全过程:手把手教你,比追剧还详细
好啦,废话不多说,咱们直接上干货,既然是“本地搭建”,那咱就得有个“本地”的样子,我的环境是Ubuntu 20.04虚拟机,用的GCC编译器,整个过程分几步,我一步步拆给大家看。
第一步:准备“靶子”—— 一个故意写崩的C程序
唉,你说这不找虐吗?写个正常程序多好,非要在代码里留个漏洞,但为了教学,咱就得这么干,我写了一个超简单的漏洞代码,取名 format_vuln.c,你们看:
#include <stdio.h>
int main(int argc, char *argv[]) {
char buf[100];
strcpy(buf, argv[1]);
printf(buf); // 唉,就这儿!这行代码就是罪魁祸首!
printf("\n");
return 0;
}
看到没,兄弟,问题就出在 printf(buf) 这行!标准写法是 printf("%s", buf),但这里直接把用户输入当成了格式化字符串,这就好比你把门钥匙直接插在锁上,还把钥匙孔亮给小偷看,这不等着被抽丝剥茧地利用吗?
第二步:关上“窗户”,设置防护
为了让漏洞更纯粹,我还要把编译时的安全选项给关了,什么ASLR、栈保护、PIE,统统给我关掉!别问为啥,问就是“为了研究更清晰”,命令行这样敲:
sudo sysctl -w kernel.randomize_va_space=0 # 关闭ASLR(地址随机化) gcc -z execstack -fno-stack-protector -no-pie format_vuln.c -o format_vuln
哟嚯,这几行命令下去,顿时感觉这台虚拟机暴露在“裸奔”状态了,不过没关系,咱这是研究用的,不上生产环境,安全得很!
第三步:开启“放大镜”—— GDB调试器
光有漏洞程序还不够,你还得有个趁手的兵器,那就是GDB,这玩意儿简直就是黑客的“显微镜”,可以让你看清楚每一个字节的内存。
gdb -q ./format_vuln
进了GDB之后,你可以设置断点,观察栈上内容,比如在 printf 那一行断下,然后用 x/20gx $sp 看看栈上都有啥,哇塞,这一看,感觉跟看藏宝图似的,每个地址都可能是你的“宝藏”或者“陷阱”。
实战演示:调出栈里的“宝贝”
我相信看到这儿,很多兄弟已经急不可耐了,咱们直接来点真实的,用%x、%n这些格式化字符去搞事情。
假设我们运行:./format_vuln "AAAA%1$x.%2$x.%3$x"
输出结果可能是:AAAA41414141.0.7ffc12345678,看!那个 41414141 不正是 "AAAA" 的十六进制ASCII码吗?这说明咱已经能通过格式化字符串来泄露栈上的内容了!看到这,心里是不是有点小激动?嘿嘿,这只是开胃小菜。
要是用 %n 呢,那就更牛了,直接可以往地址里写数据,比如你想修改某个变量的值,只需要构造特定的格式化字符串,用 %n 把目标地址的字节数写进去,就能实现任意地址写,我当初第一次成功写内存的时候,那成就感,比吃了一大碗羊肉泡馍还满足!
搭建期间的那些坑,我踩得明明白白的
说了这么多,不知道你们有没有发现,格式化字符串本地搭建过程中,坑也不少,我就把几个典型坑列出来,各位引以为戒哈:
- GCC版本不同,行为不一样,老版本GCC和现在的新版本,在栈布局上有差异,导致你的偏移不一样,哎,每次换环境都得重新计算偏移,烦得很!
- 架构不同,环境不同,32位和64位程序,在函数传参和栈的利用方式上完全不同,32位简洁直接,64位还牵扯到寄存器传参,复杂多了,建议初学者先玩32位的,简单易懂。
- 别忘了关防护,好多人搭建好环境,忘了关ASLR,结果跑一次,地址变一次,拿到的地址永远是无效的,你说气不气?这就好比你上班打卡,结果指纹机总是识别不了,急死人。
结语与延伸:这只是个开始
格式化字符串本地搭建真的是走进二进制漏洞利用大门的必修课,它虽然麻烦,但能让你透彻理解C语言、内存布局以及程序执行原理,如果你连本地都调不明白,那去玩远程利用,那更是天方夜谭。
我个人觉得,把这套东西玩转了,再去看看其他漏洞类型,比如栈溢出,那感觉就像是打通了任督二脉,思路会清晰很多,各位朋友,别怕麻烦,自己动手折腾一下格式化字符串本地搭建吧!当你成功通过一串精巧的格式化字符串控制程序流程时,你会回来感谢我的!
顺带一提,如果你在格式化字符串本地搭建中遇到了什么奇葩问题,欢迎在评论区里跟我吐槽,咱们一起探讨,一起进步呀!加油,奥利给!