CTF实战:解密哥斯拉4.0加密Webshell流量全解析
1. 项目概述一次从CTF到实战的流量解密之旅最近在复盘一道CTF题目时遇到了一个典型的加密Webshell流量分析场景目标是要从一堆看似杂乱无章的TCP流里找到攻击者留下的“Flag”。这道题的核心是解密一个由“哥斯拉”4.0客户端生成的加密通信流量。对于很多刚接触安全分析或者CTF流量分析的朋友来说看到Wireshark里那些被加密的HTTP POST数据包常常会感到无从下手。其实只要掌握了正确的密钥和加密方式我们完全可以用Wireshark内置的功能像剥洋葱一样一层层还原出攻击者的原始操作指令。这不仅仅是解一道题更是一次深入理解加密Webshell通信原理、掌握实战流量解密技巧的绝佳机会。无论你是CTF爱好者、安全运维人员还是对Webshell检测技术感兴趣的研究者通过这次手把手的演练你都能获得一套可直接复用于真实网络取证分析的方法论。2. 核心原理哥斯拉4.0的流量加密机制拆解要解密流量首先得知道它是怎么被加密的。哥斯拉Godzilla作为一款经典的Webshell管理工具其4.0版本在通信安全上做了显著加强其加密机制是解密成功与否的关键。2.1 动态密钥与加密流程哥斯拉4.0默认采用AES加密算法但其核心秘密在于“动态密钥”。它并非使用一个硬编码的密码而是由客户端和服务器端即Webshell通过一个种子key和一段固定的盐salt利用MD5哈希动态生成每次会话的加密密钥和初始向量IV。具体流程如下密钥协商客户端在发起第一个请求时会携带一个pass参数这个pass值就是密钥种子。Webshell端收到后会使用同样的算法在本地生成相同的密钥。密钥派生密钥和IV的生成公式通常为KEY md5(pass salt)[:16]IV md5(pass salt)[16:]。这里的salt是一个在客户端和Webshell脚本中预先定义好的固定字符串。通过MD5生成32位哈希值前16位作为AES-128的密钥后16位作为CBC模式的IV。数据封装需要传输的原始指令如whoami或命令执行结果会先经过一次base64编码然后再用上面生成的KEY和IV进行AES-128-CBC加密。加密后的二进制数据通常会再次进行base64编码或直接以二进制形式放入HTTP POST的Body中传输。这种设计使得即使你抓到了流量包如果不知道pass和salt也无法直接解密。在CTF题目中pass和salt往往隐藏在Webshell的源码、客户端的配置文件或者通过其他隐写手段给出。2.2 流量特征识别尽管内容加密但哥斯拉的流量仍有一些外部特征可循帮助我们快速定位HTTP POST请求几乎所有操作都通过POST请求完成。URL路径与参数可能包含特定的路径如/admin.php、/index.php并带有pass等参数。Cookie哥斯拉可能会设置一个特定的Cookie如PHPSESSID的值可能有固定模式。User-Agent有时会使用默认或特征明显的User-Agent字符串。在Wireshark中我们可以使用过滤表达式例如http.request.method POST http contains “pass”来快速缩小目标数据包的范围。3. 实战准备Wireshark环境与关键数据提取工欲善其事必先利其器。在开始解密前我们需要确保Wireshark配置得当并精准定位到需要解密的核心流量。3.1 Wireshark配置与插件检查首先确保你使用的是较新版本的Wireshark3.6以上版本功能更完善。对于解密操作一般无需额外插件但我们需要熟悉两个关键功能的位置“编辑” - “首选项” - “协议”这里是配置各种协议解密规则的地方我们稍后会用到。“统计” - “会话”这是分析TCP/UDP流还原完整通信过程的神器。一个常被忽略但极其有用的设置是调整TCP重组选项在“首选项”-“协议”-“TCP”中确保“Allow subdissector to reassemble TCP streams”被勾选这能让HTTP等应用层协议更完整地解析数据流。3.2 定位与提取加密载荷假设我们已经通过过滤找到了疑似哥斯拉流量的POST请求包。跟随TCP流右键点击该数据包选择“追踪流” - “TCP流”。这时会弹出一个新窗口以纯文本形式展示该TCP连接的所有通信数据。通常你会看到客户端发送的一坨base64编码的密文或乱码以及服务器返回的同样被加密的响应。保存原始数据在“追踪TCP流”的窗口底部将显示格式改为“原始数据”。然后复制整个显示的内容包括客户端发送和服务器返回的数据保存到一个文本文件中例如raw_stream.txt。这里有一个关键点我们通常需要分别解密请求和响应。因此更稳妥的做法是在窗口左上角选择“仅显示发送的数据”或“仅显示接收的数据”分别复制客户端发送的密文和服务器返回的密文保存为两个文件如client_raw.bin和server_raw.bin。注意如果数据在TCP流窗口里显示为base64字符串则需要先将其解码为二进制文件。可以使用Python或在线工具进行转换。确定加密模式与参数这是最关键的一步。你需要从题目描述、Webshell源码或客户端配置中明确加密算法通常是AES。密钥KEY16字节的字符串。初始向量IV16字节的字符串。加密模式通常是CBC。填充方式通常是PKCS7。数据编码加密后是base64还是hex或直接是二进制。注意在“追踪TCP流”窗口看到的数据可能已经经过了一次base64解码Wireshark自动做的。所以你复制出来的“原始数据”可能是解密前的二进制乱码也可能是base64字符串。务必结合数据包详情栏中HTTP协议层Line-based text data的内容进行对比判断。最可靠的方法是直接从数据包详情中找到HTTP-Hypertext Transfer Protocol- 展开[truncated]...或者直接查看底层的TCP段数据右键选择“复制” - “...as a Hex Stream”将其保存为十六进制文本再借助脚本转换为二进制文件。这能确保你拿到最原始的传输载荷。4. 核心操作在Wireshark中配置并执行解密拿到密钥和加密参数后我们有两种主要解密方式一是使用外部脚本解密提取出的数据二是直接在Wireshark中配置解密规则让Wireshark实时解密并解析流量后者更直观、高效。4.1 方法一使用Python脚本进行离线解密这是一种非常灵活且可控的方法。假设我们已经从流量中提取出了客户端发送的密文二进制文件client_encrypted.bin并且已知KEY:0123456789abcdef(16字节示例)IV:fedcba9876543210(16字节示例)算法: AES-128-CBC填充: PKCS7我们可以编写一个Python脚本进行解密from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 # 读取加密的二进制数据 with open(client_encrypted.bin, rb) as f: ciphertext f.read() # 定义密钥和IV key b0123456789abcdef # 替换为实际KEY iv bfedcba9876543210 # 替换为实际IV # 创建AES解密器 cipher AES.new(key, AES.MODE_CBC, iv) # 解密并去除填充 try: decrypted_padded cipher.decrypt(ciphertext) decrypted_data unpad(decrypted_padded, AES.block_size) # 哥斯拉通常会将原始指令先base64再加密所以解密后可能需要再次base64解码 original_command base64.b64decode(decrypted_data).decode(utf-8, errorsignore) print(解密后的原始指令或数据) print(original_command) except Exception as e: print(f解密失败: {e}) # 如果失败直接输出解密后的字节可能本身就是可读的 print(decrypted_padded.decode(utf-8, errorsignore))运行脚本后你很可能就能看到攻击者执行的系统命令如whoami、ipconfig或cat /flag等。4.2 方法二在Wireshark中配置SSL/TLS解密规则模拟Wireshark没有直接的“AES-CBC解密”协议选项但我们可以巧妙地利用其SSL/TLS解密功能来模拟这个过程。因为SSL/TLS在记录层也使用对称加密如AES-CBC我们可以将哥斯拉的通信“伪装”成SSL/TLS流量来解密。操作步骤如下生成SSL密钥日志文件Wireshark支持通过一个记录(Pre)-Master-Secret的日志文件来解密SSL/TLS流量。对于哥斯拉我们需要创建一个特定格式的文本文件例如godzilla_keys.log。但这里我们不是记录真正的TLS密钥而是“告诉”Wireshark一个固定的对称密钥。 实际上更直接的方法是使用Wireshark的“协议首选项”来配置一个静态的RSA私钥虽然不对但目的是触发解密流程。然而对于自定义的AES-CBC更通用的方法是使用udpdump格式的密钥文件。创建一个文本文件内容如下# Godzilla AES-128-CBC Static Key KEY 0123456789abcdef fedcba9876543210第一行是注释第二行格式为KEY 16字节Hex密钥 16字节Hex IV。将密钥和IV转换成十六进制字符串。例如如果KEY是字符串this_is_godzilla其Hex表示为746869735f69735f676f647a696c6c61。在Wireshark中配置打开Wireshark进入“编辑” - “首选项”。在左侧找到并展开“协议”。在协议列表中找到并点击“TLS”旧版本可能是SSL。在右侧的“TLS”配置页面中找到“(Pre)-Master-Secret log filename”选项。点击“浏览”选择你刚才创建的godzilla_keys.log文件。设置解密端口与协议关键步骤仍然在“TLS”首选项页面点击下方的“编辑...”按钮配置“RSA keys list”。我们需要添加一个条目但目的不是提供RSA密钥而是“欺骗”Wireshark尝试对特定端口的TCP流应用解密。可以任意指定一个IP、端口和协议如http并选择一个无关的PEM文件。这一步有时可以省略核心是上一步的密钥日志文件。更有效的方法由于哥斯拉流量是HTTP协议承载的Wireshark可能不会对其应用TLS解密。一个变通方案是在抓包或分析时修改数据包的解析方式。右键点击目标TCP数据包 - “解码为...” - 在“当前”列中将该TCP流或端口号的协议从“HTTP”临时改为“TLS”。这样Wireshark就会尝试用我们配置的密钥去解密这个端口的流量。查看解密结果配置完成后回到主界面重新加载或者直接查看数据包。如果配置成功原本显示为TCP或HTTP的应用数据部分可能会被解析为TLSv1.2 Application Data并且其下方会展开一个[Decrypted SSL data]的标签页里面就是解密后的明文HTTP请求你可以看到原始的POST参数和内容。如果没有自动解析可以尝试在数据包详情栏的TCP或SSL协议上右键选择“解密SSL数据...”手动选择密钥文件。实操心得方法二的成功率取决于Wireshark版本和具体流量特征有时会比较“玄学”。如果方法二不成功强烈推荐使用方法一脚本解密结合“追踪TCP流”这是最可靠、最直接的方式。将解密后的明文替换到TCP流窗口的原始数据中对比查看能清晰还原整个攻击交互过程。5. 案例复盘CTF题目解密全流程演练让我们结合一个虚构但典型的CTF场景完整走一遍流程。题目描述提供一个名为godzilla_traffic.pcapng的流量包提示flag隐藏在攻击者执行的命令中。已知Webshell的连接密码pass为Godzilla2023盐salt为Godzilla。5.1 第一步流量筛查与定位用Wireshark打开数据包文件。在过滤栏输入http.request.method POST 回车。在列表中找到一条POST请求目标路径可能是/upload.php。查看其HTTP头部发现一个CookiePHPSESSIDgodzilla_session_123这很可疑。右键该数据包 - “追踪流” - “TCP流”。在弹出窗口中可以看到客户端发送的数据是一长串base64编码的字符串如U2FsdGVkX1...开头服务器返回的也是类似编码。这确认了是加密流量。5.2 第二步密钥计算与数据提取计算KEY和IV已知pass Godzilla2023,salt Godzilla。连接字符串Godzilla2023Godzilla。计算其MD5哈希32位十六进制可以使用在线工具或命令行。假设计算得到e99a18c428cb38d5f260853678922e03。因此KEY e99a18c428cb38d5(前16位)IV f260853678922e03(后16位)。提取密文在TCP流窗口确保显示格式为“原始数据”。在左上角选择“仅显示发送的数据”客户端-服务器。复制全部内容保存到文件client_b64.txt。使用Python或在线工具将client_b64.txt中的base64字符串解码为二进制文件client_encrypted.bin。import base64 with open(client_b64.txt, r) as f: b64_str f.read().strip().replace(\n, ) with open(client_encrypted.bin, wb) as f: f.write(base64.b64decode(b64_str))5.3 第三步执行解密获得Flag使用准备好的Python解密脚本将key和iv的十六进制字符串转换为字节并读取client_encrypted.bin进行解密。from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 key_hex e99a18c428cb38d5 iv_hex f260853678922e03 key bytes.fromhex(key_hex) iv bytes.fromhex(iv_hex) with open(client_encrypted.bin, rb) as f: ciphertext f.read() cipher AES.new(key, AES.MODE_CBC, iv) decrypted_padded cipher.decrypt(ciphertext) decrypted_data unpad(decrypted_padded, AES.block_size) # 哥斯拉4.0默认会对原始数据先做一次base64编码 try: original_data base64.b64decode(decrypted_data).decode(utf-8) except: original_data decrypted_data.decode(utf-8, errorsignore) print(解密后的数据) print(original_data)运行脚本后输出可能是一段序列化的PHP数组或JSON其中包含了攻击指令。例如你可能会看到{func:exec,args:cat /var/www/html/flag.txt}或者直接就是命令执行的结果flag{th1s_1s_4_g0dz1ll4_fl4g}至此Flag成功获取。6. 疑难排查与进阶技巧在实际操作中你可能会遇到各种问题。这里总结一些常见的坑和解决思路。6.1 常见问题速查表问题现象可能原因排查思路与解决方案解密后是乱码1. KEY或IV错误。2. 加密模式不是CBC可能是ECB。3. 填充方式不对可能是ZeroPadding。4. 提取的密文不正确多/少了字节。1. 反复核对pass和salt确认生成KEY/IV的算法有的版本是md5(md5(pass)salt)。2. 尝试其他模式如ECB此时IV为空。3. 尝试不进行unpad操作直接查看解密数据末尾的字节。4. 确保从数据包中提取的是完整的TCP载荷检查是否有分片。解密脚本报Padding is incorrect错误1. 密钥错误导致解密出的填充字节无效。2. 密文在传输或保存过程中被损坏。1. 这是密钥错误的最典型表现。请百分之百确认密钥。2. 尝试使用unpad的style参数如PKCS7、iso7816或手动处理填充。3. 重新从数据包中提取密文确保使用“复制为Hex流”的方式避免编码问题。Wireshark配置TLS解密后无变化1. 密钥日志文件格式错误。2. Wireshark未对目标流量应用TLS解析。3. 端口或IP配置不对。1. 检查密钥文件格式确保是KEY hex_key hex_iv格式且Hex字符串长度正确KEY和IV各32字符。2. 尝试对目标TCP流“解码为”TLS协议。3. 放弃Wireshark内置解密坚定使用外部脚本方案。找不到HTTP POST请求1. 流量可能使用了其他端口非80/443。2. 可能不是HTTP协议或加密在应用层之下。1. 使用过滤条件tcp.port 8080(假设端口) 或直接浏览所有TCP会话。2. 使用tcp contains POST或tcp contains pass进行模糊搜索。3. 查看“统计”-“会话”找出发送数据量较大的TCP连接进行排查。6.2 进阶技巧自动化与流量特征提取编写自动化解密脚本可以将上述Python解密步骤封装成一个函数并集成从pcap文件中自动提取指定TCP流载荷的功能。使用scapy或pyshark库可以方便地读取pcap文件定位到特定条件的TCP流提取载荷然后调用解密函数一气呵成。构建哥斯拉流量指纹除了已知的pass参数哥斯拉的HTTP请求头、Cookie名称、POST数据的结构即使加密长度和模式也有特征都可以作为入侵检测系统IDS的规则。例如可以关注POST数据长度固定为16字节倍数、特定User-Agent如某些版本带Godzilla字样、以及请求间隔规律等行为特征。应对变种与自定义加密哥斯拉支持自定义加密器。在更复杂的场景中攻击者可能使用XOR、RC4或自定义的加密算法。这时关键就在于逆向分析Webshell的payload代码找到其加密函数的实现逻辑然后用Python或Go语言重写解密函数。思路永远是定位流量 - 获取密钥/算法 - 还原逻辑 - 编写解密程序。解密哥斯拉流量的过程本质上是一场与攻击者之间的密码学对抗和信息战。通过这道CTF题的深入实践我们不仅掌握了一个工具的使用技巧更重要的