Slide 1

Slide 1 text

PHP Object Injection REVIVAL Claudio Salazar

Slide 2

Slide 2 text

Whois ● CEO and co-founder @alertot ● Founder @spect.cl ● Open-source contributor

Slide 3

Slide 3 text

Agenda ● Quick intro to serialization ● Current problem ● Gadgets' shape ● poiwer, the tool

Slide 4

Slide 4 text

Disclaimer I’m not expert in PHP! Quick intro

Slide 5

Slide 5 text

What is serialization? ● Serialization was thought to transport objects. ● It creates a string representation of any data type. ● Deserialization is the inverse process. Quick intro

Slide 6

Slide 6 text

Equation $variable <-> unserialize(serialize($variable)); (most cases) Quick intro

Slide 7

Slide 7 text

Problem The problem happens when a program unserializes untrusted data. In a normal flow, the program expects to create X but eventually creates Z. Quick intro

Slide 8

Slide 8 text

Exploitation It’s called PHP Object Injection (POI). The exploitation is carried out through Property-oriented Programming (PoP). Quick intro

Slide 9

Slide 9 text

Property-oriented Programming ● It reuses classes available in the project. ● Classes with interesting methods are the gadgets. ● Interesting methods are driven by controlled data. ● The goal is to chain objects to achieve something. Quick intro

Slide 10

Slide 10 text

Magic methods Methods with magic powers, according to PHP documentation. The two more famous in POI are: 1. __destruct() 2. __wakeup()

Slide 11

Slide 11 text

Example 1/5 class Writer { public $data; function save($filename) { file_put_contents($filename, $this->data); } } class Document { public $filename; public $handler; function __destruct() { $this->handler->save($this->filename); } } Quick intro Both classes are part of the app

Slide 12

Slide 12 text

Example 2/5 $w = new Writer; $w->data = 'hello'; $m = new Document; $m->filename = '/tmp/file'; $m->handler = $w; Quick intro

Slide 13

Slide 13 text

Example 3/5 class Writer { public $data = ‘hello’; function save($filename) { file_put_contents($filename, $this->data); } } class Document { public $filename = ‘/tmp/file’; public $handler = new Writer; function __destruct() { $this->handler->save($this->filename); } } Quick intro

Slide 14

Slide 14 text

Example 4/5 $serializedData = serialize($m); O:8:"Document":2:{ s:8:"filename";s:9:"/tmp/file"; s:7:"handler";O:6:"Writer":1:{ s:4:"data";s:5:"hello"; } } Quick intro

Slide 15

Slide 15 text

Example 5/5 unserialize($serializedData); $ cat /tmp/file hello Quick intro

Slide 16

Slide 16 text

Clarifications ● We work only with available classes (no code creation). ● We can set any kind of property in class. ● Distinction between data and functions. Quick intro

Slide 17

Slide 17 text

Exploitation methods * (https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are) Quick intro unserialize function phar files *

Slide 18

Slide 18 text

