格式化字符串本地搭建

极客

哎呦喂,这坑我替你们踩过了!

开头先唠两句

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

格式化字符串本地搭建

为啥非要搞“本地搭建”?不能直接拿公网机器练手吗?

哎呀,说到这个我就来气!刚学的时候,我寻思着直接找个有漏洞的靶场或者公网环境练练手,结果呢?要么是权限不够,要么是环境被人改得乱七八糟,最气人的是,很多时候连个格式化字符串的触发点都找不到,净在那瞎猜!这感觉就像你拿着菜谱想做红烧肉,结果发现锅是漏的,火是小的,肉还是注水的,你说气不气人?

所以说啊,格式化字符串本地搭建简直是救命稻草,咱自己在家用虚拟机搭一个环境,想怎么折腾就怎么折腾,不怕搞崩,不怕封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 把目标地址的字节数写进去,就能实现任意地址写,我当初第一次成功写内存的时候,那成就感,比吃了一大碗羊肉泡馍还满足!

搭建期间的那些坑,我踩得明明白白的

说了这么多,不知道你们有没有发现,格式化字符串本地搭建过程中,坑也不少,我就把几个典型坑列出来,各位引以为戒哈:

  1. GCC版本不同,行为不一样,老版本GCC和现在的新版本,在栈布局上有差异,导致你的偏移不一样,哎,每次换环境都得重新计算偏移,烦得很!
  2. 架构不同,环境不同,32位和64位程序,在函数传参和栈的利用方式上完全不同,32位简洁直接,64位还牵扯到寄存器传参,复杂多了,建议初学者先玩32位的,简单易懂。
  3. 别忘了关防护,好多人搭建好环境,忘了关ASLR,结果跑一次,地址变一次,拿到的地址永远是无效的,你说气不气?这就好比你上班打卡,结果指纹机总是识别不了,急死人。

结语与延伸:这只是个开始

格式化字符串本地搭建真的是走进二进制漏洞利用大门的必修课,它虽然麻烦,但能让你透彻理解C语言、内存布局以及程序执行原理,如果你连本地都调不明白,那去玩远程利用,那更是天方夜谭。

我个人觉得,把这套东西玩转了,再去看看其他漏洞类型,比如栈溢出,那感觉就像是打通了任督二脉,思路会清晰很多,各位朋友,别怕麻烦,自己动手折腾一下格式化字符串本地搭建吧!当你成功通过一串精巧的格式化字符串控制程序流程时,你会回来感谢我的!

顺带一提,如果你在格式化字符串本地搭建中遇到了什么奇葩问题,欢迎在评论区里跟我吐槽,咱们一起探讨,一起进步呀!加油,奥利给!

文章版权声明:除非注明,否则均为极客网安-咸鱼原创文章,转载或复制请以超链接形式并注明出处。

目录[+]