前言
上次出的洞是接近元旦吧,好像刚从南京回学校,要准备烦人的期末,没心思分析,前天我刚考完,今天刚爆的洞洞貌似。然后自己跟着调试了一下。
漏洞细节
这是复现图
前提是要在index.php中禁止报错,其实在生产环境中,开发也会这么做。
漏洞点在\thinkphp\library\think\Request.php中的method函数:
public function method($origin = false)
{
if ($origin) {
// 获取原始请求类型
return $this->server('REQUEST_METHOD') ?: 'GET';
} elseif (!$this->method) {
if (isset($_POST[zxsq-anti-bbcode-$this->config['var_method']])) {
$this->method = strtoupper($_POST[zxsq-anti-bbcode-$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 是预定义的
$this->{$method} = $_POST;
这里有一个变量覆盖。
array (size=3)
'c' => string 'system' (length=6)
'f' => string 'whoami' (length=6)
'_method' => string 'filter' (length=6)
这里为什么要覆盖filter呢?
是为了最后这里,在call_user_func() 这里执行。
说明
mixed call_user_func ( callable $callback [zxsq-anti-bbcode-, mixed $parameter [, mixed $... ]] )
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
得到结果。
官方的修复代码:
return $this->server('REQUEST_METHOD') ?: 'GET';
} elseif (!$this->method) {
if (isset($_POST[zxsq-anti-bbcode-$this->config['var_method']])) {
$this->method = strtoupper($_POST[zxsq-anti-bbcode-$this->config['var_method']]);
$method = strtolower($this->method);
$this->{$method} = $_POST;
$method = strtolower($_POST[zxsq-anti-bbcode-$this->config['var_method']]);
if (in_array($method, [zxsq-anti-bbcode-'get', 'post', 'put', 'patch', 'delete'])) {
$this->method = strtoupper($method);
$this->{$method} = $_POST;
} else {
$this->method = 'POST';
}
unset($_POST[zxsq-anti-bbcode-$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 数据源
* home.php?mod=space&uid=126298 void
*/
public function arrayReset(array &$data) {
public function arrayReset(array &$data)
{
foreach ($data as &$value) {
if (is_array($value)) {
$this->arrayReset($value);
只允许五种方法,保证变量在可控范围内。
总结
大佬们真牛逼!!!