☰
CTF流量分析实战:用Wireshark定位SQL注入与提取木马密码
2026/10/17 9:24:30 网站建设 项目流程

CTF流量分析题,说难也难,说简单也简单。难的是很多人拿到一个几百MB的pcapng文件之后,第一反应是“这都什么跟什么”,密密麻麻的TCP包,完全不知道从哪看起;简单的是,这类题只要理顺了思路,本质上就是“找可疑点、跟流、还原内容”三个动作反复循环。这篇文章我聚焦两个最高频的考点:怎么用Wireshark快速定位攻击者注入的SQL语句,以及怎么从一堆收发包里把木马的登录密码翻出来。开始之前先说清楚,这里讨论的一切都是CTF竞赛以及授权环境下的取证与复盘,目的不是教人攻击,而是学着还原攻击者做过什么。

读完之后,至少你能回答这几个问题:注入点是哪个参数?密码是以什么形式传输的?攻击者的完整操作顺序是什么?不管你是刚开始打CTF的新人,还是想补一补流量取证技能的安全从业者,这套流程拿过去就能用。我尽量把每一步的命令、过滤条件、看一眼就能得出判断的技巧都写出来,这些都是我这几年做题攒下来的实用经验。

1. 场景还原与解题总览

1.1 流量分析题到底在考什么

先说一个很多人没意识到的事实:大多数流量分析题,出的不是“纯网络题”,本质是“用网络流量包装过的Web题/取证题”。出题人给一个pcap包,里面通常装着一次完整的模拟攻击过程,从扫描、尝试注入、下载木马,到连接木马、传输密码,可能还会带上点别的协议混淆视线。你的任务不是读懂每一个包,而是把这次攻击的故事线抽出来,回答最终的问题,比如攻击者IP、注入参数名、口令明文、工具类型。

所以说,做流量分析题,拼的不是你对TCP/IP协议栈理解得多深,而是“会不会用合适的关键字和过滤条件把一堆噪声剥掉”。Wireshark在这里的角色更像搜索引擎,你要做的不是一页页翻流量,而是精准检索。

1.2 我习惯用的三步法

我自己的解题流程一直没变过,三步:先看全貌,再找异常,最后深挖关键流。看全貌,就是打开文件后第一时间看Statistics菜单里的Endpoints和Conversations,确认哪些IP是主要通信双方、哪些协议出现最多、HTTP请求的路径分布长什么样。这一步花不了两分钟,能帮你快速排除一堆干扰流。

找异常,是基于全貌判断“谁不对劲”。比如某个IP持续访问同一个页面参数从1排到100,这是注入探测;比如某个路径很冷门但被请求了多次,这可能是木马路径;比如某个响应体明显比正常的大很多,这可能是被注入的报错回显。最后一步才是真正动手:对可疑流Follow TCP Stream,把请求和响应还原成一条清晰对话,然后从中提取注入语句、密码参数这些关键信息。

有朋友总问,这顺序能不能反着来?能,但代价是容易陷进去。我见过不少人在第一个可疑流里耗了半小时,最后发现那是干扰项。先把握整体,再定位可疑点,效率会高很多。

2. Wireshark关键配置:做题前的三分钟设置

2.1 把显示列调整成“对解题友好”的样子

Wireshark默认的列是No.、Time、Source、Destination、Protocol、Length、Info,这套配置抓包时够用,做流量分析题时就不太够看了。我拿到一个流量包之后,一般会先在Info这一列上做文章。比如右键列头进入Column Preferences,把Info替换成自定义字段,或者干脆新增几列常用的:Source Port、Destination Port,以及对于Web题特别关键的“HTTP请求URI”列。

怎么加呢?在Column Preferences里点Add,字段名填协议字段,比如填http.request.uri,列标题自己写“URI”,宽度调大一点。这样HTTP请求的路径就一列排开,哪个参数被反复访问一眼就能看出来。同理,你还可以加一列http.response.code,用来快速过滤所有响应码异常的请求。这三分钟设置能省下后面巨量的手动点击时间,我是强烈建议每次分析前都先配上。

2.2 必会的过滤语法速览

