SSRF学习
关于SSRF
服务端请求伪造漏洞,用户通过WEB访问/上传/发出请求,绕过服务器防火墙,获取服务器及其内网信息。SSRF可以说是一个媒介,结合服务器中的服务,常常可以形成一条完整的攻击链。
相关函数:
file_get_contents(),fsockopen(),curl_exec()三个函数使用不当时将会造成ssrf file_get_contents() 支持php://input协议 curl_exec() 支持file, dict, gopher, http,ftp协议 fsockopen() 大部分 PHP 并不会开启 fopen 的 gopher wrapper file_get_contents 情况使用 gopher 协议不能 URLencode
原理:
通过控制功能中的发起请求的服务来当作跳板攻击内网中其他服务。比如,通过控制前台的请求远程地址加载的响应,来让请求数据由远程的URL域名修改为请求本地、或者内网的IP地址以及服务,来造成内网系统的攻击。
危害:
1.内外网的端口和服务扫描
2.攻击运行在内网或本地的应用程序
3.对内网web应用进行指纹识别,识别企业内部的资产信息
4.攻击内网的web应用,主要是使用GET参数就可以实现的攻击(比如Struts2漏洞利用,SQL注入等)
5.利用file协议读取本地敏感数据文件等
SSRF利用方式
gohper协议:
介绍:
Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。
Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
Gopher 可以模仿 POST 请求,故探测内网的时候不仅可以利用 GET 形式的 PoC(经典的 Struts2),还可以使用 POST 形式的 PoC。
局限:
大部分 PHP 并不会开启 fopen 的 gopher wrapper
file_get_contents 的 gopher 协议不能 URLencode
file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
PHP 的 curl 默认不 follow 302 跳转
curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断), 7.49 可用
具体攻击手法:
file协议:
用来进行任意文件读取
http://xxx.com/ssrf.php?url=file:///etc/passwd
Dict协议:
探测端口操作,以及版本信息
详见 端口扫描部分:CTFHub-ssrf
FTP协议:
只能探测是否存在ftp,不能进行暴力破解
Http协议:
用来探测是否存在ssrf
漏洞的产生:
1、php file_get_contents:
<?php if(isset($_POST['url'])){ $content=file_get_contents($_POST['url']); $filename=''.rand().';img1.jpg'; file_put_contents($filename,$content); echo $_POST['url']; $img="<img src=\"".$filename."\"/>"; } echo $img; ?>
这段代码使用file_get_conctents函数从给用户指定的url获取图片。然后把它用一个随机文件名保存在硬盘上,并展示给用户。
2、php 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); while(!feof($fp)){ $contents.=fgets($fp,1024); } fclose($fp); return $contents; } } ?>
这段代码使用fsockopen函数实现获取用户指定url的数据。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
3、php curl_exec():
<?php funciotn curl($url){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_exec($ch); curl_close($ch); } $url = $_GET['url']; curl($url); ?>
使用curl请求
防御方式:
1、过滤返回的信息,如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
2、统一错误信息,避免用户可以根据错误信息来判断远程服务器的端口状态。
3、限制请求的端口,比如80,443,8080,8090。
4、禁止不常用的协议,仅仅允许http和https请求。可以防止类似于file:///,gopher://,ftp://等引起的问题。
5、使用DNS缓存或者Host白名单的方式。