在安全运营这个行当待久了,Webshell排查基本是每个蓝队人都躲不过去的活。不管护网还是日常应急,流量侧分析永远是第一时间发现问题的关键手段。菜刀、蚁剑、冰蝎、哥斯拉,这四个名字可以说是Webshell管理工具里的“四大天王”,贯穿了从明文时代到全加密时代的演变。这篇文章我打算直接从流量特征入手,把这四个工具从里到外拆一遍,搞清楚它们各自在网络上留下的“指纹”到底是什么,防守方又该如何精准识别。文章不是给攻击者看的教程,而是写给防守方看的排查手册。适合刚接触安全运营的新人,也适合在应急响应时想快速建立排查思路的进阶从业者。我会把每个工具的通信原理、请求特征、编码方式、时序行为都讲透,最后落到实际检测规则和排障技巧上,保证你看完能直接用得上。1. 流量分析的核心思路:先搞清楚要抓什么很多人拿到流量包第一反应就是翻HTTP请求,找有没有POST接口,看有没有base64字符串。这个思路对一半,因为传统的菜刀确实这么干,但到了冰蝎和哥斯拉这个年代,流量已经是密文了,靠肉眼盯几个关键字根本盯不出来。所以做流量分析,先得建立正确的分析框架。1.1 流量分析的三个维度我习惯把Webshell通信特征拆成三个维度来看,缺一不可:协议层特征:通信都走HTTP还是HTTPS?User-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']);?>对应的请求体通常是:pass=@eval(base64_decode($_POST['z0']));这里的坑点在z0参数上。z0的值是base64编码后的PHP代码,decode之后你能直接看到:@ini_set("display_errors","0"); @set_time_limit(0); $opdir=@ini_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/z2),content-type为表单,响应包含路径信息。检测难度:极低。2.2 蚁剑(AntSword):明修栈道,暗度陈仓蚁剑本质上是菜刀思路的升级版。它的核心解码逻辑是用一个动态生成的PHP载荷,然后在客户端动态拼接数据。所以流量层面最大的特点是编码随机化。典型蚁剑PHP请求体大概长这样:@ini_set("display_errors","0"); @set_time_limit(0); $opdir=@ini_get("open_basedir"); if($opdir){$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);...}注意,终端命令本身也会被base64编码,整体再用eval或assert执行。比如执行whoami时,流量里可能是这样一段:$s=base64_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/xhtml+xml,application/xml;q=0.9,*/*;q=0.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/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh-HK;q=0.8,en-US;q=0.6,en;q=0.4 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSID=abcdef123456 Connection: close Content-Length: 296这里有几个关键发现:第一,Accept值里带了一长串F级别的内容,正常业务很少这样填。第二,Cookie里的PHPSESSID看起来是PHP默认引擎生成的,但如果不访问任何PHP会话页面,为何会有session?第三,Content-Length: 296,这个长度几乎固定,无论执行什么命令。因为加密后的payload是填充过的,长度不影响。再看请求体:pass=gfQ5D6F1...(一段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 = [ r'base64_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,都按工具和版本归档好。等到下次遇到类似流量时,直接对比样本库,能省一半以上的排查时间。实际操作中,我见过太多安全工程师把时间耗在反复解同一个密文上,其实正确的姿势是先判断“这到底是不是攻击流量”。这个判断力,只能靠一次次的实弹积累,没有任何捷径。
在安全运营这个行当待久了,Webshell排查基本是每个蓝队人都躲不过去的活。不管护网还是日常应急,流量侧分析永远是第一时间发现问题的关键手段。菜刀、蚁剑、冰蝎、哥斯拉,这四个名字可以说是Webshell管理工具里的“四大天王”,贯穿了从明文时代到全加密时代的演变。这篇文章我打算直接从流量特征入手,把这四个工具从里到外拆一遍,搞清楚它们各自在网络上留下的“指纹”到底是什么,防守方又该如何精准识别。文章不是给攻击者看的教程,而是写给防守方看的排查手册。适合刚接触安全运营的新人,也适合在应急响应时想快速建立排查思路的进阶从业者。我会把每个工具的通信原理、请求特征、编码方式、时序行为都讲透,最后落到实际检测规则和排障技巧上,保证你看完能直接用得上。1. 流量分析的核心思路:先搞清楚要抓什么很多人拿到流量包第一反应就是翻HTTP请求,找有没有POST接口,看有没有base64字符串。这个思路对一半,因为传统的菜刀确实这么干,但到了冰蝎和哥斯拉这个年代,流量已经是密文了,靠肉眼盯几个关键字根本盯不出来。所以做流量分析,先得建立正确的分析框架。1.1 流量分析的三个维度我习惯把Webshell通信特征拆成三个维度来看,缺一不可:协议层特征:通信都走HTTP还是HTTPS?User-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']);?>对应的请求体通常是:pass=@eval(base64_decode($_POST['z0']));这里的坑点在z0参数上。z0的值是base64编码后的PHP代码,decode之后你能直接看到:@ini_set("display_errors","0"); @set_time_limit(0); $opdir=@ini_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/z2),content-type为表单,响应包含路径信息。检测难度:极低。2.2 蚁剑(AntSword):明修栈道,暗度陈仓蚁剑本质上是菜刀思路的升级版。它的核心解码逻辑是用一个动态生成的PHP载荷,然后在客户端动态拼接数据。所以流量层面最大的特点是编码随机化。典型蚁剑PHP请求体大概长这样:@ini_set("display_errors","0"); @set_time_limit(0); $opdir=@ini_get("open_basedir"); if($opdir){$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);...}注意,终端命令本身也会被base64编码,整体再用eval或assert执行。比如执行whoami时,流量里可能是这样一段:$s=base64_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/xhtml+xml,application/xml;q=0.9,*/*;q=0.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/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh-HK;q=0.8,en-US;q=0.6,en;q=0.4 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSID=abcdef123456 Connection: close Content-Length: 296这里有几个关键发现:第一,Accept值里带了一长串F级别的内容,正常业务很少这样填。第二,Cookie里的PHPSESSID看起来是PHP默认引擎生成的,但如果不访问任何PHP会话页面,为何会有session?第三,Content-Length: 296,这个长度几乎固定,无论执行什么命令。因为加密后的payload是填充过的,长度不影响。再看请求体:pass=gfQ5D6F1...(一段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 = [ r'base64_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,都按工具和版本归档好。等到下次遇到类似流量时,直接对比样本库,能省一半以上的排查时间。实际操作中,我见过太多安全工程师把时间耗在反复解同一个密文上,其实正确的姿势是先判断“这到底是不是攻击流量”。这个判断力,只能靠一次次的实弹积累,没有任何捷径。