游客发表

命令执行漏洞的防护手段

发帖时间:2026-10-17 05:09:20

```html 命令执行漏洞的命令防护手段

命令执行漏洞的防护手段

去年一个朋友的公司被拖库了,原因说出来你可能不信——运维图省事,执行在后台管理页面直接拼了个 ping 命令去检测服务器存活。漏洞攻击者把 IP 地址填成 127.0.0.1; cat /etc/passwd,防段整个系统的护手用户哈希就全吐出来了。这种漏洞从来不是命令“会不会发生”的问题,而是执行“什么时候被盯上”。命令执行漏洞的漏洞破坏力在于,它直接绕过了应用逻辑,防段把操作系统的护手 shell 当成了后门。防护的命令核心就一件事:永远不要相信用户输入会老老实实当参数。

最直接的执行手段是禁用危险函数。PHP 里的漏洞 system、exec、防段shell_exec、护手passthru、popen、proc_open,能关就关。在 php.ini 里找到 disable_functions,把这些全塞进去。Java 那边呢?Runtime.getRuntime().exec() 和 ProcessBuilder 是重灾区,如果业务上根本用不到调外部程序,直接在代码审计阶段标记为红线。我见过一个项目,开发为了“方便”,用 exec 调 ffmpeg 转视频,结果上传文件名没过滤,攻击者传了个 test.mp4; rm -rf /tmp/*,整个临时目录被清空。禁用函数不是万能药,但至少把攻击面砍掉一大半。

如果业务确实需要调系统命令,那就必须做参数化处理。别用字符串拼接,别用 shell=True。Python 的 subprocess 模块,默认 shell=False,你传一个列表进去,每个参数独立传递,shell 根本没机会解释分号、管道符和反引号。比如要查 DNS,写成 subprocess.run(['dig', user_input, 'A']),攻击者就算输入 ; rm -rf /,也只会被当成一个非法域名,dig 报错退出。Java 里用 ProcessBuilder 的列表构造方式,同理。关键是理解:参数化不是过滤,而是让 shell 根本没有机会解析你的输入。

输入过滤当然也要做,但别指望它当主力。白名单比黑名单靠谱得多。比如只允许 IP 地址,那就用正则严格匹配 ^(\d{ 1,3}\.){ 3}\d{ 1,3}$,多一个字符都不行。如果允许域名,就限制字符集为字母、数字、点和连字符。黑名单过滤分号、管道、&、$、反引号?攻击者可以用编码绕过,用 ${ IFS} 代替空格,用 \n 代替分号。我见过一个 WAF 规则只拦了 ;,结果攻击者用 %0a 换行照样执行。过滤是补丁,不是地基。

权限最小化是最容易被忽略的一环。Web 服务进程别用 root 跑,这是常识,但很多容器化部署里,Dockerfile 忘了写 USER nobody,容器里就是 root。一旦命令执行成功,攻击者直接拿到宿主机 root 权限。还有,把 /bin/sh、/bin/bash 的权限收紧,或者用 chroot 把 Web 服务关进笼子。我自己的服务器上,Web 进程的用户连 ls 都执行不了,因为 PATH 被清空了,只保留了必要的几个二进制路径。攻击者就算能注入命令,也找不到可用的 shell。

日志和监控得跟上。命令执行漏洞利用时,通常会有异常的子进程创建。比如 Web 进程突然 fork 出一个 bash 或 cmd.exe,这本身就是强信号。用 auditd 监控 execve 系统调用,或者用 falco 这类运行时安全工具,设置规则:任何 Web 进程启动 shell 就告警。别等数据被拖走了才看日志。有一次我帮客户排查,发现攻击者用 curl 往外传数据,而 curl 的调用记录在 audit.log 里躺了三天没人看。监控不是装样子,是要有人盯着告警。

最后说个反直觉的点:很多命令执行漏洞根本不需要调 shell。比如用 Runtime.exec("ping " + ip),Java 会按空格拆分参数,但攻击者输入 127.0.0.1 -c 100000 就能让 ping 跑满 CPU。这不算命令注入,但一样是命令参数注入。防护思路是一样的——别让用户输入控制命令的结构。用 ProcessBuilder 传列表,或者干脆用 Java 的 InetAddress.isReachable() 替代调 ping。能不用外部命令,就别用。每减少一次 exec 调用,就少一个可能被利用的入口。

说到底,命令执行漏洞的防护不是靠某个“银弹”函数,而是靠一层层习惯:默认禁用、参数化调用、白名单校验、权限收窄、行为监控。哪一层偷懒,哪一层就是突破口。
```

    热门排行

    友情链接