11

Say that there was a publicly accessible web page with the following PHP code:

<?php
class NotInteresting
{
    public function noExploits() {
        echo "Whatever.";
    }
}
$unsafe = unserialize($_GET['data']);
$unsafe->noExploits();
?>

The code would expect the data URL parameter to contain a serialized instance of NotInteresting, but of course the data parameter can be manipulated. When unserialize() is used on user supplied data it often leads to PHP Object Injection.

However, all the examples of PHP Object Injection I have seen so far (1,2,3) have been dangerous for one of two reasons:

  1. There were some exploitable classes with dangerous methods (which were only meant to be called internally) which were leveraged to execute arbitrary code, often the case for a CMS.
  2. The version of PHP was old or outdated and vulnerabilities in the PHP code were exploited.

Given that the PHP version is current - that is, no known vulnerabilities exist in the unserialize() function - and that there are no custom classes defined (just the default ones - Exception, stdClass etc.), is it possible to leverage the above code for a successful attack on a default PHP installation?

Extra info:

As far as I know there are only four exploitable magic methods when constructing an arbitrary class from an unserialize() call: __call(), __wakeup(), __destruct() and __toString():

  • __wakeup() is called when an object is unserialized.
  • __call() is called when invoking inaccessible methods (or non-existent ones).
  • __destruct() is always called after no more references to the object exist.
  • __toString() is called when an object is treated as a string.

So I wrote a PHP script to quickly generate a list of the classes which contains these magic methods: See here for a pastebin. Some of these look very 'interesting':

  • The XML classes (could lead to XXE)
  • The Phar classes

However I am unable so far to construct an attack just with these: I will need someone more experienced to weigh in.

Awaaaaarghhh
  • 562
  • 2
  • 18
Tryth
  • 215
  • 2
  • 7
  • Which (magic) methods get called depend on how the object is used after deserialization. Anyway, `__destruct` is always called. – Gumbo Jan 06 '15 at 12:05
  • Good point, added. – Tryth Jan 06 '15 at 12:08
  • Again, exploitability depends on the method’s behavior. The other missing magic methods `__get`, `__set`, `__isset`, `__unset`, `__invoke`, `__callStatic`, `__set_state`, and `__clone` as well as any other implemented method that gets called directly or indirectly may provide exploitable behavior. These magic methods are just often the initial trigger of a whole chain of other interactions with the deserialized object. – Gumbo Jan 06 '15 at 12:17
  • @Tryth good question. "Anyway, __destruct is always called", I highly disagree with Gumbo - if you haven't tested it yourself or can't prove your answers - don't answer ;). I tested all possible *magic methods* with all possible builtin classes (I will post my code later here) so no not every builtin class has magic methods implemented. But there is still *PHP's garbage collector* which takes care of unused stuff. I'll break down all answers to "... it seems it is unexploitable, but maybe someone might exploit it ... ". I'll show what I have tested so far, but i was mostly working with phars. – Awaaaaarghhh Sep 07 '19 at 23:49
  • I will link my question on *stackoverflow* here: https://stackoverflow.com/questions/56978005/ My conclusion is that one **require** *magic method(s)* to exploit *unserialize*. If you want to exploit it without magic methods you'll need bugs in *PHP* itself (*use-after-frees* and *buffer-overflows*). – Awaaaaarghhh Sep 07 '19 at 23:55
  • Your question requires some *PHP source code* to answer your question (the point where *unserialize* and *magic methods* start to play together). I will use the latest PHP version for that. – Awaaaaarghhh Sep 08 '19 at 00:02
  • `Phars` and `Sessions` are using *unserialization* too. – Awaaaaarghhh Sep 08 '19 at 00:07

2 Answers2

3

The exploitability of PHP object deserialization depends solely on the available classes (standard classes as well as custom classes), their methods and behavior, and whether it is possible to get one of these exploitable methods triggered.

Note that the exploitable methods may not be that trivial. You may need to create complex object structures using multiple, nested objects to trigger a certain behavior. The number of exploitable methods or their behavior may also change during the time. So even if you may not be able to exploit it today, someone may sometimes be able.

Gumbo
  • 2,003
  • 1
  • 13
  • 17
  • 1
    have you ever tried to exploit it? your answer is far from reality. please look at PHP's source code and test things yourself before you answer someones question. Currently this "answer" is not helpful in any way. You don't need "huge nested structures" you need bugs in PHP itself to exploit. And there were plenty of such bugs in *deserialization context* (session-based, phar-based, unserialize()-based). Magic methods act like triggers on certain PHP functions. Look e.g. at `Phar unserialization` and *file system functions* - here you have only 2 magic methods. – Awaaaaarghhh Sep 08 '19 at 00:22
1

OK, for this to be safe for a particular setup, you would have to be absolutely sure that there are no classes with exploitable behaviour. Given that this likely includes various modules (DB access, whatever), and their behaviour could include "magic methods" like getters or __wakeup(), this is a difficult thing to know fully.

You should also think of your fellow developers/maintainers (including future you). Firstly, they might not remember that they should be writing every class with this security constraint in mind (which seems easy to forget). Secondly the code looks insecure, and it doesn't make sense to constantly have people run over for you to carefully explain how you sanitised every other part of the system to make this particular thing work.

A better plan would be to serialise to/from something like JSON - which is not only safer, but makes your API compatible with other languages as well.

cloudfeet
  • 2,528
  • 17
  • 22
  • I am well aware this is insecure, and would never write code like this: I am just interested, from a purely theoretical point of view, whether there is a demonstrable attack against such a setup. – Tryth Jan 06 '15 at 11:29
  • 2
    A "demonstrable attack" would be "sit back and wait for the programmer to forget something". :p It's like asking about a demonstrable attack on tightrope-walking. – cloudfeet Jan 06 '15 at 11:33
  • Giving the response you're looking for (a YES/NO answer) would require a full review of every object/class PHP uses, presumably including internal ones specific to the VM (at a particular version) - and the fact that so much work would be necessary is kinda an answer in itself. – cloudfeet Jan 06 '15 at 11:35
  • @cloudfeet you're talking like if you would like to help him in his programming lessons. His question is actually about security and if it can be exploited. He didn't ask for any advises to secure his app (like using JSON or something else). This question is purely about exploitability without using PHPs *magic methods*. Of course his code looks insecure because this is part of his question about exploit. Jesus... – Awaaaaarghhh Sep 08 '19 at 00:15
  • Knowing how to break the system will help to secure your app. If this PHP feature exist then it has a use case. – Awaaaaarghhh Sep 08 '19 at 00:24