In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)05/31 Report--
This article introduces Thinkphp5.0, 5.1, 6.x deserialization vulnerability analysis, the content is very detailed, interested friends can refer to, hope to be helpful to you.
Namespace
The declaration of namespaces avoids problems caused by duplicate class or function names. Use namespace to declare and switch namespaces.
/ * run result * current namespace first * current namespace second * /
Classes of the same name can be defined in different namespaces, and when there are multiple namespaces, the default is the last declared space. If you want to use a class with another namespace, you need to add a namespace before the class, and classes that directly use other namespaces will make an error.
/ / Operation result / / O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A34%3A%22think%5Cprocess%5Cpipes%5CWindowsfiles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A11%3A%22D%3A%2F%2Fdel.txt%22%3B%7D%7D
Line 163 of the removeFiles function, using the file_exist function to handle the $filename,file_exist function will treat the argument as a string, and the _ _ toString method can be triggered if you make $filename an object with a _ _ toString method.
The _ _ toString method of the Pivot class comes from the parent class Model, while the _ _ toString method of Model comes from the trait class Conversion
The _ _ toString chain of the Conversion class is as follows
The toArray code is too long. Intercept the useful parts as follows
In the meantime, the $relation variable comes from $this- > data [$name], and the $name variable comes from $this- > append, both of which are controllable. If you make $relation an object that has available visible methods or no visible methods but has available _ _ call methods, you can move on to the next step.
_ _ call find the Request class here, as follows
Because $this- > hook is controllable, we can easily execute to call_user_func_array. However, due to the existence of 330lines of array_unshift, the Request object is placed in the first place of $args, so we cannot execute any code here (because the parameters are uncontrollable), so we need to look again for the first function whose parameters do not affect the result to construct the available chain.
Find Request::isAjax here and track it.
Tracking input
$name from config ['var_ajax'], controllable, $data from $this- > param, also controllable.
Trace filterValue, during which call_user_func is executed ($filter, $value)
$value comes from $data in input, so it finally comes from $this- > param,$filter and gets it after calling the getFilter function.
In the meantime, $this- > filter is controllable, so $filter is controllable. Since $filter,$value is controllable, you can execute arbitrary code and look back at the pop chain again.
Windows::__destruct-- > Pivot::__toString-- > Request::__call-- > Request::isAjax-- > Request::param-- > Request::input-- > Request::filterValue-- > call_user_func
Exp
If you want to perform system ('id'), you need to control the variable to the following values
Request- > filter = "system"; Request- > param = array ('id'); Request- > hook [' visible'] = [$this, "isAjax]; Request- > config ['var_ajax'] =''; Pivot- > data = [" azhe "= > new Request ()]; Pivot- > append = [" azhe "= > [" 4ut "," 15m "]]; Windows- > files = [new Pivot ()];-- exp
TPv6.x vulnerability
POP chain Model- > _ destruct ()-- > Model- > save ()-> Model- > updateData ()-> Model- > checkAllowFields ()-> Conversion- > _ toString ()-> Conversion- > toJson ()-> Conversion- > toArray ()-> Attribute- > getAttr ()-> Attribute- > getValue ()
First look at the starting point of deserialization Model- > _ _ destruct ()
Call save when $this- > lazySave = = true and trace as follows
To call updateData, you need to bypass the first if and $this- > exists = = true
Bypass of if requires isEmpty () to return false and trigger () to return true
Trace isEmpty () and return false when $this- > data is not empty
Trace trigger (), and trigger () returns true when $this- > withEvent = = false. (PS:trigger () belongs to ModelEvent)
After bypassing, trace updateData ().
To call checkAllowFields, you need to bypass the second if. Track getChangedData () to see the acquisition of $data
When $this- > force = = true, $data is controllable and is the value of $this- > data
Track checkAllowFields (). You can already see a _ _ toString trigger point here. In addition to this trigger point, another trigger point is db ()
Track db (). The trigger point is where the string is concatenated. Just make $this- > table, $this- > name, or $this- > suffix an object with the _ _ toString method.
To execute to the trigger point, you need to bypass the second and third if of updateData, that is, $this- > field (empty by default) and $this- > schema (empty by default)
The above is the _ _ destruct chain. To sum up, the properties you need to set are as follows
Model- > lazySave = true;Model- > exists = true;Model- > withEvent = falseModel- > force = true;Model- > data is not empty Model- > name (or table, suffix) is an object
Next look at the _ _ toString chain
Conversion- > _ _ toString
Trace toArray ()
To call getAttr (), you first need to bypass if.
$data comes from $this- > data and $this- > relation. When the value of $data is not an instance of Model or ModelCollection, the first if can be passed. If you set $this- > visible, getAttr will be called on line 173, and if not set, it will be called on line 175without influence.
Follow up getAttr ()
Call getData to get $value and follow up
Follow up getRealFieldName ()
When $this- > strict = = true (also true by default), $name is returned (name is the key of $this- > data). That is, the key with the final value of $fieldName of $this- > data.
The if in line 279 returns the value of the corresponding key when the $fieldname key exists in $this- > data. So the final value of $value is $this- > data [$fieldName]
Follow up getValue ()
Line 496 of the code, $closure is completely controllable, line 497 triggers rce.
Let's first look at the parameters passed in by calling getValue (), $name, $value, and $relation, which are $this- > data's key,$this- > data's value,false, respectively.
Because $this- > withAttr [$fieldName] is controllable and $relation = = false, the program executes to line 497.
The above is the _ _ toString chain, and the contents that need to be set are summarized as follows
$this- > data = array ('azhe'= >' whoami'); $this- > withAttr = array ('azhe'= > []) the conversion class is the trait class, and you need to find the class that uses it. You can summarize it with the Pivot class context as follows: $Model- > lasySave = true;$Model- > exists = true;$Model- > withEvent = false;$Model- > force = true;$Model- > name = new Pivot (); $Model- > data = array (' azhe'= > 'whoami'); $Model- > withAttr = array (' azhe'= > 'system');
TPv5.0 vulnerability
POP chain Windows- > _ destruct ()-- > Windows- > removeFiles ()-- > Model- > _ toString-- > Model- > toJson ()-> Model- > toArray ()-> Output- > _ call-- > Output- > block-- > Output- > writeln-- > Output- > write-> Memcache- > write-> File- > set
First look at the _ _ destruct chain, thinkphp/library/think/process/pipes/Windows.php:56
Follow up removeFiles (), here is the same as TPv5.1, there are also arbitrary file deletions, no longer demonstrate
Take a look at _ _ toString chain, thinkphp/library/think/Model.php:2265
Follow up toJson ()
Follow up toArray (), too much code, intercept key parts
If $value is controllable, you can trigger _ _ call here
Because $this- > append is controllable, $name is controllable when $name is not an array and does not contain. When the code enters line 899, follow up with Loader::parseName ()
That is, $relation can be any string that is lowercase of the first letter.
In lines 900-901 of the code, we can call any method of this class (Model) and assign the result to $modelRelation
Follow up getRelationData () first.
Follow up isSelfRelation ()
Follow up with getModel (), this getModel is the class method of Relation
Its getModel also calls the getModel of $this- > query. Because $this- > query is controllable, it searches getModel () globally and finds two easy-to-use getModel.
Both getModel are $this- > model that directly returns the object, so $modelRelation- > getModel () is controllable.
You can find that $this- > parent is controllable, and if $modelRelation is also controllable, then $value is controllable. Look back at $modelRelation, which is the return value of any Model method we call, look at the method of the Model class, and find a simple and controllable method getError ()
Look further down.
$modelRelation requires the existence of a getBindAttr method, and a global search finds that this method exists only in the abstract class OneToOne, which is also a subclass of Relation. From this point of view, we need to make $modelRelation a subclass of OneToOne. Looking further down, $bindAttr is controllable
At this point, you can easily control $bindAttr to make the code execute to 912 lines.
912 lines, you can look at it this way
$item [key of $bindAttr] = $this- > parent? $this- > parent- > getAttr ($bindAttra [key]): both null,$bindAttr and $this- > parent are controllable
The subclasses of OneToOne are as follows, and $modelRelation can choose one of them.
Since we are going to use the _ _ call method of the Output class, we need to make $this- > parent the Output object
The _ _ toString chain needs to construct the following
Model- > append = array ('4ut15mcm = >' getError'); Model- > error = new BelongsTo (); / / or HasOneModel- > parent = new Output (); OneToOne- > selfRelation = false;OneToOne- > query = new ModelNotFoundException (); OneToOne- > bindAttr = array ('4ut15m'); ModelNotFoundException- > model = new Output ()
Take a look at _ _ call chain, thinkphp/library/think/console/Output.php:208
Line 212, call the block method of the current object, follow up with block ()
Follow up writeln ()
$this- > handle is controllable. Search the write method globally and find Memcache::write.
Where $this- > handler and $this- > config are controllable
Global search for set method and discovery of File::set
Because $this- > options is controllable, $expire is controllable, $name is related to Memcache- > config, semi-controllable, follow up getCacheKey ()
At this point, the path of $filename is controllable, and $name is the value of MD5 that can be determined.
The content written to the file $data consists of $value and $expire, which is uncontrollable and has a value of true. The latter is uncontrollable due to formatting the output. Follow up setTagItem ()
The code calls the set method again on 200 lines, and the write $value is the passed parameter $name, that is, the previous $filename, and the path is partially controllable. Here, you can write to shell through php pseudo protocol php://write, as follows
Php://filter/write=string.rot13/resource=
The _ _ call chain needs to construct the following
Output- > styles = ['getAttr']; Output- > handle = new Memcache (); Memcache- > handler = new File () File- > options = ['expire' = > 0,' cache_subdir' = > false, / / files that can be controlled by false are written under the default path 'prefix' = >', 'path' = >' php://filter/write=string.rot13/resource=', 'data_compress' = > false]; exp
This is the end of the vulnerability analysis on Thinkphp5.0, 5.1,6.x deserialization. I hope the above can be helpful and learn more. If you think the article is good, you can share it for more people to see.
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.