过滤条件不用贪多,真正做题时翻来覆去就那几个。我把最常用的列在下面,顺手写清楚每个的用途。

  • http.request:挑出所有HTTP请求包,做题从这起步。
  • http.response:挑出所有响应包,适合看状态码和响应长度。
  • http.request.method == "POST":只看POST请求,找表单提交和后门连接流量都靠它。
  • tcp.stream eq 0:锁定某一条TCP流,配合Follow功能做深度阅读。
  • ip.addr == 192.168.1.20:按IP过滤,看某个主机的全部通信,前提是先把攻击者IP找出来。
  • frame contains “关键字”:在原始数据帧里搜字符串,SQL注入关键字、密码字段名都能这么搜。
  • tcp.port == 21:看FTP流量,同理换成80、443、23就是对应协议的流量。

这些条件之间可以用and、or、括号随意组合,最常用到的组合是ip.addr == 某IP and http.request,一下子就能把“这个攻击者发了哪些HTTP请求”全筛出来,比纯按http.request过滤干净太多。另外注意大小写,frame contains "union"和frame contains "UNION"是两回事。

2.3 Follow流与导出对象的正确打开方式

过滤出可疑包之后,右键任意一条HTTP包,Follow TCP Stream,Wireshark会把整条流的请求和响应拼成一段原始数据,左边是客户端发的,右边是服务器回的,非常直观。弹窗里左上角可以切换显示方式,默认是ASCII,适合看明文;遇到乱码时切到Hex Dump,再配合原始数据的十六进制转储,很多隐藏内容就是这么被翻出来的。

另一个实用功能是File → Export Objects → HTTP,可以把流量里传输过的所有HTTP对象全部导出来,文件名、大小、类型列得很清楚。遇到从服务器下载后门的场景,直接把这个文件导出来做静态分析,比在流量里逐字节看高效得多。做题时我习惯先把所有对象导一次,十次里有八次能直接找到线索文件。

3. 快速定位SQL注入点:从过滤到跟流

3.1 先用特征关键字把可疑请求“捞”出来

SQL注入在流量里的表现,其实比其他攻击类型直白得多,因为注入语句最终会以明文形式出现在请求参数或者请求体里,除非攻击者做了很重的混淆,否则一定会留下关键字。最快的定位办法:在Wireshark的显示过滤器里输入frame contains "select",注意这里的大小写只匹配小写,如果攻击者用大写或者大小写混合,就再试frame contains "SELECT"。

要搜的可疑关键字绝对不止一个。我习惯一次性分几轮去搜:第一轮搜最常见的select、union、sleep,分别对应普通注入、union注入和时间盲注;第二轮搜updatexml、extractvalue、exp,这几个通常和报错注入强相关;第三轮搜单引号的URL编码%27,这个更通用,因为几乎每种注入都要先试探闭合方式。每次搜出来之后不要急着下结论,配合后面的步骤逐个确认。

实测下来,用%27做初筛的效果经常比直接搜select还要好,因为很多简单的注入探测请求里只会带一个单引号,但并不会真的拼出select字样。不过要注意,%27这个串在正常业务中也可能出现(比如搜索关键词里本身有单引号),所以要结合上下文确认,看它后面有没有跟着SQL关键字或报错回显。

3.2 从统计面板看注入探测的“节奏”

关键词过滤适合精准打击,但面对一个完全不熟悉的题目时,我习惯先看Statistics → HTTP → Requests,这个页面按路径统计了所有HTTP请求的次数和方法。如果某个路径的请求次数异常多,而且都是GET方法,那基本可以判断攻击者在爆破参数或者跑注入字典。

举个真实场景:攻击者对/news.php?id=1发起请求,请求次数直线上升,id从1变到2、3一直到几十,中间夹杂着?id=1%27、?id=1 and 1=1这类变体,这就是教科书式的注入探测节奏。此时你就可以锁定这个路径和参数,进去深挖。统计面板还有一个好处:能给出各个请求的计数,很多时候一眼就能看到“哪个文件被重点照顾”,直接省掉盲翻流程。

3.3 三种常见注入类型的流量特征

定位到可疑请求后,要判断它属于哪种注入,因为最终答案里注入类型是常考的考点。报错注入最好认:请求里携带updatexml、extractvalue这类会引发数据库报错的函数,响应包里出现XPath syntax error、Incorrect value之类字样。Follow流看完整个来回,答案几乎就写在报文里了。

布尔盲注则需要观察响应差异。攻击者通常会用and 1=1和and 1=2交替测试,正常响应时页面长度和内容不变,错误条件时响应内容为空或长度骤减。做法是过滤http.response,加一列显示Content-Length,把同一路径、相邻请求的响应体长度排在一起对比,变化规律立刻现形。

