当前位置:首页 > 休闲

webshell扫描

凌晨两点,扫描日志里跳出一条奇怪的扫描POST请求。路径是扫描 `/uploads/2023/logo.php`,但那个目录只该放图片。扫描我盯着屏幕愣了几秒——这台服务器被人挂了webshell。扫描

webshell这东西,扫描说白了就是扫描一段跑在服务器上的代码,攻击者通过它远程执行命令、扫描翻文件、扫描连数据库。扫描它长得像正常脚本,扫描可能伪装成图片马、扫描日志文件,扫描甚至藏在 `.htaccess` 里。扫描很多人以为只有PHP有这问题,扫描其实ASP、JSP、Python CGI都一样中招。去年我帮一个朋友查他那个WordPress站,发现 `wp-content/uploads` 下多了个 `cache.php`,内容就一行:``。够简单,够致命。

扫描webshell,靠特征匹配远远不够。早期工具比如D盾、河马,主要比对已知后门特征码。攻击者稍微混淆一下——base64、gzinflate、字符串拼接、变量函数——就绕过去了。我见过一个样本,把 `eval` 拆成 `$a='ev'.'al'; $a($_POST[1]);`,静态规则根本认不出来。所以现在更靠谱的做法是结合语法树分析和行为监控。

说个具体案例。上个月应急响应,客户一台CentOS服务器CPU跑满。`top` 一看,`php-fpm` 占了几百百分比。用 `lsof -p` 追过去,发现进程在反复读 `/tmp/.ICE-unix/` 下一个叫 `sess_xxx` 的文件。打开一瞧,里面是混淆过的PHP代码,用 `assert` 执行外部输入。这个shell没有用常见函数名,而是通过 `array_map` 加 `create_function` 动态构造。普通扫描器直接漏报。后来我用 `find / -name "*.php" -mtime -7` 配合 `grep -rE "eval|assert|system|passthru|popen|proc_open"` 才把它揪出来。但这种方法误报高,得人工过一遍。

更实用的思路是监控文件完整性。用 `aide` 或者 `tripwire` 给web目录做基线,任何新增或修改的PHP文件都报警。再配上 `inotifywait` 实时盯 `upload`、`cache`、`logs` 这些高危目录。有一次攻击者上传了一个 `.php.jpg`,Apache配置不当当成PHP执行了。`inotify` 立刻触发告警,我赶在它连C2之前删掉了文件。那感觉比中彩票还爽。

别迷信商业扫描器。我试过几款,对已知样本查杀率不错,但遇到内存马——也就是不落地文件的webshell——全瞎。内存马通过 `php://input` 或者 `auto_prepend_file` 注入,进程里跑着,磁盘上找不到。这时候得靠 `strace` 跟系统调用,或者用 `eBPF` 挂钩子监控 `execve`。普通运维搞不定这些,但至少可以限制 `disable_functions`,把 `eval`、`assert`、`system` 全禁掉。虽然可能影响正常业务,但比被拖库强。

最后说个血泪教训。有次我扫到个shell,路径是 `/var/www/html/.well-known/acme-challenge/` 下一个随机名文件。当时以为误报,因为那个目录是Let's Encrypt验证用的。结果攻击者就是利用ACME验证时临时写文件的特性,把shell塞进去,验证完不删。扫描工具如果只认扩展名,肯定漏。所以别只看 `.php`,`.phtml`、`.php5`、`.inc`、甚至没有扩展名的文件都得查。用 `file` 命令看MIME类型,比看后缀靠谱。

webshell扫描没有银弹。特征库要更新,行为监控要细,文件完整性要勤查,权限要最小化。我习惯每天跑一次 `find /var/www -type f -newer /tmp/last_scan -exec grep -l "eval\|base64_decode\|gzinflate" { } \;`,然后人工看结果。麻烦,但安心。毕竟服务器被拿下的代价,比熬夜扫马高多了。

分享到: