Webshell流量特征分析:菜刀、蚁剑、冰蝎、哥斯拉识别与检测
在安全运营这个行当待久了Webshell排查基本是每个蓝队人都躲不过去的活。不管护网还是日常应急流量侧分析永远是第一时间发现问题的关键手段。菜刀、蚁剑、冰蝎、哥斯拉这四个名字可以说是Webshell管理工具里的“四大天王”贯穿了从明文时代到全加密时代的演变。这篇文章我打算直接从流量特征入手把这四个工具从里到外拆一遍搞清楚它们各自在网络上留下的“指纹”到底是什么防守方又该如何精准识别。文章不是给攻击者看的教程而是写给防守方看的排查手册。适合刚接触安全运营的新人也适合在应急响应时想快速建立排查思路的进阶从业者。我会把每个工具的通信原理、请求特征、编码方式、时序行为都讲透最后落到实际检测规则和排障技巧上保证你看完能直接用得上。1. 流量分析的核心思路先搞清楚要抓什么很多人拿到流量包第一反应就是翻HTTP请求找有没有POST接口看有没有base64字符串。这个思路对一半因为传统的菜刀确实这么干但到了冰蝎和哥斯拉这个年代流量已经是密文了靠肉眼盯几个关键字根本盯不出来。所以做流量分析先得建立正确的分析框架。1.1 流量分析的三个维度我习惯把Webshell通信特征拆成三个维度来看缺一不可协议层特征通信都走HTTP还是HTTPSUser-Agent是什么Content-Type是什么请求是GET还是POST有没有明显的分块传输或者畸形请求这些是最容易搞定的一层。载荷层特征传输内容的编码方式是什么是base64、hex还是自定义算法payload的结构是否固定比如有没有固定的参数名、固定的分隔符、固定的填充值。明文工具看这一层就够了加密工具只能看到密文本身的结构性特征。行为层特征单个请求看不出问题时要看请求的节奏和交互模式。连接频率是否固定UA在每次请求之间是否有微小变化Response的长度是否始终不变是否先有一个“预请求”再跟一个“正式请求”这些行为指纹在对付加密流量的时特别管用。1.2 判断工具代际的简单框架我们把工具按代际分一下你心里就有谱了初代工具菜刀payload完全明文流量里直接能看到执行的命令。检测成本极低。二代工具蚁剑payload做了base64或chr()混淆特征隐藏在编码层里但解个码就能看到明文。三代工具冰蝎全域AES加密请求和响应都是密文但在加密之前存在固定的握手逻辑和密钥协商特征。四代工具哥斯拉不仅加密还可以自定义加密算法请求可以拆分成多次会话站在纯流量视角几乎看不到明文。第3、4代工具出现后传统的规则匹配思路就不够用了必须把检测重心从特征字符串迁移到行为基线和加密结构上。2. 逐个开刀四大工具的流量画像每个工具的设计理念不一样流量表现差异非常大。我直接按工龄顺序挨个说越往后越讲究。2.1 菜刀Chopper明文时代的“裸奔”流量菜刀是Webshell工具里的老前辈2011年前后非常普及。它的PHP客户端一般长这样?php eval($_POST[pass]);?对应的请求体通常是passeval(base64_decode($_POST[z0]));这里的坑点在z0参数上。z0的值是base64编码后的PHP代码decode之后你能直接看到ini_set(display_errors,0); set_time_limit(0); $opdirini_get(open_basedir); ...菜刀的流量特征用一个词概括就是**“毫无遮掩”**请求Content-Type是application/x-www-form-urlencoded参数名短促常见的有z0、z1、z2响应文字里常常混着文件路径、命令执行结果攻击payload中频繁出现eval(、assert(、base64_decode这些字符串就算攻击者对菜刀默认配置做了二次开发把参数名改了、做嵌套编码但只要流量里最终会出现eval等危险函数就有机会被WAF或IDS抓个正着。排查建议直接在日志里搜base64_decode、eval(这类敏感字符串。如果发现某些POST参数名极短且内容是一长串base64请先拉黑观察。菜刀特征速查表明文特征明显参数名短z0/z1/z2content-type为表单响应包含路径信息。检测难度极低。2.2 蚁剑AntSword明修栈道暗度陈仓蚁剑本质上是菜刀思路的升级版。它的核心解码逻辑是用一个动态生成的PHP载荷然后在客户端动态拼接数据。所以流量层面最大的特点是编码随机化。典型蚁剑PHP请求体大概长这样ini_set(display_errors,0); set_time_limit(0); $opdirini_get(open_basedir); if($opdir){$ocwddirname($_SERVER[SCRIPT_FILENAME]);...}注意终端命令本身也会被base64编码整体再用eval或assert执行。比如执行whoami时流量里可能是这样一段$sbase64_decode(d2hvYW1p);d2hvYW1p解出来就是whoami。蚁剑跟菜刀最大的不同在于随机性。它每次请求生成的PHP代码块结构都有差异变量名是随机的编码方式可以切换还会插入大量冗余代码和无意义变量来扰乱正则。单纯靠匹配base64_decode特征现在已经防不住蚁剑了。但是蚁剑还有一个致命的习惯性特征UA标识。虽然新版蚁剑允许自定义UA但默认状态下的UA是antSword/v2.1另外蚁剑的请求头User-Agent是可以修改的所以这个特征只能作为辅助判断。更硬的指标是它的请求体逻辑结构比如几乎所有请求里都会出现ini_set和set_time_limit这两个函数的组合再配合后续的dirname($_SERVER[SCRIPT_FILENAME])路径探测这套组合拳很难在其他正常业务请求里出现。排查建议不要只盯着UA。重点查看PHP请求体里是否出现了ini_set set_time_limit dirname三件套同时结合是否包含base64_decode特征进行综合判断。2.3 冰蝎Behinder密钥先行的加密隧道冰蝎和前面两位完全不是一个物种。它出场的时候流量几乎已经全加密了。通信前客户端和服务端会先用一个固定密钥默认key是e45e329feb5d925b做AES加密握手之后所有指令都走加密通道。一次典型冰蝎通信的请求流程分三步建立密钥会话类GET请求那个阶段会先尝试访问服务端这时响应里会带一个固定的密钥标志。请求密钥参数客户端通过特定参数默认是pass把一个加密的XML结构发给服务端服务端返回AES加密后的密钥材料和标志位。正常通信阶段此后每个请求体的关键参数都被AES加密密文用base64承载。冰蝎流量有几个硬指标值得关注Accept头冰蝎默认的Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8是固定节奏。Content-Type通常是application/x-www-form-urlencoded但载荷中会刻意填充随机长度的数据来掩盖密文长度一致的问题。Content-Length响应长度往往高度一致。AES的块大小是固定的所以每个回显加密后长度基本相同。Cookie冰蝎默认在Cookie里塞一个固定的PHPSESSID路径每次会话虽然不同但行为上会先GET一次再POST一次类似Session握手。还有一点值得注意冰蝎的AES密钥硬编码在客户端代码里解密后payload开头往往有固定结构。虽然每个版本结构不同但新版本冰蝎的握手包会带一个固定注解这在流量中会有一定的回落规律。排查建议如果发现大量POST响应长度几乎不变的请求优先怀疑冰蝎。对这类请求没有必要强行解密密文看协商过程和包长特征反而更快。2.4 哥斯拉Godzilla从加密到“拟态”哥斯拉是目前四大工具里最讲究的一代它对流量做了“拟态设计”目的是让流量看起来跟正常业务一样。哥斯拉支持AES、XOR等自定义加密算法甚至可以把密钥跟服务端密钥做动态协商。它可以自定义请求体里的参数名也可以把载荷包在JSON里、XML里或者文件上传里。哥斯拉流量链路的基本逻辑是选择一个密码参数作为密钥入口比如pass服务端通过这个参数接收密文。密文采用payload 签名 填充的结构填充长度随机以规避长度分析。响应部分也加密末尾还会追加一段随机数据来混淆长度。**哥斯拉的核心破绽在它的解密逻辑而非密文本身。**比如PHP版本哥斯拉的payload里有一段固定的key生成节点不同模式下的偏移量不同。如果攻击者不做二次开发流量里会存在固定的AES密钥块比如md5(pass)的前16位这对熟悉工具源码的人来说反而是一条可以人工验证的路子。实际排查时哥斯拉最大的弱点是请求和响应的节奏过于机械。同一个样本上来看哥斯拉的请求每次都是POST POST成对出现且两次POST之间的间隔极短。若所有请求的Content-Length都相差无几响应最短长度一致这本身就不符合正常人类操作节奏。排查建议哥斯拉不好用特征一刀切建议以行为分析为主同源IP在同一时间窗口内连续出现固定参数的POST请求且响应长度类似的优先做深度检测。工具流量特征对比汇总工具载荷形态主要识别维度检测难度菜刀明文base64eval函数、短参数名极低蚁剑随机混淆base64UA、ini_set组合、随机变量低冰蝎AES全加密固定Accept、响应长度均一中高哥斯拉自定义加密拟态请求节奏、参数固定规律高3. 实操从抓包到检测规则落地的完整流程前面说的是理论特征这部分才是真正动手的部分。我会按自己平时做分析时的流程走一遍包括怎么搭环境、怎么抓流量、怎么提取特征最后怎么把特征变成可持续检测的规则。3.1 环境搭建与抓包配置要分析流量特征首先得有一套“靶场环境”。我的标准配置是这样的部署一个基础环境安装PHP、Apache或者Nginx目的就是放置Webshell文件。用虚拟机快照保证每次测试完可以快速恢复干净状态。抓包工具我用Burp Suite做中间人代理同时开启Wireshark做全流量镜像。客户端则是Windows下跑四个工具注意工具的版本要统一方便重现。抓包时有几个细节必须注意关闭HTTPS拦截之外的任何缓存插件避免浏览器或工具复用连接导致流量不全。Burp里开启HTTP history和WebSockets history两个面板就算工具走的是HTTP2也要能抓到。Wireshark的过滤器提前写清楚http.request || tls.handshake.type 1。如果我需要看加密流量就直接在Burp里解密后再导出省得硬啃密文。有个坑提前说一下别在一台机器上切换多个代理端口工具会缓存代理配置。我遇到过蚁剑的代理配置失效所有请求都直接出去了抓包抓了个寂寞。3.2 请求样本采集与特征提取记录我以冰蝎为例说一次完整的分析记录。先正常跑一遍拿到请求后第一步先看HTTP头POST /shell.php HTTP/1.1 Host: 192.168.1.123 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Accept-Language: zh-CN,zh-HK;q0.8,en-US;q0.6,en;q0.4 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSIDabcdef123456 Connection: close Content-Length: 296这里有几个关键发现第一Accept值里带了一长串F级别的内容正常业务很少这样填。第二Cookie里的PHPSESSID看起来是PHP默认引擎生成的但如果不访问任何PHP会话页面为何会有session第三Content-Length: 296这个长度几乎固定无论执行什么命令。因为加密后的payload是填充过的长度不影响。再看请求体passgfQ5D6F1...一段AES加密的base64字符串这里有个有意思的细节加密后的字符串末尾经常带这是AES-CBC模式下带PKCS7填充后base64的常见特征。另一个细节是请求体里除了pass参数之外没有其他参数干净得反常。正常业务表单很少只有一个参数且值是纯密文。基于这个分析我提取冰蝎的核心特征就是请求体参数名固定且单一默认是pass参数值为长base64字符串带结尾Content-Length相对稳定针对同一服务端响应体是压缩后的二进制或base64且hex转储后能看到AES相关块这个流程拿到蚂蚁剑和哥斯拉那边也适用就是提取的特征点会不一样蚁剑提取的是函数组合哥斯拉提取的是请求节奏。工具是死的分析方法是活的。3.3 把特征落成检测规则很多人以为检测规则就是写几个正则匹配关键字这个思路能防菜刀防不了冰蝎和哥斯拉。我建议用三层检测策略。第一层规则匹配层针对明文特征适用工具菜刀、部分蚁剑。# 简化版Python检测示例 import re def detect_webshell_request(payload): suspicious_keywords [ rbase64_decode\s*\(, r\s*eval\s*\(, r\s*assert\s*\(, r\s*ini_set\s*\(, r\$_\s*POST\s*\[, ] for pattern in suspicious_keywords: if re.search(pattern, payload): return True return False针对蚁剑的ini_set组合特征可以专门写一条规则同时出现ini_set和set_time_limit且后续跟随dirname的直接命中高危。第二层结构检测层针对加密流量适用工具冰蝎、哥斯拉。加密流量没法直接解正则但结构特征还是可以看。例如请求体参数值长度是否一致响应Content-Length是否稳定请求是否固定成对出现Accept头是否异常完整响应中是否存在结尾的密文块这些规则不适合写在WAF的正则引擎里更适合放在NDR或者流量分析平台上做聚合统计。比如某源IP在5分钟内针对某个URL发起超过5次POST请求且请求体的参数名和长度都恒定直接跳出告警。第三层行为基线层针对拟态流量这一层不看单个包看会话序列。正常的浏览器访问一个Web应用请求是多样化的有GET有POST有静态资源有时间间隔。而Webshell工具的操作序列千篇一律工具连接后立刻执行命令然后断开。整个过程不会去加载图片、不会点击链接、更不会滚动页面。通过流量会话重建如Zeek等工具直接看“页面访问深度”和“交互多样性”两个指标。一个URL被同一IP反复POST且没有前置GET页面浏览这个行为本身就足够可疑。4. 常见问题与排查技巧实录实际操作中总会遇到各种奇怪的坑。我在这里把踩过的坑和经验整理成几个典型的排查场景应该比你看十篇理论文章都有用。4.1 误报极高的“疑似冰蝎”流量我最开始写冰蝎检测规则的时候遇到过一个很有意思的误报场景。某业务系统上报大量“疑似冰蝎”告警特征是完全匹配固定参数名、固定Content-Length、AES加密字样。后来把流量解出来发现那只是一个用了HTTPS的入口网关在做加密转发把内部请求重新封装了一遍。排查这类问题核心是看接口语义。如果这个URL是登录接口、图形验证码接口或者下单接口那么它的确定性参数是合理的业务结构。比如登录接口固定传username和password内容也加密但它是带着业务标识的。而Webshell工具的参数永远只有一个或两个没有业务含义。这个辨别点非常重要。4.2 加密流量里怎么找明文痕迹冰蝎和哥斯拉虽然流量是加密的但攻击者往往会在服务端Webshell文件里留下线索。而从流量侧看工具在发起加密请求之前通常有一个“测试连接”的行为。这个预请求很关键它不加密因为服务端还没有会话。例如哥斯拉的“测试连接”会发送一个携带特殊参数的数据包比如echo md5(123456)这种校验逻辑。虽然是加密传输但如果你在Wireshark里顺着TCP流往下翻偶尔能在某个SSL协商后未加密的握手包中看到一个类似key...的明文参数。这个抓住了可以直接手工关联后续的加密流。4.3 应急响应时流量排查的优先顺序如果只有半小时排查一个疑似Webshell别漫无目的地翻包。我的经验按这个顺序走先查最近5分钟的新鲜告警拉出全部HTTPS解密后的会话筛POST请求然后按响应长度排序看是否有长度集中的异常再过滤带常见Webshell参数名pass、s、z0、cmd的会话全部标红最后用工具直接对可疑请求做解密验证。每一步中间如果有发现停下深挖不要继续扩大范围。从实战数据来看60%的Webshell攻击都可以在第一步、第二步被识别。4.4 追踪溯源时流量能提供的额外证据Webshell流量分析不只是用于检测在溯源阶段同样有价值。通过分析流量中的UA、Cookie、请求时间可精准还原攻击者的行为路径。比如蚁剑有个默认逻辑是发起连接后先获取当前目录那么它在payload里会带一个获取getcwd()的请求响应里回显路径。这个路径一旦跟真实服务器路径对上就能确定这台机器的哪个目录被脱了壳。另外工具的种类能暗示攻击者的习惯和水平。菜刀多数时候是扫描器自动打的蚁剑通常是人肉操作冰蝎和哥斯拉可能是在维护一个常驻后门。这些差异化信息在报告里写出来比单纯列IP有价值得多。4.5 一个容易忽略的“非标准端口”问题团队成员曾遇到一次“漏报”事件哥斯拉的所有特征我们全部命中但告警就是不触发。后来查下来发现攻击者把Webshell部署在了一个非标准端口比如8080上而我们的流量分析平台默认只监听80和443端口。所以凡是做Webshell流量分析一定要把全端口覆盖作为一个前置条件。标准端口之外的服务尤其是8080、8443、8888这些常见Web端口必须纳入检测范围。攻击者不会傻到非要用80端口把后门暴露给防守方。写在最后的一点经验这几种工具我前前后后分析了不少样本有个很深的体会工具本身的能力差异不是最关键的防守方的思维层级才是。菜刀时代大家拼的是规则覆盖蚁剑时代大家拼的是绕过与反绕过冰蝎和哥斯拉出现后拼的其实是“能不能理解加密流量背后的行为逻辑”。你如果能从一段无意义的密文中想起“为什么这个Content-Length这么整齐”那你离真相就不远了。还有个小建议平时做流量分析时多留一份样本库。不管是Burp导出的HTTP history还是Wireshark的pcapng都按工具和版本归档好。等到下次遇到类似流量时直接对比样本库能省一半以上的排查时间。实际操作中我见过太多安全工程师把时间耗在反复解同一个密文上其实正确的姿势是先判断“这到底是不是攻击流量”。这个判断力只能靠一次次的实弹积累没有任何捷径。