Exploitation methods * (https://blog.secarma.co.uk/labs/near-phar-dangerous-unserialization-wherever-you-are) **(https://www.evonide.com/how-we-broke-php-hacked-pornhub-and-earned-20000-dollar/) Quick intro - Serialized string - Exploit unserialize() function ** unserialize function phar files *

Slide 19

Slide 19 text

Current problem

Slide 20

Slide 20 text

Motivation $request = unserialize($myData); $request = other_function($request['green']); Problem

Slide 21

Slide 21 text

General solution Autoloading Problem

Slide 22

Slide 22 text

Solution to motivation Find what Wordpress plugins must be present to turn the deserialization exploitable. Problem

Slide 23

Slide 23 text

Gadget’s shape

Slide 24

Slide 24 text

Example explanation 1. class ExpectedClass { carrot } 2. $instance = new ExpectedClass; 3. $my_data = serialize($instance); 4. $obj = unserialize($my_data); 5. some operation on carrot! Gadget’s shape

Slide 25

Slide 25 text

Magic methods 102 Magic methods are more than __destruct() and __wakeup(), let’s go to find other gems! Magic methods

Slide 26

Slide 26 text

Definition __get() is utilized for reading data from inaccessible properties. Magic methods - __get()

Slide 27

Slide 27 text

Use case $obj = unserialize($my_data); $attrib = $obj->carrot; Magic methods - __get()

Slide 28

Slide 28 text

Expected class class ExpectedClass { public $carrot = 123; } Magic methods - __get()

Slide 29

Slide 29 text

Unexpected class class UnexpectedClass { // no $carrot public attribute function __get($key = ‘carrot’) { [...] } } Magic methods - __get()

Slide 30

Slide 30 text

Real-world example (1/2) class ValidGenerator { public function __get($attribute) { return $this->__call($attribute, array()); } } * fzaninotto/faker/src/Faker/ValidGenerator.php Magic methods - __get()

Slide 31

Slide 31 text

Real-world example (2/2) public function __call($name, $arguments){ do { $res = call_user_func_array( array($this->generator, $name), $arguments ); [...] } while (!call_user_func($this->validator, $res)); } * fzaninotto/faker/src/Faker/ValidGenerator.php Magic methods - __get()

Slide 32

Slide 32 text

__set method __set() is run when writing data to inaccessible properties. Magic methods

Slide 33

Slide 33 text

Use case $obj = unserialize($my_data); $obj->carrot = 123; Magic methods - __set()

Slide 34

Slide 34 text

Expected class class ExpectedClass { public $carrot; } Magic methods - __set()

Slide 35

Slide 35 text

Unexpected class class UnexpectedClass { // no $carrot public attribute function __set( key = ‘carrot’, $value = ‘123’) { [...] } } Magic methods - __set()

Slide 36

Slide 36 text

Real-world example class CI_Session { public function __set($key, $value) { $_SESSION[$key] = $value; } } * CodeIgniter-3.1.9/system/libraries/Session/Session.php Magic methods - __set()

Slide 37

Slide 37 text

Similar magic methods __isset($key) -> isset() or empty() __unset($key) -> unset() Magic methods

Slide 38

Slide 38 text

__call method __call() is triggered when invoking inaccessible methods in an object context. Almost the same for __callStatic(). Magic methods

Slide 39

Slide 39 text

Use case $obj = unserialize($my_data); $obj->carrot(); Magic methods - __call()

Slide 40

Slide 40 text

Expected class class ExpectedClass { public function carrot() { return ‘hello’; } } Magic methods - __call()

Slide 41

Slide 41 text

Unexpected class class UnexpectedClass { public function carrot() { return ‘bye’; } } Magic methods - __call()

Slide 42

Slide 42 text

Unexpected class class UnexpectedClass { // no carrot method public function __call($key = ‘carrot’, $args) { [...] } } Magic methods - __call()

Slide 43

Slide 43 text

Real-world example class TraceableEventDispatcher { public function __call($method, $arguments) { return \call_user_func_array( array($this->dispatcher, $method), $arguments ); } } * symfony/event-dispatcher/Debug/TraceableEventDispatcher.php Magic methods - __call()

Slide 44

Slide 44 text

Definition __toString() method allows a class to decide how it will react when it is treated like a string. Magic methods - __toString()

Slide 45

Slide 45 text

Use case $obj = unserialize($my_data); echo $obj; Magic methods - __toString()

Slide 46

Slide 46 text

Expected value $carrot = ‘hello’; Magic methods - __toString()

Slide 47

Slide 47 text

Unexpected class class UnexpectedClass { public function __toString() { return ‘bye’; } } Magic methods - __toString()

Slide 48

Slide 48 text

Sets Sets are related gadgets given by the use of an interface or class.

Slide 49

Slide 49 text

Sets The array set

Slide 50

Slide 50 text

Scenario The program thinks it’s working on a normal array. The array set

Slide 51

Slide 51 text

Foundations The ArrayAccess interface Interface to provide accessing objects as arrays. Also found in: ArrayObject class. The array set

Slide 52

Slide 52 text

Cases $theArray = unserialize($my_data); $v = $theArray[$key]; offsetGet($key) $theArray[$key] = 1; offsetSet($key, value) empty($theArray[$key]); offsetExists($key) unset($theArray[$key]); offsetUnset($key) The array set

Slide 53

Slide 53 text

Caution It’s not a real array. The array set

Slide 54

Slide 54 text

Sets The iterator set

Slide 55

Slide 55 text

Scenario The program thinks it’s working on a normal array. The iterator set

Slide 56

Slide 56 text

Case $theArray = unserialize($my_data); foreach($theArray as $element) {...} The iterator set

Slide 57

Slide 57 text

Foundations The Traversable interface Interface to detect if a class is traversable using foreach. Also found in: Iterator, IteratorAggregate interfaces and ArrayObject class. The iterator set

Slide 58

Slide 58 text

Gadget #1 class Example implements Iterator { function current () {...} function key () {...} function next () {...} function rewind () {...} function valid () {...} } The iterator set

Slide 59

Slide 59 text

Gadget #2 class Example implements IteratorAggregate { function getIterator () {...} } The iterator set

Slide 60

Slide 60 text

Real-world example: Symfony Console class TableRows implements \IteratorAggregate { public function getIterator() { $g = $this->generator; return $g(); } } * symfony/console/Helper/TableRows.php The iterator set

Slide 61

Slide 61 text

Sets The json set

Slide 62

Slide 62 text

Scenario The program encodes a variable as a JSON string. The json set

Slide 63

Slide 63 text

Case $obj = unserialize($my_data); $jsonString = json_encode($obj); The json set

Slide 64

Slide 64 text

Foundations The JsonSerializable interface Can customize their JSON representation when encoded with json_encode(). The json set

Slide 65

Slide 65 text

Gadget class Example implements JsonSerializable { function jsonSerialize () {...} } The json set

Slide 66

Slide 66 text

Real-world example: CakePHP Mailer class Email implements JsonSerializable, Serializable { public function jsonSerialize() { array_walk($array['_attachments'], function (&$item, $key) { if (!empty($item['file'])) { $item['data'] = $this->_readFile($item['file']); unset($item['file']); } }); } } * cakephp/cakephp/src/Mailer/Email.php The json set

Slide 67

Slide 67 text

Additional sets ● Serializable interface & unserialize() ● new statement & __construct() ● Countable interface & count()

Slide 68

Slide 68 text

Additional ideas ● Combine seen gadgets as you want ● Gadgets chaining in an array

Slide 69

Slide 69 text

The tool POIwer

Slide 70

Slide 70 text

Architecture poiwer

Slide 71

Slide 71 text

Gadget hints poiwer

Slide 72

Slide 72 text

Exploitation poiwer

Slide 73

Slide 73 text

Download software to analysis poiwer

Slide 74

Slide 74 text

Editor ● Focused on gadget chains building ● Uses the same PHP parser as actual editors ● Creates phpggc-ish gadgets poiwer

Slide 75

Slide 75 text

Video time poiwer

Slide 76

Slide 76 text

Generated code 1/2 namespace GuzzleHttp\Cookie; class SetCookie { private $data = ['Expires' => 1, 'Discard' => 0, 'Data' => "injection"]; public function __construct($data) { $this->data = $data; } } poiwer

Slide 77

Slide 77 text

Generated code 2/2 class CookieJar { private $cookies = [new SetCookie]; public function __construct() { } } class FileCookieJar extends CookieJar { private $filename = "injection"; public function __construct($filename) { $this->filename = $filename; } } poiwer

Slide 78

Slide 78 text

github.com/alertot/poiwer