目录
一、SSRF的介绍
二、漏洞产生的原因
三、利用SSRF可以实现的效果(攻击方式)
四、SSRF的利用
五、SSRF中的函数
file_get_content() 、fsockopen() 、curl_exec()
1.file_get_content():
2.fsockopen():
3.curl_exec():
六、漏洞的判断
七、SSRF可以利用到的协议
例题(ctfhub中的伪协议读取文件)
八、SSRF漏洞的相关绕过
(1)@符号
(2)302跳转
(3)数字IP Bypass
(4)短网址绕过
(5)添加端口号
例题(ctfhub中的端口扫描)
(6)协议限制绕过
九、 漏洞修复:
十、例题
(1)ctfhub中的POST请求
(2)ctfhub中上传文件
一、SSRF的介绍
SSRF(服务器端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是外网无法访问的内部系统(正因为请求是由服务端发起的,所以服务端能请求到与自身相连而与外网隔离的内部系统)。
二、漏洞产生的原因
服务端提供了能够从其他服务器应用获取数据的功能,比如从指定的URL地址获取网页内容,加载指定地址的图片、数据、下载等等,服务端请求的目标都是与该请求服务器处于同一内网的资源服务,如果没有对这个请求的目标地址、文件等做充足的过滤和限制,攻击者就可以通过篡改这个请求的目标地址来进行伪造请求,造成漏洞。
三、利用SSRF可以实现的效果(攻击方式)
1、可以对服务器所在的内网、本地进行端口扫描,获取一些服务的banner信息
2、攻击运行在内网或本地的应用程序(比如溢出)
3、对内网web应用进行指纹识别,通过访问应用存在的默认文件实现;
4、攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2漏洞利用等)
5、利用file协议读取本地文件
6、利用Redis未授权访问,HTTP CRLF注入达到getshell
7、DOS攻击(请求大文件,始终保持连接keep alive always)等等
四、SSRF的利用
五、SSRF中的函数
file_get_content() 、fsockopen() 、curl_exec()
1.file_get_content():
使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随即文件名保存在硬盘上,并展示给用户。
<?php
if (isset($_POST['url'])) //检查是否用post传了一个url的参数
{
$content = file_get_contents($_POST['url']); //使用 file_get_contents 函数获取 POST 参数 'url' 对应的 URL 的内容
$filename ='./images/'.rand().';img1.jpg'; //构造一个文件名,其中文件名的一部分是随机数,文件名固定为 'img1.jpg'
file_put_contents($filename, $content); echo $_POST['url']; //使用 file_put_contents 函数将 $content 保存到 $filename 指定的文件中,并输出接收到的 URL。
$img = "<img src=\"".$filename."\"/>"; //构造一个包含图片路径的 HTML img 标签
}
echo $img; //输出图片的 HTML 标签,如果之前没有设置 $img,这里会输出一个空字符串
?>
2.fsockopen():
使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
<?php
function GetFile($host,$port,$link) //定义了一个名为 GetFile 的函数,它接受三个参数:$host(主机名或IP地址),$port(端口号),$link(请求的URL或路径)。
{
$fp = fsockopen($host, intval($port),
$errno, $errstr, 30); //使用 fsockopen 函数尝试与指定的 $host 和 $port 建立 TCP 连接。intval($port) 确保端口号是一个整数。$errno 和 $errstr 用于捕获可能的错误信息。如果连接不能在 30 秒内建立,fsockopen 将返回 false。
if (!$fp){
echo "$errstr (error number $errno) \n"; //如果 $fp 为 false(即连接失败),则输出错误信息。
}
else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n"
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n"; fwrite($fp, $out); //构建 HTTP GET 请求的头部,使用 fwrite 函数将构建的 HTTP 请求发送到服务器
$contents='';
while (!feof($fp)){
$contents.= fgets($fp, 1024); //通过循环读取从服务器返回的响应内容,每次读取最多 1024 字节,直到文件结束(feof($fp) 返回 true)
}
fclose($fp);
return $contents; //关闭与服务器的连接,并返回读取到的内容。
}
}
?>
3.curl_exec():
使用curl发送请求获取数据。(Curl是一个强大的工具,可以用于从命令行或脚本发送HTTP请求。)
<?php
// 检查是否通过POST方法接收到了名为'url'的变量
if (isset($_POST['url'])) {
// 从POST数据中获取'url'的值,并赋值给$link变量
$link = $_POST['url'];
// 初始化一个cURL会话
$curlobj = curl_init();
// 设置cURL选项,指定此次请求为GET请求(CURLOPT_POST的值为0表示GET请求)
curl_setopt($curlobj, CURLOPT_POST, 0);
// 设置cURL选项,将curl_exec()返回的数据以字符串形式返回,而不是直接输出
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, TRUE);
// 执行cURL请求,并将返回的数据赋值给$result变量
$result = curl_exec($curlobj);
// 关闭cURL会话
curl_close($curlobj);
// 生成一个随机文件名,其中'./curled/'是文件存放的目录,rand()函数生成随机数作为文件名的一部分,'.txt'是文件扩展名
$filename = './curled/'.rand().'.txt';
// 将$result中的数据写入到$filename指定的文件中
file_put_contents($filename, $result);
// 输出$result的内容
echo $result;
}
?>
六、漏洞的判断
1.排除法:浏览器F12查看源代码看是否是在本地进行了请求 举例:该资源地址类型为 http://www.xxx.com/a.php?image=(地址)的就可能存在SSRF漏洞。
2、Dnslog等工具进行测试,查看是否被访问 生成一个域名用于伪造请求,看漏洞服务器是否发起 DNS 解析请求,若成功访问在 http://DNSLog.cn 上就会有解析日志。
3、抓包分析发送的请求是不是由服务器的发送的,如果不是客户端发出的请求,则有可能是,接着找 存在HTTP服务的内网地址。
4、访问日志检查:伪造请求到自己控制的公网服务器,然后在服务器上查看访问日志是否有来自漏洞 服务器的请求。
5、扫描工具
七、SSRF可以利用到的协议
常用的URL伪协议:
file:/// -- 本地文件传输协议,主要用于访问本地计算机中的文件
dict:// -- 字典服务器协议,dict是基于查询相应的TCP协议,服务器监听端口2628
sftp:// -- SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol)
ldap:// -- 轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议
tftp:// -- 基于lockstep机制的文件传输协议,允许客户端从远程主机获取文件或将文件上传至远程主机
gopher:// -- 互联网上使用的分布型的文件搜集获取网络协议,出现在http协议之前,Gopher协议可以说是SSRF中的万金油。利用此协议可以攻击内网的 Redis、Mysql、FastCGI、Ftp等等,也可以发送 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
gopher协议格式:URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
?url=127.0.0.1/index.php/?url=gopher://127.0.0.1:80/_POST包
WEB常用的本地地址:/?url=file:///var/www/html/xxxx.php
例题(ctfhub中的伪协议读取文件)
八、SSRF漏洞的相关绕过
url解析规则
IP地址进制转换
302跳转
DNS重绑定
(1)@符号
对于一个 url 的访问实际上是以 @符后为准的,比如说 xxxx.com@10.10.10.10,则实际上访问的是 10.10.10.10 这个地址
(2)302跳转
网址后加 xip.io(xip.io可以指向任意域名)
其原理是例如 10.10.10.10.xip.io 会被解析成 10.10.10.10
(3)数字IP Bypass
IP进制转换/Enclosed Alphanumerics/特殊地址
进制转换
ip 转换为八进制十进制十六进制这种,同样也可以正常访问
(4)短网址绕过
https://0x9.me/cuGfD 推荐:http://tool.chinaz.com/tools/dwz.aspx、https://dwz.cn/
(5)添加端口号
例题(ctfhub中的端口扫描)
1.根据提示,猜测需要端口,想到使用bp抓包
2.根据提示设置参数
3.长度不一样的就是端口
(6)协议限制绕过
当url协议限定只为http(s)时,可以利用follow redirect 特性
构造302跳转服务,
结合dict:// file:// gopher://
九、 漏洞修复:
(1)使用地址白名单
(2)对返回内容进行识别
(3)需要使用互联网资源(比如贴吧使用网络图片)而无法使用白名单的情况:
首先禁用CURLOPT_FOLLOWLOCATION;然后通过域名获取目标ip,并过滤内部ip;最后识别返回的内容是否与假定内容一致
十、例题
(1)ctfhub中的POST请求
1.使用/?url=file:///var/www/html/flag.php来查看本地文件,通过代码大致可得需要用post传一个"key"参数,并且这个key要等于$key,这样才能输出flag
2.根据代码可得需要检查当前请求的 IP 地址是否为本机地址(127.0.0.1),所以使用使用http协议查看本地的flag.php文件,查看源代码,发现key
3.使用burp抓包,并发送到Repeater模块进行操作,构造一个简单的POST请求
gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: xxx(根据key)
key=xxxxxxxxxxxxxxxxxxxxxxxx
4.对该POST请求进行编码
5.将%0A全部改为%0D,再进行编码
6.构造payload再在bp中发送,得到flag
(2)ctfhub中上传文件
1.构造file伪协议payload查看index.php和flag.php源代码