ssrf漏洞解析

SSRF 简介

SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。

攻击者可以利用 SSRF 实现的攻击主要有 5 种:

  1. 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
  2. 攻击运行在内网或本地的应用程序(比如溢出)
  3. 对内网 WEB 应用进行指纹识别,通过访问默认文件实现
  4. 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(比如 Struts2,sqli 等)
  5. 利用 file 协议读取本地文件等

上面的话说的有点抽象,然后说一下网上大佬的理解
首先,我们要对目标网站的架构了解,脑子了要有一个架构图。比如 : A网站,是一个所有人都可以访问的外网网站,B网站是一个他们内部的OA网站。
所以,我们普通用户只可以访问a网站,不能访问b网站。但是我们可以同过a网站做中间人,访问b网站,从而达到攻击b网站需求。
正常用户访问网站的流程是:
输入A网站URL –> 发送请求 –> A服务器接受请求(没有过滤),并处理 –>返回用户响应
【 那网站有个请求是www.baidu.com/xxx.php?image=URL
那么产生SSRF漏洞的环节在哪里呢?安全的网站应接收请求后,检测请求的合法性
产生的原因:服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致A网站可以从其他服务器的获取数据
例如:
www.baidu.com/xxx.php?image=www.abc.com/1.jpg
如果我们将www.abd.com/1.jpg 换为与该服务器相连的内网服务器地址会产生什么效果呢?
如果存在该内网地址就会返回1xx 2xx 之类的状态码,不存在就会其他的状态码
终极简析: SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源。

可能出现的场景

  • 能够对外发起网络请求的地方,就可能存在 SSRF 漏洞
  • 从远程服务器请求资源(Upload from URL,Import & Export RSS Feed)
  • 数据库内置功能(Oracle、MongoDB、MSSQL、Postgres、CouchDB)
  • Webmail 收取其他邮箱邮件(POP3、IMAP、SMTP)
  • 文件处理、编码处理、属性信息处理(ffmpeg、ImageMagic、DOCX、PDF、XML)

可进行利用的协议

FILE                           读取服务器上任意文件内容
IMAP/IMAPS/POP3SMTP/SMTPS      爆破邮件用户名密码
FTP/FTPS                       FTP匿名访问、爆破
DICT                           操作内网Redis等服务
GOPHER                         能够将所有操作转成数据流,并将数据流一次发出去,可以用来探测内网的所有服务的所有漏洞
TFTP                           UDP协议扩展

常见函数

file_get_contents()

把文件写入字符串,当把url是内网文件的时候,他会先去把这个文件的内容读出来再写入,导致了文件读取

1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_POST['url'])) {
$content = file_get_contents($_POST['url']);
$filename ='./images/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>

fsockopen()

打开网络连接或者Unix套接字连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$host=$_GET['url'];
$fp = fsockopen("$host", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>

curl_exec()

使用 curl 获取到数据
使用 file:// 获取到数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
if (isset($_POST['url'])) {
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);

$filename = './'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>

利用协议

利用 file 协议读取文件
利用 dict 协议查看端口
利用 gopher 协议反弹shell,攻击数据库

常见的过滤方法

  • 对 url 开头进行过滤
  • 对 url 为 ip 格式的连接进行过滤
  • 对 url 结尾进行判定

绕过方法

  • 更改 IP 地址写法 例如192.168.0.1

    8 进制格式:0300.0250.0.1

    16 进制格式:0xC0.0xA8.0.1

    10 进制整数格式:3232235521

    16 进制整数格式:0xC0A80001

    还有一种特殊的省略模式,例如10.0.0.1这个 IP 可以写成10.1

    利用 URL 解析问题 在某些情况下,后端程序可能会对访问的 URL 进行解析,对解析出来的 host 地址进行过滤。这时候可能会出现对 URL 参数解析不当,导致可以绕过过滤。 例如:

  • http://www.baidu.com@192.168.0.1/http://192.168.0.1 请求的都是 192.168.0.1 的内容

  • 可以指向任意 ip 的域名xip.io:http://127.0.0.1.xip.io/ ==> http://127.0.0.1/

  • 短地址http://dwz.cn/11SMa ==> http://127.0.0.1

  • 利用句号。:127。0。0。1 ==> 127.0.0.1

  • 利用 Enclosed alphanumerics

    ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ  >>>  example.com
    List:
    ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ 
    ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ 
    ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ 
    ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ 
    Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ 
    ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ 
    ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ 
    ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
    

参考文章:
https://xz.aliyun.com/t/2115
https://ctf-wiki.github.io/ctf-wiki/web/ssrf/
https://www.jianshu.com/p/6bf7700139fa
https://www.jianshu.com/p/d1d1c40f6d4c
https://www.jianshu.com/p/86bb349baac1

AbelChe wechat
扫码加微信
Donate here!!!
0%