时间盲注是这三种里面最费眼的,因为它不体现在内容上,体现在时序上。请求里通常有sleep(3)、benchmark(10000000,md5(1))这类字眼,而且对应请求和下一次请求之间的时间间隔明显拉长。判断方法很简单:把Time列的格式改成显示增量delta时间,然后看可疑请求前后有没有远超正常值的间隔。也可以在过滤条件里加tcp.time_delta > 2来做快速筛选,只要攻击者用了sleep,这些大间隔的包基本跑不掉。

3.4 注入点定位实战演示

来一段虚构但很常见的标准演示:题目给了一个抓包文件,已知攻击者IP是192.168.1.20,web服务IP是192.168.1.10。我先输入ip.addr==192.168.1.20 and http.request,把攻击者发的HTTP请求全捞出来,这时看到大量指向/news.php?id=xxx的请求。接着我搜frame contains "%27",果然在某个请求里看到/news.php?id=1'。

别急着走,右键这条请求,Follow TCP Stream,完整看一遍:攻击者先发了?id=1'试探,响应里出现了SQL语法错误,然后发?id=1' and '1'='1,页面正常返回;再发?id=1' and '1'='2,页面内容变化。到这一步,结合统计面板里的请求节奏,我就能确定这是一个基于id参数的布尔注入点。最终题目的答案悬着啥问啥:注入参数是id,注入点是news.php查询的id字段,类型是布尔盲注。整个过程可能不到五分钟。

4. 密码提取:木马密码藏在哪些地方

4.1 先画一张“密码藏身地图”

题目问木马密码或者登录密码时,很多人第一反应是搜password这个字符串。方向没错,但不能只靠这一招,因为密码可能出现的位置远不止一个。我按出现频率排一下:HTTP POST表单的某个字段、URL参数里的key=、Authorization头的Basic认证、Cookie或者Set-Cookie头、Webshell连接参数、FTP/Telnet这类明文协议命令。

说个经验:看到“木马密码”四个字,先别急着找明文密码,先确认这台机器是被Webshell控了还是被远控木马控了。如果是Webshell,密码大概率藏在连接请求里的某个参数值;如果是远控木马,密码可能在握手阶段、配置下发阶段或者登录认证阶段,往往还带着加密混淆。搞清楚了这两类场景,再去流量里找对应特征,比盲目搜password高效很多。

4.2 HTTP POST表单:最常见也最容易被忽视

最经典的场景:受害者或者攻击者向服务器提交登录表单,HTTP请求体里写着username=xxx&password=yyy。想快速定位,先在过滤条件里输入http.request.method == "POST",然后在结果里看Content-Type。只有当Content-Type是application/x-www-form-urlencoded或multipart/form-data时,请求体里才是表单字段,纯文本的body大概率是接口JSON,密码字段的名称可能是password、passwd、pwd、user_password等各种变体。

这里有个很坑的坑:请求体跨了多个TCP分段。你单独点开某个POST包看的时候,Payload可能只有前半截,字段都不全,怎么看都找不到密码。正确做法是Follow TCP Stream看完整流程,或者用tshark按字段提取,我后面会讲。另外表单传输的密码一般会做URL编码,比如密码A@b会被编码成A%40b。看到%XX就不认识,这是新手最常卡住的地方。

4.3 Base64与Basic Auth:几个解码套路

浏览器访问带认证的目录时会自动带一个Authorization头,格式是Basic base64(user:password)。流量里直接过滤http.authorization就能把所有这类请求找出来,密码就在里面躺着,只是被Base64包了一层。解码方法很无脑,复制到终端里echo “value” | base64 -d,或者丢进网页解码工具都行。

要注意的是,Base64只是编码不是加密,所以做题时见到以=结尾的短字符串,第一反应就去解Base64,能解决不少问题。同理,流量里经常出现两次编码的情况,比如先Base64再URL编码,解的时候要反序:先URL decode,再Base64 decode,顺序反了大概率解出一堆乱码。我自己踩过这个坑,当时密码明明就在眼前,因为解码顺序错了,差点以为自己找错地方。

4.4 Webshell连接流量和后门口令

这类流量通常长这样:攻击者向/shell.php发送POST请求,请求体里带着一串参数,其中某个参数值就是连接密码,后面才是执行的命令。识别Webshell流量有几个特征:请求路径一般不像正常业务路径那么规整,可能是upload、shell、x.php之类;请求体里经常出现eval、assert、system、$_POST这些字的变形写法;响应体则可能直接回显命令执行结果。

