收到过不少朋友的提问:网站上被传了webshell、数据库被拖了、后台密码被爆破了,可日志翻来翻去就是找不到攻击者到底怎么进来的。这时候如果手边有一份从边界或者Web层抓下来的pcap文件,事情往往会简单很多。用Wireshark打开这份pcap,从HTTP流量里按图索骥还原攻击链,是我做应急响应和溯源分析时最常用的手段,也是我今天想完整分享的一套实操流程。
这篇文章会以“Wireshark抓包分析:如何从HTTP流量中快速定位黑客攻击痕迹”为主题,从环境准备、过滤器语法、统计视图、TCP流还原到典型攻击特征对照,把一套能直接落地的分析方法讲透。适合刚接触流量分析的安全新人,也适合需要快速上手做应急研判的运维和开发同学。文末提到的pcap文件,既可以是自己抓的实验流量,也可以是实战中保留下来的攻击样本,分析方法完全一样。
1. 这个项目到底要解决什么问题
流量分析说起来高大上,落到实际场景里就一句话:在海量数据包中,把“可疑的那几个”挑出来,并还原出它干了什么。HTTP流量又是其中最优先看的部分,因为Web攻击占了绝大多数攻击面,而HTTP请求和响应天然携带大量语义信息,URL参数、UA头、POST内容、响应状态码,都是判断攻击行为的重要依据。
我见过很多人在拿到pcap后第一反应是直接点击过滤框输入“http”,然后开始一个个翻数据包。这种做法不是完全不行,但效率极低,10分钟就能把人看晕。正确思路是先做“降噪”,再“定位”,最后“还原”。降噪靠统计视图和过滤器把流量规模压下来,定位靠特征筛选找出包含攻击payload的包,还原靠Follow TCP Stream把一次完整请求响应拼起来看。
这套思路还有个隐藏的价值:它能帮你形成“攻击者视角”。当你反复从流量里识别SQL注入、目录扫描、Webshell连接这些行为后,再去看系统日志、WAF告警,会自然建立关联,知道日志里哪条记录值得追到底。
2. Wireshark分析HTTP流量的基本功
Wireshark的界面一眼看上去全是数据包,新手很容易懵。但真正常用的能力其实就三块:过滤器、显示列配置、统计视图。把这三块用熟,分析效率能翻倍。
2.1 过滤器语法:会用这几个就够起步
Wireshark有两套过滤器:抓包过滤器(Capture Filter)和显示过滤器(Display Filter)。日常分析更多用显示过滤器,它作用于已经抓到的数据包上,灵活性极高。
先记几个最基础的:
http显示所有HTTP协议相关的数据包,等价于http.request or http.response,适合刚打开pcap时快速看有没有HTTP流量。
http.request只看HTTP请求,过滤掉响应包。定位攻击者从哪里发起了什么请求时特别有用。
http.request.method == "POST"只看POST请求。登录爆破、文件上传、Webshell执行多半是POST,先用这个把范围缩小。
ip.src == 192.168.1.105只看某个来源IP发出的包。结合and http.request使用,比如:
ip.src == 192.168.1.105 and http.request这条是我日常用得最多的组合之一,直接锁定“哪个IP在发什么HTTP请求”。
http.request.uri contains "union"按URL关键字过滤。想看带SQL注入特征的请求时直接用。contains支持子串匹配,比==灵活,适合初期筛选。
tcp.stream eq 15只看第15条TCP流的全部数据包。配合Follow TCP Stream使用,是还原一次完整请求响应的关键。
2.2 显示列、时间显示与着色规则:先把界面调成战斗状态
很多人用Wireshark喜欢用默认界面,默认的列只有No.、Time、Source、Destination、Protocol、Length、Info。干流量分析建议先加几列,省去每次点开详情看字段。
在列头右键,选择“Column Preferences”,然后添加:
http.request.uri:直接看到请求的URL,不用展开数据包详情。http.response.code:直接看响应状态码,快速区分200、301、403、500。http.user_agent:看客户端身份,扫描器和浏览器在这一列上一眼就能分辨。tcp.stream:显示TCP流编号,方便对同一连接的数据包归类。
时间显示也要改。默认显示的是“时间戳”或“相对时间”,分析攻击节奏时会很不直观。在View菜单下找“Time Display Format”,我习惯改成“Seconds Since Beginning of Previous Displayed Packet”,也就是和上一个显示包之间的时间差。这样能清楚看到攻击者是不是在短时间发起大量请求——扫描和爆破的典型特征就是包间间隔非常均匀且密集。
着色规则用默认的就够,Wireshark已经把TCP SYN、RST、HTTP请求响应做了颜色区分。如果你想自定义,可以给包含特定关键字的包标记红色,比如:
http.request.uri contains "select" or http.request.uri contains "union"在View菜单的Coloring Rules里加一条,把所有带SQL关键字的请求标成红底黑字,攻击包在包列表里一眼就能挑出来。
2.3 用统计菜单看流量概貌,不被海量数据淹没
拿到一个几百MB的pcap,不要直接去翻包。先看统计,用宏观视角找异常。
Statistics菜单下有几个功能是分析HTTP流量的利器:
- Protocol Hierarchy:看整个pcap的协议分布。如果HTTP/HTTPS占比异常高,说明Web层是主要攻击面;如果TLS占绝大多数,可能需要先解决解密问题(后面会讲)。
- Conversations:看IP与IP之间的通信量。按Bytes或Packets排序,通信量异常大的那对IP往往就是攻击者和受害者的组合。比如内网某台服务器和某个公网IP之间有几百MB的HTTP流量,这就是重大嫌疑。
- HTTP > Requests:列出所有HTTP请求的URL、Host、请求次数。按请求次数排序,攻击者对同一路径反复探测的行为会在列表顶部暴露。
统计视图的作用是把“大海捞针”变成“沿着地图找针”。我做分析时,会先看Conversations确定嫌疑IP,再看HTTP Requests找到具体路径,然后才用过滤器切到包级别做精细分析。
3. 从HTTP流量中定位攻击痕迹的实操套路
直接给一套四步走的流程,这是我处理大多数Web攻击pcap时用到的标准动作。每一步都要配合具体的Wireshark操作,跟着做就能复现。
3.1 第一步:用统计视图快速锁定可疑IP
打开pcap后,第一步我不会去过滤任何东西,而是直接进Statistics > Conversations。
这时能看到一张IP通信列表。把排序方式切到Packets或Bytes,重点关注几个信号:
- 某个来源IP单独占掉大量数据包,和其他IP不在一个数量级。
- 某个外部IP和服务器之间建立了大量短连接,每次传输的数据量都很小。
- 内网IP之间出现大量HTTP通信,这在办公网环境里本身就不正常。
比如有一次排查,我发现一个欧洲IP和客户Web服务器之间有几万个HTTP请求,而服务器正常业务流量只有几千。再结合业务方确认该IP不在访问白名单里,嫌疑立刻锁定,后续用过滤器和Follow Stream一步步还原出了完整的目录扫描和SQL注入尝试过程。
锁定可疑IP后,用这个表达式把它的HTTP请求全部过滤出来:
ip.src == 可疑IP and http.request然后看包列表里的URL,攻击意图基本能猜个大概了。
3.2 第二步:筛选HTTP请求,识别异常请求模式
单个IP过滤出来后,如果流量依然很多,就按请求类型和路径做进一步筛选。
先看正常业务请求长什么样,再看异常的差在哪里。我常检查几个维度:
- 请求频率:正常用户几秒一个请求,攻击扫描器一秒可能发几十上百个请求。通过时间显示列的间隔就能看出来。
- URL路径模式:如果看到大量
/admin、/wp-login.php、/../、/etc/passwd这种路径,基本可以确定是扫描或路径穿越尝试。 - 参数内容:URL参数里出现
select、union、sleep、<script>、alert(等关键字,说明存在注入类攻击。 - HTTP版本和UA:大量HTTP/1.0请求、UA是
python-requests、Go-http-client或者干脆没有UA,很可能是工具扫描。
实际操作时,我会在过滤器里逐个测试下面的表达式:
http.request.uri contains "select" http.request.uri contains "union" http.request.uri contains "<" http.request.uri contains ".." http.request.uri contains "login"每跑一条,看包列表中的命中数量,命中越多,越可能是被攻击的重点方向。
3.3 第三步:用Follow TCP Stream还原攻击请求与响应
过滤器只能帮你定位到单条包,但攻击行为是成串的。一个完整的SQL注入尝试,包含TCP握手、HTTP请求、HTTP响应、连接关闭这一整条流。单看一个数据包只能看到零散片段,必须把整个TCP流拉出来看。
在命中可疑请求的包上右键,选择Follow > TCP Stream。Wireshark会在新窗口里把这条TCP流里双向传输的数据按原始顺序拼出来,红色的部分是客户端发的,蓝色的部分是服务器回的(颜色可在设置里调)。
这时候你能看到完整的原始HTTP请求报文,包括请求行、请求头、空行和请求体;下面跟着服务器的完整响应。一次SQL注入尝试是否成功、服务器有没有返回数据库错误信息、是否触发了500,全都能在这个窗口里确认。
如果流量里包含上传文件的POST请求,Follow TCP Stream还能直接看到上传的文件内容。有一次分析webshell上传,就是在这个窗口里看到了完整的PHP一句话代码,配合File > Export HTTP Objects把服务器返回的完整对象导出来,取证材料非常清楚。
3.4 第四步:把攻击特征做成Wireshark过滤器
分析完一条完整的攻击流后,别急着翻下一条。把这次攻击的特征提炼成过滤器,再用它全局扫描整个pcap,看看还有没有同类攻击。
继续拿SQL注入举例,第一次发现的特征是URL里出现了union select,那我用这条过滤器扫全包:
http.request.uri contains "union"如果又发现同一个IP还尝试了sleep(5),那就把范围扩大:
http.request.uri contains "union" or http.request.uri contains "sleep"再比如发现扫描器UA是nuclei,可以全包搜UA:
http.user_agent contains "nuclei"这一步的核心是“由点及面”。一次攻击很少是孤立行为,攻击者通常会批量尝试多种payload。用一个样本提炼出的特征去全局扫,往往能查出更多被忽略的攻击痕迹。
4. 常见攻击类型在HTTP流量中的特征对照
不同的攻击类型在HTTP流量里留下的痕迹差别很大。我从pcap里识别攻击者时,通常会凭一套“特征对照表”快速归类。这里挑几类最常见的展开讲。
4.1 SQL注入流量长什么样
SQL注入在HTTP流量里的特征主要集中在URL参数和POST请求体中。常见关键字包括:
union select、union all selectsleep(、benchmark(extractvalue(、updatexml(' or 1=1、' and '1'='1、1' OR '1'='1- 注释符
--、#、/*
一条典型的SQL注入探测请求可能长这样:
GET /news.php?id=1%20union%20select%201,2,3,4--+ HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0用Wireshark看的时候,最直观的就是http.request.uri里面出现大量URL编码后的特殊字符。建议先输入:
http.request.uri contains "union"快速定位,然后Follow TCP Stream看服务器端的响应。如果响应里出现数据库错误提示,比如“You have an error in your SQL syntax”,基本可以确认注入点存在。
如果攻击者用了sqlmap这类自动化工具,流量里还会有另一个特征:UA头中的sqlmap/1.6.8(版本号会变)。喜欢指定UA的朋友可以优先锁这个特征。
4.2 Web目录扫描与爆破流量特征
目录扫描和账号爆破是流量上最容易识别的攻击类型,因为它们共同的特点是“大量重复请求”。
目录扫描的特征:
- 短时间内产生成百上千个GET请求。
- URL路径各种各样,都是猜测的路径,比如
/backup.zip、/.git/config、/phpmyadmin、/wp-content。 - 大量请求会返回404,但扫描器为了确认,仍然继续发送。
- UA常为
nuclei、dirsearch、gobuster、feroxbuster,或者完全是随机UA。
我一般用这条过滤器把扫描流量筛出来:
http.request.uri contains "." and http.response.code == 404统计一下404的占比,再配合包间隔时间,基本能快速判断有没有扫描行为。
账号爆破的特征稍有不同:
- 大量POST请求集中在同一个路径上,比如
/login.php、/user/login、/wp-login.php。 - 请求体里都是
username=xxx&password=yyy这种字段。 - 响应状态码会有规律地变化,比如未成功时返回200并带错误提示,成功时才302跳转。
- UA固定为某个脚本库,比如
python-requests/2.31.0。
筛选表达式:
http.request.method == "POST" and http.request.uri contains "login"配合时间显示列,如果看到Post请求每隔几百毫秒稳定出现一次,而且持续了很长时间,就能得出结论:这是爆破。
4.3 Webshell连接流量的识别
Webshell流量比注入和扫描要隐蔽,因为工具(蚁剑、冰蝎、哥斯拉)通常会构造看起来像正常业务的HTTP请求。但既然走HTTP,就一定留下痕迹。
蚁剑的流量特征:
- 请求通常带
X-Requested-With: XMLHttpRequest头。 - 请求体是
eval类函数执行,常带base64编码内容。 - 响应内容是动态生成的随机字符串,和请求参数有关联。
冰蝎的流量特征:
- 默认使用AES加密,请求体和响应体看起来是一串无明显含义的字节,但数据包长度往往有固定规律。
- 不同版本的冰蝎UA不同,有的是Java内置UA,有的是自定义UA。
哥斯拉的流量特征:
- 请求体和响应体都用AES加密,请求里带有明显随机字节。
- 会携带特定的Cookie字段。
识别Webshell流量的通用思路是“看请求和响应的组合异常”。正常业务请求的参数名和参数值是有语义的,而Webshell流量往往参数名固定但值是一长串看不明白的编码。这种情况下,我会先用过滤器筛POST包:
http.request.method == "POST" and tcp.len > 500然后逐个Follow TCP Stream,看哪个请求体的结构明显和正常业务不一致。如果确认可疑,还可以File > Export HTTP Objects,把上传的脚本直接导出来做进一步分析。
4.4 利用User-Agent等元数据锁定扫描器
不要小看元数据,HTTP头里的User-Agent、Referer、Accept字段,在攻击识别里价值很高。
扫描器和脚本工具的UA是非常明显的:
sqlmap/1.6.8nuclei/v3.2.1python-requests/2.31.0Go-http-client/1.1Nikto/2.5.0Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)——这个不是真Googlebot,攻击者喜欢伪造成搜索引擎爬虫。
筛选UA的表达式:
http.user_agent contains "nuclei" http.user_agent contains "sqlmap" http.user_agent contains "python-requests"每条跑一遍,命中结果按IP聚一下,很快就能列出“哪些IP在用哪些工具扫我”。
需要提醒的是,UA可以被伪造。我一般把UA特征作为线索,不作为铁证,真正定论还是要看具体的请求payload和响应行为。
5. 实操中的常见问题与排查技巧
真正上手分析时会遇到一堆“为什么看不到”“为什么卡死”“为什么全是加密包”的问题。这里把我踩过的坑整理一遍,按问题类型列出来,下次遇到能少折腾半小时。
5.1 HTTPS流量看不到明文怎么办
这是问得最多的问题。现代网站基本都是HTTPS,Wireshark默认只能看到TLS加密后的流量,看不到HTTP明文。Steam上看到全是TLSv1.3、TLSv1.2,别慌,这是正常的。
有几种办法能解出明文,但都要满足前提条件:
本地浏览器测试解密:在本地环境里,设置环境变量
SSLKEYLOGFILE指向一个文件,然后用Chrome或Firefox访问目标站点。Wireshark里到Edit > Preferences > Protocols > TLS,把Pre-Master-Secret log filename指向同一个文件,重新抓包,就能看到解密后的HTTP明文。这个办法只能解密你自己的浏览器流量,适合测试环境。服务器端解密:如果pcap是在服务器上抓的,且服务器上配置了TLS会话密钥记录,可以导入会话密钥。但很多环境没有做这个配置,实际获取比较难。
放弃解密,分析元数据:如果你的pcap里没有密钥,那也仍然能分析。TLS握手阶段的ClientHello里有SNI字段,能看到客户端访问的是哪个域名;还可以看IP、端口、连接时长、传输字节数。虽然看不到具体内容,但能确定通信对象和数据规模,这在应急阶段往往已经能提供有价值线索。
5.2 pcap文件打不开或Wireshark卡死
pcap文件打不开,最常见的原因是Wireshark版本太老,不支持pcapng格式或新版协议解析。建议直接去官网下载最新稳定版(4.0以上),Windows下安装时勾选Npcap组件,这是抓包和解析的底层依赖。
还有一个我经常遇到的情况:打开的pcap文件很大,几十个GB,结果Wireshark直接卡死。解决思路不是升级电脑,而是“预处理”。
用tshark(Wireshark自带的命令行工具)先过滤再打开,比如只提取HTTP请求:
tshark -r big.pcap -Y "http.request" -w http_only.pcap生成的http_only.pcap体量会小很多,用Wireshark打开就流畅了。如果是想按IP切流量:
tshark -r big.pcap -Y "ip.addr == 192.168.1.105" -w suspect_ip.pcap抓包的时候也可以设置环形缓冲和文件大小限制,避免生成超大文件。在Capture Options里设置“Ring buffer with N files of M MB”就行。
5.3 Wireshark为什么只能看到520字节数据
有朋友问,为什么数据包详情里只显示了520字节,而实际抓到的包有2090字节。这个问题其实不是Wireshark的问题,而是抓包时的“截断”设置。
Wireshark抓包时默认会记录每个数据包的前面一部分字节,后面的数据不保存。这个长度叫snaplen(抓包长度)。如果抓包时设置成64或128字节,那就只能看到每个包的头部,看不到HTTP完整内容。
解决方法是:抓包时在Capture Options里把每个包的限制长度调大,或者直接取消勾选“Limit each packet to”选项。已经抓好的pcap,如果截断了,里面确实没有完整数据,这是补不回来的,只能重新抓。
所以我的习惯是,做流量分析目的的抓包,一律不限制单包长度,宁可文件大一点,也别丢了关键内容。
5.4 误报与漏报:如何区分正常爬虫与攻击扫描
流量分析里最费时间的其实是误报处理。搜索引擎爬虫、监控系统、运维脚本都可能产生大量HTTP请求,看起来很像扫描器。
我判断是正常爬虫还是攻击扫描,有几个参考维度:
- robots.txt:正常爬虫会先请求
/robots.txt,遵守其中的规则;攻击扫描器不会。 - 请求路径语义:正常爬虫请求的URL是真实存在的页面,攻击扫描器会请求大量不存在的路径,收获大量404。
- 规律性:正常业务用户请求间隔有随机性,扫描器请求间隔非常均匀——自动化工具就是用固定间隔发请求才能快。
- 行为组合:攻击者不会只扫不攻。扫描之后往往会跟着尝试登录、传payload。如果一份pcap里先出现大量404扫描,然后跟着出现大量POST注入尝试,基本可以定性为攻击。
建议建立一个“行为时间线”:用Wireshark的IO Graph功能,输入http.request过滤器,画一条请求速率曲线。正常业务的速率曲线是扁平的,攻击行为会出现明显尖峰或持续高位。这个图在给非技术同事汇报时也很有说服力。
6. 一点个人体会
做了这么多流量分析,最大的感受是:Wireshark本身并不难,难的是建立“异常感”。什么是正常流量,什么是攻击流量,这种判断力只能靠反复看包喂出来。
强烈建议新手找一个包含攻击流量的pcap文件,先不看我上面写的特征对照,自己用统计视图和过滤器走一遍,把可疑点标出来,再对照文章检查漏了哪些。我当年就是用几份攻击包反复练,才把Wireshark用成顺手的工具。
还有一个小技巧:分析结束后,把用过的有效过滤器表达式保存起来。Wireshark的过滤框旁边有个书签图标,可以收藏为“Filter Expression”。我自己攒了一套常用过滤集,从SQL注入到爆破到Webshell,下次碰到类似情况,直接点一下就切过去,省去每次重打一遍的时间。
流量分析这件事,本质上是在跟攻击者玩“找不同”。他把恶意行为藏在看似正常的HTTP请求里,我们要做的就是通过Wireshark把那些不正常的细节揪出来。掌握这套方法论之后,下次再拿到pcap,心里就有底了。