远程代码执行漏洞复现
凌晨两点,远程我盯着屏幕上那个泛着绿光的代码终端窗口,手指悬在回车键上。执行这不是漏洞什么黑客电影场景,只是复现一次普通的漏洞复现——目标是一个运行着旧版Apache Struts的测试服务器,漏洞编号是远程S2-045。
复现的代码路径很老套,甚至有点无聊。执行抓包,漏洞改Content-Type头,复现塞进一段OGNL表达式,远程发包。代码就这么简单。执行服务器把用户输入当成了命令的漏洞一部分,直接拼进了执行逻辑里。复现我按下回车,三秒后,服务器返回了一个“id”命令的输出结果——uid=0(root)。那一刻我反而有点失落,这漏洞比我想象中还要蠢,蠢到让人怀疑当年那些大规模数据泄露是不是真的源于这种低级错误。
但蠢归蠢,它带来的破坏力一点不打折。2017年,Equifax因为没打这个补丁,1.43亿美国人的社保号、驾照号被拖走。事后调查发现,他们用的还是两个月前就公布修复方案的版本。你看,漏洞复现的意义不在于炫技,而在于把“如果没修会怎样”这件事演给你看。我这边是root,那边是1.43亿条记录,本质上是同一行代码。
复现到一半,我习惯性去查了查这个漏洞的触发条件。问题出在Jakarta Multipart解析器上,它处理文件上传时,错误信息里直接引用了用户可控的Content-Type值。开发者的本意只是把异常信息拼个字符串,方便排错,结果这个字符串变成了通往系统后门的钥匙。这种疏忽太典型了——你永远不会想到自己写日志的那行代码,会成为别人提权的跳板。
我把攻击载荷里的命令换成“cat /etc/passwd”,回显正常。又换成“whoami”,还是正常。最后试了试反弹shell,在内网另一台机器上监听,成功连上。整个过程不到十分钟,期间我甚至还有空喝了口凉掉的咖啡。这种“容易”本身就是一种警示:漏洞的利用门槛越低,意味着暴露面越大。别指望攻击者都是天才,大多数时候他们只是比你更早地看了补丁公告。
关掉虚拟机之前,我顺手清空了日志。不是心虚,是习惯——复现环境就该干净利落地销毁。但脑子里那个root提示符还在闪。说真的,每次复现完一个漏洞,我都会产生一种怪异的不安全感。你清楚知道哪扇门没锁,而门外站着无数个拿着通用钥匙的人。这种感觉没法跟非技术朋友解释,他们只会觉得你在装。
补丁已经打了四年多,现在网上还能找到一堆没修复的僵尸系统。这漏洞就像个老笑话,讲的人累了,听的人腻了,但门依然开着。我关掉终端,屏幕暗下去,窗外的天已经蒙蒙亮。明天还有别的CVE要复现,循环往复,无穷无尽。可每次看到那个root,还是忍不住想骂一句:这代码写得真他妈糙。