远程命令执行漏洞
2017年,远程Equifax被黑,命令1.43亿美国人的执行社保号、驾照号、漏洞信用卡信息全泄了。远程事后调查发现,命令攻击者利用的执行就是一个远程命令执行漏洞——Apache Struts2的CVE-2017-5638。这个漏洞允许攻击者通过构造特殊的漏洞HTTP请求,在服务器上直接执行任意系统命令。远程说得直白点:你的命令服务器在攻击者面前,就像一台没锁屏的执行电脑摆在公共图书馆里。 远程命令执行,漏洞英文叫Remote Code Execution,远程简称RCE。命令它的执行本质是什么?就是攻击者能让你服务器上的程序,去执行他想要的命令。不是读取文件那么简单,不是越权访问那么含蓄——是直接在你机器上跑shell命令。想下载木马?执行wget。想反弹shell?执行bash -i。想删库?一条rm -rf就够了。 这种漏洞为什么危险?因为它跳过了所有中间环节。SQL注入还需要你构造查询语句,XSS还需要受害者点击链接,CSRF还需要诱导用户操作。RCE不需要。攻击者找到入口,发送payload,命令就在你的服务器上跑起来了。整个过程可能只需要一个HTTP请求。 RCE漏洞的成因不复杂。最常见的是程序把用户输入直接拼接进系统命令里。比如一个ping工具,用户输入IP地址,程序执行 另一种常见情况是反序列化漏洞。Java的ObjectInputStream、Python的pickle、PHP的unserialize——这些机制本来是用来传输对象的,但如果反序列化的数据可控,攻击者就能构造恶意对象,在反序列化过程中触发命令执行。WebLogic、JBoss、Shiro这些中间件都出过这类问题。Shiro的那个rememberMe反序列化漏洞,2016年爆出来之后,到现在还有大量未修复的系统在互联网上裸奔。 表达式注入也是重灾区。Struts2的OGNL、Spring的SpEL、Elasticsearch的Groovy脚本——这些表达式引擎功能强大,但一旦用户输入能影响表达式内容,RCE就是分分钟的事。Struts2那几个经典漏洞,S2-045、S2-046、S2-048,全是这个路子。攻击者构造一个Content-Type头,里面塞进OGNL表达式,服务器解析的时候就把命令执行了。 防御RCE,核心原则就一条:永远不要相信用户输入。具体做法有很多。能用API就别用命令行,能传参数就别拼字符串。如果非要调系统命令,用白名单限制可执行文件,用参数化方式传参,别碰shell。反序列化这块,能不用就不用,实在要用就做签名校验,限制可反序列化的类。表达式引擎,关闭不必要的功能,限制用户输入对表达式的控制。 但说实话,防御RCE最难的地方不在技术,在开发习惯。很多开发者觉得“我内部系统,没人会攻击”。Equifax也这么想。结果呢?一个没及时打的补丁,赔了7亿美元。RCE漏洞的利用门槛在不断降低,自动化利用工具满天飞,Shiro反序列化工具、Struts2利用工具,GitHub上随便搜。攻击者不需要多高的技术水平,拿着工具扫一遍,有漏洞的机器就沦陷了。 还有个现实问题:很多RCE漏洞出现在第三方组件里。你代码写得再安全,引用的库有漏洞,照样中招。Log4j2那个CVE-2021-44228,一个JNDI注入,全球多少系统受影响?Java生态里Log4j的普及率太高了,几乎无处不在。这种供应链层面的RCE,靠单个开发者根本防不住,只能靠及时更新依赖、关注安全公告。 RCE漏洞不会消失。只要还有程序需要执行系统命令,只要还有开发者图省事直接拼接字符串,只要还有系统不及时打补丁,RCE就会一直存在。对攻击者来说,这是最高效的入侵方式。对防御者来说,这是最不能容忍的失误。一个RCE,足以让整个系统沦陷。ping -c 4 [用户输入]。如果用户输入的不是IP,而是127.0.0.1; cat /etc/passwd,那后面的命令也会被执行。分号、管道符、反引号、$(),这些都是命令拼接的入口。