PHP代码审计03之实例化任意对象漏洞

根据红日安全写的文章,学习PHP代码审计的第三节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完相关知识点,会用一道CTF题目来加深巩固。之前分别学习讲解了in_array函数缺陷和filter_var函数缺陷,有兴趣的可以去看看:
PHP代码审计01之in_array()函数缺陷
PHP代码审计02之filter_var()函数缺陷

漏洞分析

下面我们看第一题,代码如下:

<?php function __autoload($className) { include $className; } $controllerName = $_GET['c']; $data = $_GET['d']; if (class_exists($controllerName)) { $controller = new $controllerName($data['t'], $data['v']); $controller->render(); } else { echo 'There is no page with this name'; } class HomeController { private $template; private $variables; public function __construct($template, $variables) { $this->template = $template; $this->variables = $variables; } public function render() { if ($this->variables['new']) { echo 'controller rendering new response'; } else { echo 'controller rendering old response'; } } } ?>

这段代码有两处漏洞,第一处是文件包含漏洞,现在看代码第八行,这里用到了class_exists()函数来判断用户传过来的控制器是否存在。现在看一下PHP手册对这个函数的解释。

PHP代码审计03之实例化任意对象漏洞


通过看上面的解释,我们知道,如果不指定第二个参数,默认情况下,如果本程序存在__autoload()函数,如果检查的类不存在,那么class_exists()函数就会去调用它。这道题的文件包含漏洞,就出现在这里。如果PHP版本在5~5.3之间,就可以使用路径穿越来包含任意文件,比如类名为../../../../../etc/passwd的查找,那么将查看passwd的内容。
第二处漏洞是在上面代码的第10行,我们发现实例化的类名和传入的参数都是我们可以控制的,所以我们可以通过这个漏洞调用PHP代码库的任意构造构造函数。比如可以使用PHP内置类SimpleXMLElement来进行XXE攻击,看一下PHP手册对这个函数的解释:

PHP代码审计03之实例化任意对象漏洞


功能就是用来表示XML文档中的元素。详细的请看下面,重点是第六条,下面要用到它。

SimpleXMLElement::addAttribute-向SimpleXML元素添加属性

SimpleXMLElement::addChild-向XML节点添加子元素

SimpleXMLElement::asXML-基于SimpleXML元素返回格式良好的XML字符串

SimpleXMLElement::attributes-标识元素的属性

SimpleXMLElement::children-查找给定节点的子节点

SimpleXMLElement::__construct-创建新的SimpleXMLElement对象

SimpleXMLElement::count-计算元素的子级

ExtSimpleNamespaces::GetDocElement-在文档命名空间中声明

SimpleXMLElement::getName-获取XML元素的名称

SimpleXMLElement::getNamespaces-返回文档中使用的命名空间

SimpleXMLElement::registerXPathNamespace-为下一个XPath查询创建前缀/ns上下文

SimpleXMLElement::saveXML-别名SimpleXMLElement::asXML

SimpleXMLElement::__toString -返回字符串内容

SimpleXMLElement::xpath-对XML数据运行XPath查询

为了便于理解,用一小段代码来说明:

<?php $xml = <<<EOF <?xml version = "1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY xxe SYSTEM "file:///C:Windows/win.ini"> ]> <x>&xxe;</x> EOF; $xml_class= new SimpleXMLElement($xml,LIBXML_NOENT); var_dump($xml_class); ?>

查看系统win.ini文件,效果如下图:

PHP代码审计03之实例化任意对象漏洞

CTF练习

通过上面的学习分析,是不是对实例化漏洞和XXE漏洞有了一点点的理解呢?下面我们来做一道CTF题目来练习一下吧,这道题考察的就是实例化漏洞和XXE漏洞。现在我们看具体代码:

<?php class NotFound{ function __construct() { die('404'); } } spl_autoload_register( function ($class){ new NotFound(); } ); $classname = isset($_GET['name']) ? $_GET['name']:null; $param = isset($_GET['param']) ? $_GET['param'] : null; $param2 = isset($_GET['param2']) ? $_GET['param2'] : null; if (class_exists($classname)){ $newclass = new $classname($param,$param2); var_dump($newclass); foreach ($newclass as $key=>$value) echo $key.'$value'.'<br>'; } ?>

我们把注意力放在class_exists()函数这里,上面我们说过了,这个函数它会去检查类是否定义,如果不存在的话,就会调用程序中的 __autoload 函数。我们发现上面没有__autoload 函数,是用spl_autoload_register注册了和__autoload()差不多的,这里输出404信息。
我们仔细看上面的代码第12~16行,我们发现这里的类和类里面的参数都是我们可以控制的,满足了上面咱们提到的实例化漏洞。也就是说,我们可以调用PHP的内置类来完成我们的攻击。
先用GlobIterator类来寻找flag文件的名字,PHP手册对这个类的构造函数定义如下:

PHP代码审计03之实例化任意对象漏洞


通过上图,我们知道,第一个参数是必须的的,也就是搜索的文件名,第二个参数为选择文件的哪个信息作为键名。咱们先搜一下.txt文件。我们构造payload如下:

?name=GlobIterator&param=*.txt

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgpyd.html