遇到这种情况,我的做法是先看响应长度。正常业务的POST响应基本稳定,但如果某个POST请求的响应长度剧烈变化,那大概率就是命令执行类后门:攻击者执行dir时响应短、执行type时响应长。锁定之后Follow流,把请求里的参数名和值一对一遍就出来了。现在不少Webshell管理工具会在客户端做AES加密,流量里可能看不到明文口令,这种情况题目一般会在其他包里给出密钥或初始化向量,留意流量里有没有日志、配置文件之类的附加线索,这个要多做几题才能形成直觉。

4.5 FTP、Telnet这些明文协议的白给密码

老牌明文协议在CTF流量题里几乎等于送分题。FTP的登录过程就是USER一个包、PASS一个包,过滤ftp.request.command == "PASS",中间那句就是密码,前后文里还能顺手读到用户名。Telnet同理,过滤tcp contains "Password"或者直接看telnet.data字段,密码大多直接出现在ASCII报文里,连解码都省了。

还有POP3、IMAP、SMTP这类邮件协议,里面USER和PASS命令同样直白到惊人。如果题目的背景是钓鱼或内网渗透,这些协议往往是提分大头。我个人的建议是,看到题目包里端口统计有21、23、25、110这些老端口,别嫌它们土,先按对应协议过滤一遍,经常能在两分钟内白捡一个密码字段。

5. 完整解题流程演示:从打开包到拿到答案

为了把前面这些零散技巧串起来,我模拟一道实战风格的题目:某web服务器(192.168.1.10)被攻击者扫描、注入、挂马,流量包里还掉落了木马密码。下面是完整流程,每一步都给出过滤表达式和判断依据。

第一步,打开pcap后直接看Statistics → Endpoints,一眼就能看到192.168.1.20和192.168.1.10之间的流量占了绝大多数,包数也显著高于其他地址对。于是我把攻击者锁定为192.168.1.20,其他地址暂时丢到一边,输入ip.addr==192.168.1.20 and http.request,看到攻击者的请求总体路径分布。

第二步,打开Statistics → HTTP → Requests,发现两个路径不对劲:/news.php出现了60多次,请求参数从id=1一直扫到id=60多;/login.php出现了20多次,且集中在后面几分钟。前者像注入扫描,后者像爆破登录,两个都是疑点。

第三步,针对/news.php,我用frame contains "%27"过滤,命中了好几条请求。Follow其中一条TCP Stream,完整看到单引号闭合、and 1=1、and 1=2的交替过程,响应长度也出现规律变化。这里我判断:注入点在id参数,注入类型为布尔盲注。题目答案里这一类往往是送分题。

第四步,针对/login.php,过滤http.request.method == "POST" and ip.addr==192.168.1.20。发现每次POST都提交username、password两个字段。我用Follow TCP Stream观察到其中一次响应返回成功,密码明文就写在请求体里,URL解码之后得到真正的密码值。这个密码,往往就是题目问的木马密码。

第五步,回到全局视图,用File → Export Objects → HTTP导出了一堆对象,其中有个奇怪的shell.php,文件很小但被请求了多次。静态打开一看,里面就一行PHP代码,参数名是pass,这不就是Webshell口令。再回到流量里验证:POST到shell.php的请求体里,pass字段的值正好等于第四步解出来的密码。到这里,整个攻击故事线就完整了:扫描发现注入点、从注入点下载shell、再用密码连接shell。题目再怎么问,答案都在手上。

6. 常见问题与排查技巧实录

6.1 过滤没结果,可能是这三个原因

搜SQL关键字搜不到,最常见的原因是大小写。攻击者写了UNION,你搜union,当然搜不到。更稳的方法是搜URL编码变体%27,因为这个跟大小写无关,只要存在注入探测基本逃不掉。第二个原因是关键字出现在响应里但你过滤器只看请求,那就在条件里加http.response或者干脆用frame contains对整个帧搜。第三个原因是Wireshark的显示过滤器默认不包含原始字段,不过frame contains搜的是帧数据,基本能覆盖所有层,如果链路层数据被分段还是搜不完整,那就需要重组后再看。

6.2 密码拿到了但是乱码,可能解了两层码

前面已经提过,URL编码和Base64可能叠加出现。看到%开头,先URL decode;看到等号结尾或者A-Za-z0-9+/密集排列,先Base64 decode。多层编码就按实际出现顺序逆向解。还有一类情况是UTF-8和UTF-16的编码差异,在十六进制转储里如果能看到00 41 00 42这种补零的ASCII,说明是宽字符,转换编码之后才是明文,别直接放弃。

