thinkphp远程代码执行漏洞分析

本文详细分析了ThinkPHP的两个远程代码执行漏洞,包括触发条件、环境和漏洞原理。通过对代码审计和调试,揭示了如何利用这些漏洞实现代码执行,并提供了漏洞利用的示例payload,总结了漏洞成因和防范措施。
摘要由CSDN通过智能技术生成

前言

最近刚刚简单学习了thinkphp,所以就看了看thinkphp爆出的代码执行漏洞。第一次看这种代码,所以是根据大佬们所讲的,加大佬们的payload,加手工调试,总算是找到了一些流程

thinkphp漏洞 一
漏洞版本

thinkphp5.1.* 版本

触发条件

thinkphp5 设置 error_reporting(0)

环境

thinkphp5.1.31+php7.2.13+apache

漏洞分析

漏洞文件:\thinkphp\library\think\Request.php
这个文件是Request类,处理对网站发起的请求
漏洞代码(其中有我加的调试代码)

public function method($origin = false)
    {
   
		print_r("start---method    ");
        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;
				print_r('start------覆盖   ');
            } 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';
				echo "server2";
            }
        }

        return $this->method;
    }

这里存在一个变量覆盖漏洞,$this->config[‘var_method’]这是一个常量,这个常量定义在\think\config\app.php中,也就是$this->config[‘var_method’]=_method,我们以POST传入的_method 的值会被先转化为大些,然后转化为小写,赋值给$method,最后会执行$this->{$method} = $_POST,既然_method的值是post传入的,那就是可控的,也就是说$this->{$method} = P O S T 中 _POST中 POSTmethod是可控的,也就是说$method 可以是request类中任何变量,最后会导致request类中任何变量可以被覆盖。
举个列子

<?php

class fugai
{
   
	public $filter=123;
	public $method=456;
	
	public function __construct()
	{
   
		        $this->method   = strtoupper($_POST['_method']);
                $method      = strtolower($this->method);
				$this->{
   $method}= $_POST;
	}
	public function print_fugai()
	{
   
		echo '$this->filter=';
		print_r($this->filter);
		echo '$this->method=';
		print_r($this->method);
	}
	
}
$a =new fugai();
$a->print_fugai();

?>

在这里插入图片描述最后$this->filter的值被覆盖为图上的值,这样就能覆盖类中任意变量
接下来是利用函数,其实通过代码审计工具也能找到,函数中的call_user_func是可以造成代码执行的函数,其中$filter可以是php自带函数(可以是危险函数,但不包括eval),$value是传入函数的值。

private function filterValue(&$value, $key, $filters)
    {
   
        $default = array_pop($filters);

        foreach ($filters as $filter) {
   
            if (is_callable($filter)) {
   
                // 调用函数或者方法过滤
                $value = call_user_func($filter, $value);
            } elseif (is_scalar($value)) {
   
                if (false !== strpos($filter, '/')) {
   
                    // 正则过滤
                    if (!preg_match($filter, $value)) {
   
                        // 匹配不成功返回默认值
                        $value = $default;
                        break;
                    }
                } elseif (!empty($filter)) {
   
                    // filter函数不存在时, 则使用filter_var进行过滤
                    // filter为非整形值时, 调用filter_id取得过滤id
                    $value = filter_var($value, is_int($filter) ? $filter : filter_id($filter));
                    if (false === $value) {
   
                        $value = $default;
                        break;
                    }
                }
            }
        }

        return $value;
    }

调试查看哪里调用了函数filterValue,找到input函数和cookie ,函数cookie函数是获取cookie参数,input函数是获取变量。进行调试(print就行)发现是Input函数对filterValue进行了调用,跟进Input函数
调试并找到调用filterValue的函数array_walk_recursive。

 public function input($data = [], $name = '', $default = null, $filter = '')
    {
   
		print_r('start input');
        if (false === $name) {
   
            // 获取原始数据
            return $data;
        }

        $name = (string) $name;
        if ('' != $name) {
   
            // 解析name
            if (strpos($name, '/')) {
   
                list($name, $type) = explode('/', $name);
            }

            $data = $this->getData($data, $name);

            if (is_null($data)) {
   
                return $default;
            }

            if (is_object($data)) {
   
                return $data;
            }
        }

        // 解析过滤器
		echo '$this->filter';
        $filter = $this->getFilter($filter, $default);
		//print_r($this->filter);
		//print_r($filter);
        if (is_array($data)) {
   
            array_walk_recursive($data, [$this, 'filterValue'], $filter);
            if (version_compare(PHP_VERSION, '7.1.0', '<')) {
   
                // 恢复PHP版本低于 7.1 时 array_walk_recursive 中消耗的内部指针
                $this->arrayReset($data);
            }
        } else {
   
            $this->filterValue($data, $name
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值