Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP Object Injection Revival

alertot
September 28, 2018

PHP Object Injection Revival

alertot

September 28, 2018
Tweet

More Decks by alertot

Other Decks in Technology

Transcript

  1. PHP Object Injection
    REVIVAL
    Claudio Salazar

    View Slide

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

    View Slide

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

    View Slide

  4. Disclaimer
    I’m not expert in PHP!
    Quick intro

    View Slide

  5. 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

    View Slide

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

    View Slide

  7. 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

    View Slide

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

    View Slide

  9. 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

    View Slide

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

    View Slide

  11. 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

    View Slide

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

    View Slide

  13. 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

    View Slide

  14. 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

    View Slide

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

    View Slide

  16. 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

    View Slide

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

    View Slide

  18. 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 *

    View Slide

  19. Current problem

    View Slide

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

    View Slide

  21. General solution
    Autoloading
    Problem

    View Slide

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

    View Slide

  23. Gadget’s shape

    View Slide

  24. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  30. 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()

    View Slide

  31. 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()

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  36. 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()

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  43. 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()

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  49. Sets
    The array set

    View Slide

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

    View Slide

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

    View Slide

  52. 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

    View Slide

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

    View Slide

  54. Sets
    The iterator set

    View Slide

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

    View Slide

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

    View Slide

  57. 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

    View Slide

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

    View Slide

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

    View Slide

  60. 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

    View Slide

  61. Sets
    The json set

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. 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

    View Slide

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

    View Slide

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

    View Slide

  69. The tool
    POIwer

    View Slide

  70. Architecture
    poiwer

    View Slide

  71. Gadget hints
    poiwer

    View Slide

  72. Exploitation
    poiwer

    View Slide

  73. Download software to analysis
    poiwer

    View Slide

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

    View Slide

  75. Video time
    poiwer

    View Slide

  76. 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

    View Slide

  77. 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

    View Slide

  78. github.com/alertot/poiwer

    View Slide