0x00 SSRF漏洞简介
SSRF(server-site request forgery,服务端请求伪造)是一种构造请求,由服务端发起请求的安全漏洞。
客户端—服务端—内网资源
服务端与内网资源可交互,客户端通过伪造服务端请求内网资源的http请求,来获取内网资源。
0x01 SSRF漏洞原理
1. SSRF形成原因
服务端提供了从其他服务器获取数据的功能,但没有对内网目标地址做过滤和限制。
2. 主要方式
- 对外网、服务器所在内网、本地进行端口扫描,获取Banner信息。
- 测试运行在内网或本地的应用程序。
- 利用file协议读取本地文件等。
3. 漏洞代码
<?php
function curl($url){ // curl函数用来发送请求
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_exec($ch);
curl_close($ch);
}
$url = $_GET["url"]; // 用户通过构造url来进行访问
curl($url);
?>
访问链接如:http://ip/ssrf_test/test.php?url=file:///c:/windows/win.ini
即利用file伪协议进行SSRF,攻击内网:
file:///c:/windows/win.ini
0x03 产生SSRF漏洞的PHP函数
很多web应用都提供了从其他的服务器上获取数据的功能。使用用户指定的URL,web应用可以获取图片、下载文件,读取文件内容等。
这个功能如果被恶意使用,可以利用存在缺陷的web应用作为代理,攻击远程和本地的服务器。
这种形式的攻击称为服务端请求伪造攻击(Server-side Request Forgery)。
SSRF攻击可能存在任何语言编写的应用,php中可能存在SSRF漏洞的函数有:
- file_get_contents()
- fsockopen()
- curl_exec()
0x04 file_get_contents()
下面代码使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随机文件名保存在硬盘上,并展示给用户。
<?php
if(isset($_POST['url'])){
$content = file_get_contents($_POST['url']);
$filename = './images/'.rand().'img1.jpg';
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>
0x05 fsockopen()
使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
<?php
function GetFile($host, $port, $link){
$fp = fsockopen($host, intval($port), $errno, $errstr, 30); // 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 .=($fp,1024);
}
fclose($fp);
return $contents;
}
}
?>
0x06 curl_exec()
使用curl发送请求获取数据。
<?php
if(isset($_POST['url'])){
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj,CURLOPT_POST,0); // 如果最后一个是1或真,那就是POST请求。
curl_setopt($curlobj, CURLOPT_RETURNTRRANSFER, TRUE); // TRUE 将curl_exec获取的信息以字符串返回,而不是直接输出。
$result = curl_exec($cuelobj);
curl_close($curlobj);
$filename = './curled/'.rand().'/txt';
file_put_contents.echo $result;
}
?>
0x07 SSRF内网资源探测
以下代码存在SSRF漏洞:
<?php
if(isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init($link);
curl_setopt($curlobj,CURLOPT_HEADER,0);
curl_setopt($curlobj,CURLOPT_RETURNTRANSFER,1); // 设置返回结果为字符串
$result = curl_exec($curlohj);
echo $result;
curl_close($curlobj);
}
?>
使用NAT网卡模式打开vm windows server 2003。这样windows虚拟机就和PC在同一个局域网下,相当于内网,然后由PC对外有一个ip,修改本地host文件,使本地IP地址与自定义域名映射(运行drivers,然后打开etc文件夹,想办法新建一个hosts文件,写入
127.0.0.1 test.com
即可,浏览器访问test.com就会访问本地网站)。
一般情况下将web应用程序暴露在互联网可以通过web浏览器进行访问。但是会将内网资源封闭起来,避免与外部交互。那么如果网站存在SSRF漏洞,利用SSRF进行内网资源访问。
如:
http://服务器ip/ssrf_test/ssrf.php?url=http://内网资源ip/source.txt
或者利用SSRF进行端口扫描:提交对应参数url包含IP地址:端口号 测试端口状态。比如在浏览器中输入:http://服务器ip/ssrf/ssrf.php?url=http://127.0.0.1:3306 来查看服务器是否开放了3306端口,如果有会把响应直接输出在浏览器上。
0x08 SSRF危害
- 扫描内部网络
- 构造数据攻击内部主机
- 作为网络跳板来攻击其他主机
- 发起DDOS攻击
0x09 SSRF漏洞利用
- 对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息
- 攻击者运行在内网或本地的应用程序(比如溢出)
- 对内网web应用进行指纹识别,通过访问默认文件实现
- 攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struct2、SQL注入等)
- 利用file等协议读取本地文件
0x0a SSRF防御
一般防御方法:
- 使用系统内置函数完成目标URL解析
- 禁止解析跳转
- 对返回结果进行过滤,返回结果之前先验证返回的信息是否符合标准
- 禁用不必要的协议,如file://、gopher://、dict://、ftp://等
- 设置URL白名单或限制内网IP
- 只允许请求端口为Web端口,比如80、443、8080、8090
- 统一错误信息,屏蔽返回的详细信息,避免用户根据错误信息来判断远端服务器的端口状态
0x0b 常见SSRF位置
- 社交分享功能:获取超链接的标题等内容进行显示
- 转码服务:通过URL地址把原地址的网页内容调优适合手机屏幕浏览
- 在线翻译:给网址翻译对应网页的内容
- 图片加载/下载:富文本编辑器的下载图片;通过URL地址加载或下载图片
- 图片/文章收藏:会取URL中title以及文本的内容作为显示
- 云服务厂商:远程执行一些命令来判断网站是否存活
- 网站采集:一些网络会针对输入的URL进行信息采集工作
- 数据库内置功能:比如MongoDB的copyDatabase函数
- 邮件系统:比如接收邮件服务器地址
- 编码处理,属性信息处理,文件处理:如ffmpg/ImageMagic/docx/pdf/xml处理器等
- 一些URL的关键词:share、wap、url、link、src、source、target、u、3g、display、sourceURI、imageURL、domain……
0x0c 绕过host限制
1. @绕过
URI = scheme:[//[user[:pass]@]host[:port]path[?query][#fragment]]
例如:
http://baidu.com@127.0.0.1:10080/abc/xxx.php
2. 域名绕过
用域名代替IP。
3. 其他形式的IP地址
- 十进制
http://2130706433/ 相当于 http://127.0.0.1/
- 缩略
http://127.1/
- localhost
- [::]:80
- 短链接
4. 指向任意IP的xip.io
xip.io是一个可以指向任意IP的域名,以下都相当于10.0.0.1
- 10.0.0.1.xip.io
- www.10.0.0.1.xip.io
- mysite.10.0.01.xip.io
- foo.bar.10.0.0.1.xip.io
0x0d 绕过scheme限制
curl如果允许重定向
curl_setopt($curlobj, CURLOPT_FOLLOWLOCATION,1);
可通过header函数来重定向页面
<?php
header("Location: http://1.1.1.1/");
?>