2017年,漏洞一位安全研究员在分析某款主流PDF阅读器时,挖掘发现其JavaScript引擎对`this`对象的技术绑定处理存在逻辑缺陷。他没有急着写exploit,漏洞而是挖掘先构造了一个能触发类型混淆的样本——一个被删除后再引用的对象。程序崩溃了。技术这个崩溃点后来被证实可利用,漏洞最终演变成远程代码执行漏洞。挖掘整个过程没有魔法,技术全是漏洞手工逆向加一点点直觉。
漏洞挖掘的挖掘本质,是技术在程序逻辑的缝隙里找“意外”。程序是漏洞人写的,人一定会犯错。挖掘错误分两类:一类是技术写代码时手滑,比如把`==`写成`=`;另一类是设计时没想清楚,比如权限检查只做了前半段,漏了后半段。前者靠静态扫描工具能抓出不少,后者得靠人脑去推演状态机。我见过一个案例,某云盘客户端的分享功能,前端校验了文件ID是否属于当前用户,后端却没有。攻击者改个ID就能下载别人的文件。这种漏洞,自动化工具几乎无能为力,因为代码语法完全正确,逻辑却错了。
挖漏洞的人常被问:你们是不是天天对着反汇编发呆?不全是。更多时候是在做“假设-验证”的循环。假设某个输入参数没做长度检查,那就发一个超长字符串看看;假设某个状态切换时锁没释放,那就并发调用一百次试试。这种活像侦探,线索藏在崩溃日志、内存转储和网络包的时间差里。去年有个开源的MQTT代理,我在测试时注意到,客户端断开连接后,服务器清理会话的定时器偶尔会延迟几毫秒。就这几毫秒,如果此时重连并复用同一个clientID,旧会话的订阅关系会短暂残留。利用这个窗口,能收到本不该收到的消息。这种漏洞没有CVE编号,厂商也不一定认,但它真实存在。
工具当然重要。AFL、libFuzzer这类模糊测试器能24小时不间断地跑,用变异输入轰击目标。但工具给的只是崩溃样本,是不是安全漏洞、能不能利用、影响范围多大,还得人来判断。我见过太多“疑似漏洞”最后被证明只是断言失败或内存耗尽。真正的漏洞挖掘,七成时间花在理解目标上:它怎么解析输入、怎么管理内存、怎么处理异常。剩下三成才是测试和验证。
有人觉得挖漏洞靠运气。运气确实有,比如你恰好点开了一个没人测过的功能菜单。但持续产出漏洞的人,靠的是系统化方法。他们会画数据流图,标出所有外部输入点;会读历史补丁,看厂商最近在修什么类型的bug;会针对特定协议写自定义的fuzzer。一个朋友专门挖路由器漏洞,他的做法是买二手设备,拆固件,提取文件系统,然后手工审计CGI脚本。两年下来,他拿了十几个CVE。没什么捷径,就是熟能生巧。
漏洞挖掘的终点不是提交报告。一个崩溃变成可用的exploit,中间隔着绕过ASLR、构造ROP链、处理编码限制等一堆麻烦事。但那是另一篇文章的事了。回到起点:如果你刚入门,别急着找0day。先找一个开源的小项目,把它的代码读一遍,试着找出一个能让它崩溃的输入。这个过程会教你比任何教程都多的东西。
顶: 255踩: 769






评论专区