当前位置:首页 > 综合

远程命令执行漏洞怎么解决

去年某电商平台被拖库,远程攻击者用的命令就是一个还没修复的Struts2远程命令执行漏洞。从上传恶意请求到服务器执行`whoami`,执行整个过程不到三秒。漏洞运维团队甚至没来得及看日志,解决数据库连接串就已经被打包传走了。远程这类漏洞的命令破坏力从来不在“能不能执行命令”,而在于“执行得多快、执行多隐蔽”。漏洞

远程命令执行(RCE)的解决本质是:用户输入的数据被当成代码跑了。可能是远程系统命令,也可能是命令脚本代码。问题出在数据流和指令流没分家。执行PHP里的漏洞`system($_GET['cmd'])`是最蠢的写法,但现实里更常见的解决是框架反序列化、表达式注入、模板注入——数据绕了几层,最后还是进了`exec`。

我见过一个真实案例。某企业内部系统用Jackson做JSON反序列化,开了`enableDefaultTyping`。攻击者构造一个`@class`指向`com.sun.rowset.JdbcRowSetImpl`,配合JNDI注入,直接加载远程class文件。服务器上没装杀软,防火墙也没拦出站LDAP请求。从漏洞披露到被利用,中间隔了四个月,补丁一直挂在测试环境没上生产。

解决RCE,第一件事不是写WAF规则,而是把“数据永远不能变成代码”这条原则焊死在架构里。具体怎么做?参数化查询能防SQL注入,同样思路可以推广到命令执行。Java里别用`Runtime.exec(String)`,改用`ProcessBuilder`传数组,每个参数独立,不经过shell解析。PHP禁用`system`、`exec`、`passthru`、`popen`、`proc_open`,在php.ini里加`disable_functions`,但注意`putenv`和`mail`这类函数可能绕过。

反序列化漏洞更麻烦。Java的`ObjectInputStream`根本不该处理不可信数据。如果业务非要传序列化对象,用白名单机制——`ObjectInputFilter`在JDK 9+可以用,老版本就自己写`resolveClass`校验。Fastjson、Jackson这些库,关掉autoType,别偷懒。Python的`pickle`同理,永远不要`pickle.loads`来自网络的字节流。YAML用`safe_load`,别用`load`。

表达式注入是另一个重灾区。Spring EL、OGNL、SpEL,这些本来是为了灵活配置,结果变成了RCE入口。Struts2的S2-045就是Content-Type头里的OGNL表达式被解析执行。修法很简单:升级到最新版,然后关掉不必要的动态表达式求值。如果业务必须用,加沙箱——Java SecurityManager虽然 deprecated,但比裸奔强。或者用`ExpressionParser`时限制类加载器。

WAF有没有用?有,但别指望它兜底。RCE的payload变形太快,`cat /etc/passwd`可以写成`c\at /etc/pas\swd`,或者用`$IFS`代替空格。基于正则的WAF很容易绕过。真正有效的是RASP——运行时应用自我保护。在`Runtime.exec`、`ProcessBuilder.start`、`JNDI` lookup这些关键方法上插桩,检测调用栈里有没有用户输入。有就阻断,并打日志。OpenRASP和JRASP都算可用方案,但性能损耗得实测,高并发下可能到5%到10%。

最小权限原则不能只写在文档里。Web进程别用root跑,用`www-data`或者独立用户。容器里加`readOnlyRootFilesystem`,`dropCapabilities`,禁止`ptrace`。Linux的seccomp可以限制系统调用,Docker默认已经禁了`clone`带`CLONE_NEWUSER`这类危险flag。但很多人为了图方便,`--privileged`一开,全白搭。

日志和监控得能抓到异常。RCE利用往往伴随异常子进程——比如web用户突然起了`bash`、`sh`、`curl`、`wget`。用auditd或者eBPF监控`execve`,规则写死:父进程是nginx或tomcat,子进程是shell,直接告警。我见过一个团队靠这个在攻击者横向移动前掐断了连接。他们没买商业EDR,就用`bpftrace`写了个十行脚本。

最后说句实在的:没有银弹。RCE的根因是代码把数据和指令混在一起,这是设计问题,不是配置问题。升级依赖、关危险函数、加沙箱、上RASP、最小权限、监控子进程——每层都做一点,攻击成本就上去了。别想着一步到位,先把手头那个用了五年的Fastjson 1.2.24换掉,比什么方案都管用。

分享到: