从流量包到攻击链:实战拆解HTTP协议分析与JWT安全盲区
最近在复盘一些网络安全竞赛的流量分析题时,我发现很多朋友对Wireshark这类工具的理解,还停留在“抓个包看看”的层面。面对一个动辄几百兆、包含成千上万个数据包的流量文件,新手往往感到无从下手,而有一定经验的分析者,也可能因为缺乏系统的方法论,在关键的攻击痕迹面前擦肩而过。流量分析,尤其是针对Web应用的HTTP流量分析,远不止是过滤协议那么简单。它更像是在数字世界的案发现场进行刑侦勘查,你需要从海量的、看似无序的网络通信中,识别出攻击者的意图、手法和路径,最终还原出完整的攻击故事线。
这篇文章,我将以一个实战者的视角,带你深入HTTP流量分析的腹地。我们不空谈理论,而是聚焦于如何像侦探一样思考,利用Wireshark这个“显微镜”,结合真实的攻击场景(例如比赛中常见的JWT攻击、Webshell上传等),一步步拆解攻击链。无论你是刚入门的安全爱好者,还是希望提升实战排查能力的运维、开发人员,都能从中获得一套可立即上手的方法论和思考框架。我们的目标很明确:让你下次再面对一个陌生的流量包时,能清晰地知道从哪里开始,如何推进,以及如何解读每一个可疑的信号。
1. 构建分析思维:从“盲人摸象”到“全景还原”
在打开任何一个.pcap或.pcapng文件之前,最重要的一步是建立正确的分析心态。很多人一上来就急着用“http”过滤,这其实是一种“战术勤奋,战略懒惰”的表现。你可能会迅速找到一些HTTP请求,但却完全丢失了攻击发生前的侦察阶段、发生后的横向移动等关键上下文。
1.1 初窥全貌:统计与对话还原
首先,我们应该对流量文件有一个宏观的认识。Wireshark的“统计”(Statistics)菜单是你的第一站。
- 协议分层统计:查看哪些协议占据了主导。如果HTTP/HTTPS流量占比异常高,那很可能是一个Web攻击的焦点。但也要注意,攻击者可能利用DNS、ICMP甚至正常业务协议(如SMB、RDP)进行数据外传。
- 端点与会话:查看哪些IP地址之间的通信最频繁。寻找内部地址与异常外部地址(如陌生的公网IP)的大量会话,这可能是C2(命令与控制)通信的标志。
- 流量图:利用I/O图表或Conversation图,可视化地查看流量随时间的变化。一个突然的流量峰值,可能对应着漏洞利用或数据窃取的行为。
完成宏观扫描后,我习惯先快速浏览整个数据包列表,不施加任何过滤器。看看TCP三次握手是否完整?有没有大量的TCP重传或RST包(可能意味着扫描或网络不稳定)?有没有长度异常的数据包?
提示:在分析比赛或应急响应提供的流量包时,通常攻击已经发生。我们的目标是“事后取证”,因此要特别关注状态码异常(如大量404、403、500)的HTTP响应,以及POST请求体巨大或响应体异常的TCP流。
1.2 确立分析锚点:从异常到假设
宏观分析会给你一些模糊的线索,比如“192.168.1.100和某个外部IP通信很频繁”。接下来,我们需要找到具体的“锚点”来深入。锚点通常是第一个明显的异常行为。它可能是:
- 一个明显的攻击路径:如访问
/admin/upload.php的POST请求。 - 一个可疑的用户代理:如使用
sqlmap/1.6或其它扫描器标识的UA。 - 一个异常的参数或路径:如包含
../(路径遍历)、<script>(XSS)或union select(SQL注入)片段的请求。 - 一个特殊的协议或端口:如对内网3389(RDP)、22(SSH)端口的连接尝试。
一旦找到锚点,就以此为中心,追踪TCP流或HTTP流,查看完整的请求与响应对话。这是理解单次攻击行为的关键。
2. 深度解剖HTTP攻击流:以JWT篡改为例
Web攻击是流量分析中最常见的场景。我们以一个具体的、在CTF和实战中都频繁出现的攻击手法——JWT(JSON Web Token)攻击——作为案例,看看如何层层深入。
2.1 识别JWT流量与结构解析
在HTTP流量中,JWT通常出现在 Authorization: Bearer 头或 Cookie 字段中。它的格式非常醒目:由点号分隔的三部分 xxxxx.yyyyy.zzzzz。
GET /api/userInfo HTTP/1.1
Host: target.com
Cookie: session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
在Wireshark中,你可以直接过滤 http.cookie contains "eyJ" (JWT通常以Base64编码的“eyJ”开头,对应JSON的{")来快速定位。
找到JWT后,第一步是解码,理解其声明内容。JWT的三部分分别是:
- Header:描述令牌类型和签名算法,如
{"alg": "HS256", "typ": "JWT"}。 - Payload:包含声明(Claims),如用户ID、角色、过期时间等,例如
{"sub": "123", "username": "admin", "exp": 1516239022}。 - Signature:对前两部分的签名,用于验证令牌完整性。
你可以使用在线工具、浏览器插件或命令行工具(如 jq 配合 base64)进行解码。在Wireshark中,虽然不能直接解码,但你可以将令牌复制出来处理。
# 示例:解码JWT的Payload部分(第二段)
echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwidXNlcm5hbWUiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0" | base64 -d | jq .
2.2 攻击手法研判:从流量中识别篡改意图
攻击者对JWT的利用,核心围绕绕过签名验证和提升权限。在流量中,你可以通过对比一系列请求中的JWT变化来发现攻击行为。以下是一些常见手法及在流量中的特征:
| 攻击手法 | 原理简述 | 流量分析中的关键线索 |
|---|---|---|
| 签名算法篡改 | 将Header中的alg改为none,试图让服务器跳过签名验证。 | JWT的Header部分明显变为 {"alg": "none", ...}。需注意,现代库已基本免疫此攻击。 |
| 密钥混淆攻击 | 当服务器错误地使用非对称算法(如RS256)的公钥来验证对称算法(如HS256)的签名时,攻击者可以用公钥作为密钥伪造签名。 | 需要结合源代码审计判断,流量本身JWT格式正常,但签名密钥来源可疑。 |
| 弱密钥爆破 | 对HS256等对称签名算法,尝试爆破弱密钥。 | 流量中会出现大量、连续的、Payload相似但Signature不同的JWT请求,服务器返回的HTTP状态码在401(失败)和200(成功)间变化。这是非常明显的爆破行为。 |
| 信息泄露与篡改 | 直接修改Payload中的声明(如将"role":"user"改为"role":"admin"),但使用原签名(无效)。或者,从服务器响应、错误信息中泄露敏感信息。 | 1. 无效签名请求:服务器返回4xx错误(如401/403),但攻击者持续尝试。 2. 信息泄露:服务器响应体或Header中可能包含解码后的JWT信息、密钥提示或堆栈跟踪。 |
在实战分析时,你需要像看故事一样,按时间顺序追踪一个会话(TCP Stream)中JWT的变化。例如:
- 第一个请求:JWT的Payload是
{"user":"guest"},返回200,但数据受限。 - 攻击者随后发送数十个请求,JWT的Signature不断变化,Payload可能尝试
{"user":"admin"},服务器均返回403。 - 突然,某个请求的JWT的Signature段变了,服务器返回200并给出管理员数据。
这个转折点,就是攻击成功的时刻。你需要仔细检查这个“成功”的JWT与其之前失败的有何不同。是不是Payload里多了一个
"MapClaims"字段?或者用户ID(id)发生了变化?这往往就是flag或解题的关键。
注意:JWT各部分虽然是Base64编码,但未经加密。任何人都可以解码查看其内容。安全性的核心在于签名。任何对Header或Payload的修改,如果不重新用正确的密钥签名,验证都会失败。
3. 追踪攻击者足迹:Webshell上传与后续行为
攻击者获取权限(如通过JWT提权)后,下一步往往是建立持久化通道。上传Webshell是最常见的手段。在流量中分析Webshell上传,考验的是你对数据编码和协议交互的理解。
3.1 识别文件上传流量
Webshell上传通常通过HTTP POST请求完成,内容类型多为 multipart/form-data 或 application/x-www-form-urlencoded。在Wireshark中过滤 http.request.method == POST,然后重点关注:
- 请求路径:指向疑似上传接口的路径,如
/upload.php,/admin/upload,/filemanager/upload。 - 请求体内容:在追踪HTTP流时,你会看到文件内容和表单字段。攻击者为了绕过过滤,会对Webshell代码进行多次编码。
例如,你可能看到POST数据里有一长串像乱码的字符:
content=%252F2%252FwB%252BDQ%252BC%252F4H%252Fgv%252B...
这很可能是经过了URL编码(甚至双重URL编码)的Base64字符串。你需要做的,是像剥洋葱一样,一层层解码还原。
# 假设从流量中提取出content参数的值
encoded_content="%252F2%252FwB%252BDQ%252BC%252F4H%252Fgv%252B..."
# 第一层:URL解码(可能多次)
echo $encoded_content | sed 's/%25/%/g' | xxd -r -p # 一种处理方式,或使用python的urllib.parse.unquote
# 更实际的做法是使用Python
python3 -c "import urllib.parse; print(urllib.parse.unquote('$encoded_content'))"
# 输出可能是Base64字符串:L2YvYkEvRFovQy80SC9ncis...
# 第二层:Base64解码
echo "L2YvYkEvRFovQy80SC9ncis..." | base64 -d
# 输出可能就是Webshell的源代码,如 `<?php @eval($_POST['cmd']);?>`
3.2 串联后续攻击链
上传Webshell不是终点,而是攻击者新的起点。接下来,你需要以Webshell的访问点为线索,追踪攻击者的后续操作。
- 定位Webshell访问:寻找对上传文件路径(如
/uploads/shell.php)的POST请求。这些请求的Body中通常会包含攻击命令,例如cmd=whoami或c=system('ls -la');。 - 分析命令执行与回传:
- 直接回显:命令输出可能直接放在HTTP响应体中。这比较容易发现。
- 外传通道:攻击者可能将执行结果通过Websocket、DNS隧道、或向外部服务器发起HTTP GET/POST请求的方式外传。你需要关注内部服务器主动发起的、指向异常外部域名的连接。
- 发现横向移动与持久化:在流量包的后半部分,攻击者可能尝试扫描内网、爆破其他服务、或部署后门。例如:
- 向
/etc/pam.d/common-auth等系统关键配置文件写入内容(如添加恶意so库),这是经典的Linux持久化手法。 - 传输并执行二级载荷,如远控木马(
looter.so这类名称就很可疑)。 - 建立代理隧道(如SOCKS5),流量中可能出现相关协议握手包。
- 向
分析的关键在于时间线和因果关系。Wireshark的“时间”列是你的好朋友。将攻击行为按时间排序:JWT攻击成功 -> 访问管理员接口 -> 上传Webshell -> 通过Webshell执行命令 -> 下载内网扫描工具 -> 发起内网爆破……一个清晰的攻击链就浮现出来了。
4. 高阶技巧与自动化辅助
当流量包非常庞大时,完全依赖手动分析效率低下。掌握一些高阶技巧和自动化脚本,能让你事半功倍。
4.1 Wireshark高级过滤与着色规则
除了基本的协议过滤,这些过滤表达式非常实用:
http contains "union select":查找可能的SQL注入载荷。http.request.uri contains ".php" && http.request.method == "POST":查找所有POST到php文件的请求。tcp.port == 8888:关注攻击者可能使用的非标准端口。ip.src == 192.168.1.100 and http:只看来自某个可疑IP的HTTP流量。
你可以为特定的攻击模式设置着色规则。例如,将所有包含 eval( 或 base64_decode( 的HTTP数据包标为红色背景。这样,恶意流量在数据包列表中就“一目了然”。
4.2 使用tshark进行命令行提取
对于日志分析或批量提取数据,Wireshark的命令行版本 tshark 是神器。比如,从流量包中提取所有HTTP请求的URL和Cookie:
tshark -r attack.pcap -Y http -T fields -e http.request.full_uri -e http.cookie > http_requests.txt
或者,提取所有包含“flag”字符串的数据包内容:
tshark -r attack.pcap -Y 'frame contains "flag"' -V
4.3 编写Python脚本进行深度挖掘
对于复杂的、需要逻辑判断的分析,Python结合pyshark或scapy库非常强大。例如,自动分析JWT爆破行为:
import pyshark
from collections import defaultdict
def detect_jwt_bruteforce(pcap_file, target_ip):
cap = pyshark.FileCapture(pcap_file, display_filter=f'http and ip.dst == {target_ip}')
jwt_attempts = defaultdict(list) # key: payload, value: list of packets
for pkt in cap:
try:
cookie = pkt.http.cookie
if 'eyJ' in cookie: # 简单判断JWT
# 这里需要解析JWT,提取payload部分作为key
# 简化示例:以整个cookie作为key
jwt_attempts[cookie].append(pkt)
except AttributeError:
pass
# 找出被尝试次数最多的JWT Payload(可能是爆破目标)
for jwt, packets in jwt_attempts.items():
if len(packets) > 10: # 设定一个阈值
print(f"疑似JWT爆破: {jwt[:50]}... 尝试次数: {len(packets)}")
print(f"首次尝试: {packets[0].sniff_time}, 末次尝试: {packets[-1].sniff_time}")
cap.close()
# 使用示例
detect_jwt_bruteforce('goroot.pcap', '192.168.1.10')
这个脚本的思路是:统计发往目标服务器的、携带不同JWT的HTTP请求数量。如果同一个请求路径下,出现了大量Payload相似但Signature不同的JWT,那很可能就是爆破行为。
流量分析的世界没有银弹,最大的工具是你的好奇心和逻辑思维。每一次分析都是一次独特的探险。我自己的习惯是,在完成初步分析后,会画一张简单的攻击时序图,把关键IP、关键请求、状态转折点标出来。这张图不仅能帮我理清思路,在写报告或与团队交流时也无比清晰。下次当你面对一个棘手的流量包时,不妨深吸一口气,告诉自己:这不是一堆杂乱的数据,这是一个等待被讲述的故事。而你,就是那个解谜的人。
3527



被折叠的 条评论
为什么被折叠?



