0x01.技术文章仅供参考学习,请勿使用本文中所提供的任何技术信息或代码工具进行非法测试和违法行为。若使用者利用本文中技术信息或代码工具对任何计算机系统造成的任何直接或者间接的后果及损失,均由使用者本人负责。本文所提供的技术信息或代码工具仅供于学习,一切不良后果与文章作者无关。使用者应该遵守法律法规,并尊重他人的合法权益。蓝凌EKP由深圳市蓝凌软件股份有限公司自主研发,是一款全程在线数字化OA,应用于大中型企业在线化办公,包含流程管理、知识管理、会议管理、公文管理等等。蓝凌0A的thirdImSyncForKKWebService接口存在任意文件读取漏洞。攻击者可利用漏洞获取系统敏感信息。最近比较闲也好久没写公众号了近期可能会陆陆续续的更新漏洞或者漏洞分析。web.icon=="302464c3f6207d57240649926cfc7bd4"
漏洞位置是在ThirdImSyncForKKWebService.java中,漏洞类型是webservice soap类型的。以下代码分析均为个人对代码的理解如有分析不对的还请多担待。
前面很简单就是RequestMapping({"/getTodo"})
该注解用于将 HTTP 请求映射到方法上,当访问/getTodo
路径时,会调用getTodo
方法。然后NotifyTodoAppResult result = new NotifyTodoAppResult();
创建一个NotifyTodoAppResult
对象result
,该对象会存储操作的结果,并作为返回值。然后就if判断是否为空值。
接下来是String whereBlock= "";
初始化一个空字符串whereBlock
,用于构建查询的条件部分。HQLInfo info = new HQLInfo();
创建一个HQLInfo
对象info
,该对象可能包含了 HQL 查询所需的信息。List<HQLParameter> paramList = new ArrayList();
创建一个空的paramList
列表,用来存储查询条件的参数。
剩余的不重要直接跳到重点,根据前面的代码可以判断出如果type
不是13
执行以下代码。whereBlock = whereBlock + this.getTodoSqlBlock("type", type, paramList);
调用getTodoSqlBlock
方法,传入"type"
、type
和paramList
,向whereBlock
添加对应的 SQL 查询条件。
whereBlock = whereBlock + this.getTodoSqlBlock("type", type, paramList);
我们开始追踪this.getTodoSqlBlock方法,代码如下
getTodoSqlBlock方法中调用了keyword,value,hqlParam参数,而hqlParam参数是用于存储查询条件参数的列表HQLParameter用于动态构建 HQL 查询的参数。然后调用了第二个重载方法getTodoSqlBlock。
private String getTodoSqlBlock(String keyword, Object value, List
hqlParam) {
return this.getTodoSqlBlock(keyword, value, "=", keyword, hqlParam);
}
在这段代码中我们需要重点关注是hqlParam.add(new HQLParameter(extendKey, value)); 向hqlParam列表中添加一个新的HQLParameter对象,extendKey作为参数的名字,value作为参数的值。我们追踪HQLParameter。
private String getTodoSqlBlock(String keyword, Object value, String optStr, String extendKey, List
hqlParam) {
hqlParam.add(new HQLParameter(extendKey, value));
String key = keyword.substring(0, 1).toUpperCase() + keyword.substring(1);
return " and sysNotifyTodo.fd" + key + optStr + ":" + extendKey;
}
public HQLParameter(String name, Object value) {
this.name = name;
this.value = value;
}
这个构造函数的作用是创建一个HQLParameter对象,并初始化它的 name和value属性。HQLParameter类通常用于表示HQL(Hibernate Query Language)查询中的参数,在查询构建时使用,在这里可能包含查询的字段名name和该字段的值value。这个类动态构建查询条件时能够方便地传递参数。
到这里可能大家会觉得这个webservice接口不就是HQL查询嘛,别急我们接着往下走。根据刚才的分析type是由POST请求中嵌入了文件路径的参数引发的而后从代码逻辑来看type参数被传递给方法this.getTodoSqlBlock构造了HQL查询的一部分。这些最终的触发点是调用了page=this.sysNotifyTodoService.findPage(info);来触发查询。最终是HQL查询与ORM框架的处理,代码中使用了HQL(Hibernate Query Language)查询,whereBlock中包含了攻击者传入的参数type。ORM 框架(如 Hibernate 或 JPA)处理参数时可能会尝试对 file:// URI 进行解析。这种行为通常发生在以下场景:
类型转换:
框架可能会将 file:// 参数作为 URI 类型或资源类型进行解析。
如果 fdType 是与文件、资源或流相关的字段(如 Blob、Clob 等),框架可能会尝试加载对应资源。
扩展功能:
某些 ORM 框架支持使用 URI 直接指向文件或资源(通常用于存储外部文件路径)。
这类功能会隐式调用 Java 的 URL.openStream() 或 Files.newInputStream(),从而加载远程资源或本地文件。
由于本身webservice走的是soap协议,这里使用到了xop:IncludeSOAP 的 XOP 扩展:
xop:Include 是 SOAP 附件优化机制(XML-binary Optimized Packaging)。
如果服务器端 SOAP 框架支持 XOP,并未禁用 file:// 协议,它可能会尝试解析 href 指向的文件内容。
触发条件:
如果服务器端解析 SOAP 的 type 字段时,遇到 xop:Include 的 href 属性,会调用底层的 URI 解析方法(如 new URL().openStream()),加载指定文件。
第一步:入口点是getTodo,用户通过请求体传入type参数。该参数通过this.getTodoSqlBlock方法构造HQL查询条件,最终被拼接到whereBlock中。
第二步:构造HQL查询条件getTodoSqlBlock方法被调用,用户传入的type添加到hqlParam中。
第三步:HQL查询被执行 page=this.sysNotifyTodoService.findPage(info);
第四步:文件解析触发,解析过程使用SOAP框架的xop:Include协议ORM 框架。
那么也就是说最终触发漏洞的是soap中包含了xop:Include标签,也就是我可以在poc中的任意位置插入paylaod,但是能够被解析的前提是代码中必须存在查询或处理逻辑,能够解析并利用传入的参数内容。
0x05 漏洞复现
根据以上代码分析的结果构造poc如下,参数是type,回显是base64的然后解码就行
刚才根据代码分析也得知不是只有type这一处能够解析,我们尝试别的参数也可以正常文件读取。
阅读原文:https://mp.weixin.qq.com/s/t2KQOe3aGex5CPwa6kNFPg
该文章在 2024/12/19 17:43:36 编辑过