thinkphp5.2.*-dev反序列化漏洞分析

前言

国庆旅游回来,发现tp反序列化链很流行,试着学习一下,打算用三篇文章来目前最新的三个反序列化漏洞,继上一篇tp5.1.x反序列化,现在分析tp5.2.*-dev的反序列化漏洞。

环境搭建

1
composer create-project topthink/think=5.2.*-dev v5.2

poc演示截图

调用链

单步调试

可以看到前面的链跟tp5.1.x的一样,这里不在列举,直接进去toArray函数,可以看到$data可控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public function toArray(): array
{
。。。
$data = array_merge($this->data, $this->relation);

foreach ($data as $key => $val) {
if ($val instanceof Model || $val instanceof ModelCollection) {
// 关联模型对象
if (isset($this->visible[$key])) {
$val->visible($this->visible[$key]);
} elseif (isset($this->hidden[$key])) {
$val->hidden($this->hidden[$key]);
}
// 关联模型对象
$item[$key] = $val->toArray();
} elseif (isset($this->visible[$key])) {
$item[$key] = $this->getAttr($key);
} elseif (!isset($this->hidden[$key]) && !$hasVisible) {
$item[$key] = $this->getAttr($key);
}
}
。。。
1
2
3
4
5
6
7
8
9
10
11
12
public function getAttr(string $name)
{
try {
$relation = false;
$value = $this->getData($name);
} catch (InvalidArgumentException $e) {
$relation = true;
$value = null;
}

return $this->getValue($name, $value, $relation);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public function getData(string $name = null)
{
if (is_null($name)) {
return $this->data;
}

$fieldName = $this->getRealFieldName($name);

if (array_key_exists($fieldName, $this->data)) {
return $this->data[$fieldName];
...
}
}
1
2
3
4
protected function getRealFieldName(string $name): string
{
return $this->strict ? $name : App::parseName($name); //this->strict默认为true
}

可以看到getAttr函数中的$value可控,那么导致$this->getValue($name, $value, $relation);这里的三个参数都可控,跟进$this->getValue($name, $value, $relation);

1
2
3
4
5
6
7
8
9
10
11
12
13
protected function getValue(string $name, $value, bool $relation = false)
{
// 检测属性获取器
$fieldName = $this->getRealFieldName($name);
$method = 'get' . App::parseName($name, 1) . 'Attr';

if (isset($this->withAttr[$fieldName])) {
if ($relation) {
$value = $this->getRelationValue($name);
}

$closure = $this->withAttr[$fieldName];
$value = $closure($value, $this->data);

这里$fieldName、$this->withAttr,导致$closure也可控,最终直接产生RCE。如下图

poc这里就不放了,公网已经大范围公开。

补充:

1
2
3
4
<?php

$a = array();
system('whoami',$a);

-------------本文结束感谢您的阅读-------------