6.3 题目流量是HTTPS,怎么破

如果过滤http.request只有零星几条,其余都是TLS的密文,别慌。CTF题里遇到HTTPS,十有八九会在文件里附带解密密钥或者keylog文件,打开Wireshark的Edit → Preferences → Protocols → TLS,在(Pre)-Master-Secret log filename里选中keylog文件,刷新一下就能看到解密后的HTTP明文流。

如果题意里没给keylog,那就要看证书私钥是不是就藏在其他对象里,可以从Export Objects里找找.pem、.key文件,或者从题目描述里找提示。再不行,就退回到观察TLS元数据,比如ClientHello里的SNI、证书的CN字段,虽然拿不到明文密码,但有时题目的答案问的是其他字段,比如攻击者访问了哪个域名。

6.4 文件太大、过滤太卡怎么办

几百MB甚至上GB的流量包,在Wireshark图形界面里操作真的会卡到怀疑人生。我的解决办法是先用显示过滤器把范围缩小,比如ip.addr==攻击者IP and http,这一步能让Wireshark少渲染大量无关包。如果还是卡,就直接命令行用tshark先做粗提取,比如tshark -r file.pcapng -Y "http.request" -T fields -e http.request.uri > uri.txt,把URI列表导出来扫一遍,找到可疑目标再回到图形界面定点分析。

另外,tshark还可以提取请求体:tshark -r file.pcapng -Y "http.request.method==POST" -T fields -e http.file_data,这个字段会把POST载荷以十六进制形式打印出来,配合xxd转回文本,经常能批量看到一票密码字段。这个技巧在处理“一整个文件都是扫描流量”的题目时尤其好用。

6.5 多流交错,看不过来怎么办

Follow TCP Stream默认只跟单条流,但实际场景里攻击者可能同时开了很多条连接,导致你把某条流看到一半,另一条流又横插进来。这时候建议先用Statistics → Conversations找到主连接,确认TCP流的序号范围,再用tcp.stream eq N逐个跟。有经验之后你会发现,真正需要逐字看的流通常只有那么两三条,其余大部分数据包在统计和初筛环节已经被排除了。

7. 工具链与效率扩展:tshark和脚本能帮你省一半时间

图形界面做深度分析,命令行做批量提取,这是我处理流量包的基本原则。tshark就是Wireshark的命令行版,最大的优势是能一口气处理多个文件,并且输出格式完全由你控制。提取所有HTTP请求的目标路径可以用一行:

tshark -r traffic.pcapng -Y "http.request" -T fields -e http.host -e http.request.uri

提取所有POST请求体并转成文本可以用:

tshark -r traffic.pcapng -Y "http.request.method == POST" -T fields -e http.file_data | xxd -r -p

如果题目文件很多,你还能写一个小循环批量跑,把每个文件的URI列表都拉出来对比,省去手动一个个打开的时间。

Python这边,可以试试基于pyshark写简单脚本,批量统计每个流的大小、关键字命中次数,这在面对超大型pcap的时候比图形界面稳太多。但我建议先别一上来就上脚本,因为CTF里大多数题目的流量包并没有大到需要写代码,图形界面加tshark组合已经能覆盖90%的场景,脚本更多的是处理重复劳动和自动提取答案,属于进阶玩法。

8. 最后再分享几个实际做题的心得

说了这么多,最后还是想从实操角度补几句。第一,拿到流量包先别急着点开第一个可疑包,先花三分钟做统计预览,这个习惯能帮你避开百分之五十以上的干扰流。第二,养成保存显示过滤器的习惯,把http.request、ip.addr、frame contains这些常用条件存成按钮,下次直接点,省下的都是真实时间。第三,遇到不会解的编码,先别查工具,手算一遍URL解码感受一下规律,时间长了你对“编码到底套了几层”会有很强的直觉。

我做流量分析题最大的体会是:这类题考验的不是记忆力,而是耐心和顺序感。攻击者的行为一定留下了痕迹,问题是你的过滤条件能不能像筛选漏斗一样,把几万个包一步步缩减到十几条关键流。把这个流程跑顺了,SQL注入点和木马密码这种问题,真的只是时间问题。祝你能从第一个包开始,一步步把攻击者走过的路完整还原出来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询