代码审计：wordpress 3.5.1 远程代码执行漏洞详细分析(结合插件)

Some time ago, I published ablog post describing a PHP Object Injection vulnerability I found in WordPress. At that time, I consciously did not include instructions of how this vulnerability could be exploited. Now, almost three months after the public disclosure of the vulnerability, website administrators have had a reasonable amount of time to update their WordPress installations in order to be secure. Hence, I feel that disclosing an example exploit is acceptable, and will hopefully raise awareness with website administrators that updating (vulnerable) web frameworks is crucial.

Recap

The vulnerability I found in WordPress allowed user-generated content to be passed to PHP’sunserialize()function. This allows an attacker to initialize objects of his choosing, given that the file containing the class definition for the object is included at the time theunserialize()function is called. Furthermore, the attacker can also control the values for the attributes of the initialized object. Except for the initialization of an arbitrary object, an attacker is left with his creativity to make the initialized object do something “special”. This is possible because of PHP’s magic methods. For instance, when an object is unserialized, the object’s__wakeup()magic method is called. Later, when the object has fulfilled its duties and gets destructed, the__destruct()method is called.

O Exploit, Where Art Thou?

As you may have read in my previous post, there were three different magic methods an attacker could use to exploit a WordPress installation, namely__destruct(),__wakeup()and__toString(). The latter is called when PHP requests a string representation of the object, for example when the object isechoed to a web page. In my quest for a working exploit I inspected all WordPress classes that had one of these magic methods. However, I was unable to find one which could lead to a useful exploit.(Side note: if you did manage to find such a class in the WordPress core, I would certainly like to hear about it!)

Now, does this mean that the vulnerability is unexploitable? Of course not, otherwise you wouldn’t be reading this article :-). One of the most popular features about WordPress is that it allows plugins and templates, which are developed by third parties, to be installed. At the time of this writing, WordPress lists 28,358plugins, with over 560 million downloads. These plugins allow you to do “anything you can imagine”. Next to the plugins, there are also 2,155themesavailable, which were downloaded more than 86 million times.

Since I was searching for a class with a “useful” magic method implementation, I decided to take my chances with plugins. For obvious reasons, I started looking in the most popular plugins, and worked my way down. After a quite hard process of going through several plugins, I finally found one that had a class containing an “interesting”__toString()definition. This plugin is calledLightbox Plus ColorBox.

Exploit time

The class of interest in theLightbox Plus ColorBoxplugin is located in the/classes/shd.class.phpfile, more precisely in the definition of thesimple_html_dom_nodeclass. This is what it looks like:

NOTE:Just the essential code fragments are extracted. If you want to look at the full source code of the plugin, please refer to theWordPress plugin repository.

Now, why does this class definition draw our attention? Well… because we can control all properties of asimple_html_dom_nodeobject, we can set the privatedomproperty to an arbitrary value. If this value would happen to contain acallbackproperty, something interesting will happen. In this case, the function located in thecallbackproperty of thedomproperty will be called. The first (and only) argument to this method call is thesimple_html_dom_nodeobject we defined.

This allows us to call an arbitrary function with limited control over the first argument. Limited because we can pick the attributes, but that’s about it. Most likely there is a PHP function out there that allows you to do some cool things, even with these limitations. As I am no PHP expert, I couldn’t come up with something, so I decided to keep on looking. This drove me back to the WordPress core, more precisely to the/wp-admin/includes/screen.phpfile. This file contains a class definition ofWP_Screenand is included when the serialized user-meta data is unserialized. Here is the definition of the class:

As I mentioned in the previous section, we are able to call any arbitrary chosen function. This includes methods of an object. Hence, we can call therender_screen_meta()method of aWP_Screenobject (which takes no arguments). This method will loop over all the elements in the_help_tabsproperty, and if thecallbackproperty of such an element is not empty, it will call the function located in thecallbackproperty with two arguments: theWP_Screenobject and$tab(one of the elements of the_help_tabsproperty).

This gives us a bit more control: we can choose which function is called, and can control (to some extent) the first two arguments. But we may want to look a bit further as we don’t fully control the arguments. This brings us to the/wp-includes/category-template.phpfile of the WordPress core, with following definition:

Thewp_generate_tag_cloud()function takes two arguments:$tagsand$args. The latter is first transformed through thewp_parse_args()function, which merges$argswith an array of default values ($defaults). Directly after that, a number of variables, with names equal to the keys in$args, are created by theextract()function. One of the variables that is created is the$topic_count_scale_callbackvariable. Later on, the value located in this variable is called, given one argument. The good thing here is: we can fully control this variable because we can control the second argument! As for the argument that is given to the function, it appears we can control it as well! The first argument, aWP_Screenobject for example, is cast to an array. When an object is cast to an array in PHP, this results in an associative array where the properties become the keys. See following code snippet:

Now all we need for a working exploit, is a property in theWP_Screenobject that has acountproperty. Of course this is not a problem as we get to pick all attributes of objects that get unserialized. This means that we can call an arbitrary function with one argument, which we can also fully control. And this brings us to Remote Code Execution; thinkshell_exec('echo "schwag" > /tmp/1337h4x0rs').

Putting it all together

With the information provided above, you should be able to create you own über 1337 expl0it! But let me show you what I made of it:

When an attacker sets the output of this script as his user metadata, the shell_exec() function is called with‘echo “schwag” > /tmp/1337h4x0rs’as argument. Note that the output contains NULL bytes because when an object is serialized in PHP its private properties are surrounded by NULL bytes (see PHP manual). Most of the user metadata in WordPress does not allow NULL bytes, except for some that are present by default in version 3.5.1.

Conclusion

This blog post showed an example exploit for the PHP Object vulnerability in WordPress installations before version 3.6.1. The exploit made use of classes defined in theLightbox Plus ColorBoxplugin, which has close to 1 million downloads. By using another class and function definition of the WordPress core, we were able to call an arbitrary function which can be given a value under the control of the attacker. This way, an attacker is capable of executing commands on the vulnerable server. Ohh snap! If you haven’t updated your WordPress installation yet, now would be a good time!