抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

byc_404's blog

Do not go gentle into that good night

终于准备把欠了好久的SSRF学习记录一下了。最早接触SSRF是去年暑假,师傅给了我一道郁离歌出的入群题。当时对SSRF一无所知,东拼西凑才得到一个ip。可惜当时不知道是内网ip,最后涉及一个gopher打mysql的常见类型,最后也没能做出来。那之后也没有仔细做过ssrf题目,那我现在就来记录一下ssrf的学习笔记吧。

1. SSRF

ssrf全称为Server-side Request Forgery,即服务端请求伪造攻击。很多web应用都提供了从其他的服务器上获取数据的功能。使用用户指定的URL,web应用可以获取图片,下载文件,读取文件内容等。这个功能如果被恶意使用,可以利用存在缺陷的web应用作为代理攻击远程和本地的服务器。

也就是说,ssrf的漏洞点在于:服务端提供了从其他服务器应用获取数据的功能,在用户可控的情况下,未对目标地址进行过滤与限制.
常见场景包括但不仅限于:

1.社交分享功能:获取超链接的标题等内容进行显示
2.转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
3.在线翻译:给网址翻译对应网页的内容
4.图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片
#比如hgameweek2
5.图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
6.云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
7.网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
......

如果要从服务端的源码层面来讲,主要就是以下三种函数(php):

1.file_get_contents()

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

常见的直接用file_get_contents()加载url指向文件
2.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; 
} 
}
?>

这个函数会使用socket跟服务器建立tcp连接,传输原始数据。

3.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;
}
?>

假如出现以上几种函数(已知源码前提下),通常可以尝试使用ssrf。

2.SSRF的利用

实话说,ssrf不像sql,xss那样属于人尽皆知的漏洞。但其利用在真实渗透中是非常常见的。其利用场景主要有:

1.让服务端去访问相应的网址
(比如读/flag之类的)
2.让服务端去访问自己所处内网的一些指纹文件来判断是否存在相应的cms
3.可以使用```file、dict、gopher、ftp```协议进行请求访问相应的文件
(其中gopher被称作万金油,可以打内网也可以get,post,当然还有攻击内网未授权的mysql,主要区别在于不默认端口)
4.攻击内网web应用(可以向内部任意主机的任意端口发送精心构造的数据包{payload})
(ssrf打redis)
5.攻击内网应用程序(利用跨协议通信技术)
6.判断内网主机是否存活:方法是访问看是否有**端口开放**
7.利用phar协议触发反序列化

CTF题目中具体见过的包括之前hackergame的一道伪ssrf(只涉及到url);NCTF2019 True-XML-Cookbook
以及hgame的Cosmos的博客后台(果然还是做得太少了)

3.绕过

关于绕过,把重点放在几个大类上:
1)ip地址绕过
192.168.0.1

8进制:0300.0250.0.1
16进制:0xC0.0xA8.0.1
10进####制:3232235521
16进制整数: 0xC0A80001

也可以通过省略达到同样的效果
对10.0.0.1

1.http://0/
2.http://127.1/
3.ipv6:http://[::1]/
4.http://127.0.0.1./

2)url bypass

这应该是是基础类ssrf最常见的考点了,比较适合我这样的萌新总结。
在谈及绕过之前,先来理解下url的基本概念:
url
可以注意到url的组成部分。

scheme 协议
authority 权限=主机名+端口号 ,再详细一点如
![2.jpg](https://upload-images.jianshu.io/upload_images/18060177-6d443ccaaa9138ba.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
admin:admin@www.example.com:2333`(使用用户名为 admin,密码为 admin,访问 www.example.com 的 2333 端口获取资源)
path 路径
query 查询
fragment 指向一个更低级别的资源

我们常常通过构造url来bypass个别函数,最终达成ssrf的目的。
而orange的那篇经典的pdf指出了几个函数利用上的经典漏洞,其中离不开一个@

php parse_url:
host: 匹配最后一个@后面符合格式的host

libcurl:
host:匹配第一个@后面符合格式的host

parse_url
利用@可以轻松使google.com(默认白名单)置为host,达到绕过php parse_url的效果(这里用#将@忽略了)

同样对于curl操作,假如使用libcurl
lib_curl
则将第一个@后的危险网站置为执行curl的对象,达到漏洞利用。
同样效果的还有;
http://evil.com;google.com。curl会将evil.com当成
hostname,而将后面的google.com当做quqerystring。

提到curl,还可以提到后端代码的一种常见搭配

1.filter_var对url进行check
2.parse_url获取url的host
3.对host进行正则匹配
4.exec执行命令
<?php
   echo "Argument: ".$argv[1]."\n";
   // check if argument is a valid URL
   if(filter_var($argv[1], FILTER_VALIDATE_URL)) {
      // parse URL
      $r = parse_url($argv[1]);
      print_r($r);
      // check if host ends with google.com
      if(preg_match('/google\.com$/', $r['host'])) {
         // get page from URL
         exec('curl -v -s "'.$r['host'].'"', $a);
         print_r($a);
      } else {
         echo "Error: Host not allowed";
      }
   } else {
      echo "Error: Invalid URL";
   }
?>

关于bypass filter_varparse_url也是有妙招的:
首先是 filter_var
上面说到,http://evil.com;google.com是可以执行curl到危险网站的。但是假如在curl之前加上filter_var后要怎么绕过呢?很简单,更改协议即可

0://evil.com;google.com

但是这样的话curl可能执行不了了,所以把hostname强调一下

0://evil.com:80;google.com:80

加上端口即可。

其次是parse_url:
pase_url并不需要完全绕过hostname。因为parse_url的作用只是将一个给定url分成上面提到的scheme,hostname,port,path几部分。所以下面这个paylaod

0://evil$google.com

在经过parse_url后,hostname仍为evil$google.com。但是当源码中

exec('curl -v -s "'.$r['host'].'"', $a);

执行时,bash会将后面的$google.com当做一个变量并置为空,所以exec()时仍是指向evil.com
使用前提:用exec system执行curl wget之类的。

以上都是curl函数的ssrf,那么如果是file_get_contents()呢:
比如只将上面exec()部分函数改为

// get page from URL
$a = file_get_contents($argv[1]);

这时就可以考虑到常常利用的各种协议,比如data协议

data://google.com/plain;base64,SSBsb3ZlIFBIUAo=

parse_url会将host设为google.com,而将后面全部看作path。但实际上输出了

I love PHP

所以如果把后面的base64部分换作xss代码编码后的结果,就可以执行xss。

先这样。由于还没接触到ssrf的高级拓展场景,等日后接触到再写一篇高级利用。

参考文章:

https://xz.aliyun.com/t/2115

https://skysec.top/2017/08/19/SSRF%E5%AD%A6%E4%B9%A0/

https://medium.com/secjuice/php-ssrf-techniques-9d422cb28d51

https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf

评论