function BootstrapDrupalCacheArrayTestCase::testGadgetChainDrupal7RCE1
Simulate unsafe deserialization of payload prepared by the phpggc project.
See also
https://github.com/ambionics/phpggc/pull/28
File
-
modules/
simpletest/ tests/ bootstrap.test, line 926
Class
- BootstrapDrupalCacheArrayTestCase
- Tests DrupalCacheArray functionality.
Code
public function testGadgetChainDrupal7RCE1() {
// phpggc -s Drupal7/RCE1 phpinfo 2
$payload = 'O:11:"SchemaCache":4:{s:6:"%00*%00cid"%3Bs:14:"form_DrupalRCE"%3Bs:6:"%00*%00bin"%3Bs:10:"cache_form"%3Bs:16:"%00*%00keysToPersist"%3Ba:3:{s:8:"#form_id"%3Bb:1%3Bs:8:"#process"%3Bb:1%3Bs:9:"#attached"%3Bb:1%3B}s:10:"%00*%00storage"%3Ba:3:{s:8:"#form_id"%3Bs:9:"DrupalRCE"%3Bs:8:"#process"%3Ba:1:{i:0%3Bs:23:"drupal_process_attached"%3B}s:9:"#attached"%3Ba:1:{s:7:"phpinfo"%3Ba:1:{i:0%3Ba:1:{i:0%3Bs:1:"2"%3B}}}}}';
$object = unserialize(urldecode($payload));
// The object then needs to be destructed.
unset($object);
// If the exploit was successful, there should now be a row in cache_form.
$payload2 = db_query_range('SELECT data FROM {cache_form} WHERE cid LIKE :cid', 0, 1, array(
':cid' => 'form_DrupalRCE',
))->fetchField();
$this->assertFalse(is_string($payload2) && strpos($payload2, 'phpinfo') !== FALSE, 'Second stage payload was not written to cache_form.');
// The final exploit is executed via the ajax system, but is not a
// sufficiently valid ajax form submission to use drupalPost for testing.
$headers = array(
'Content-Type: application/x-www-form-urlencoded',
);
$curl_options = array(
CURLOPT_URL => url('system/ajax', array(
'absolute' => TRUE,
)),
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => 'form_build_id=DrupalRCE',
CURLOPT_HTTPHEADER => $headers,
);
// The second stage payload causes several PHP warnings / notices if it is
// there in cache_form.
$content = $this->curlExec($curl_options);
$this->assertFalse(strpos($content, 'Rasmus Lerdorf') !== FALSE, 'Remote Code Execution was not successful.');
// Now opt-out of the cache_form protection.
variable_set('drupal_cache_array_persist_cache_form', TRUE);
$object = unserialize(urldecode($payload));
// The object then needs to be destructed.
unset($object);
// If the exploit was successful, there should now be a row in cache_form.
$payload2 = db_query_range('SELECT data FROM {cache_form} WHERE cid LIKE :cid', 0, 1, array(
':cid' => 'form_DrupalRCE',
))->fetchField();
$this->assertTrue(is_string($payload2) && strpos($payload2, 'phpinfo') !== FALSE, 'DrupalCacheArray persisted data to cache_form.');
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.