• Java代码审计安全篇-XXE(XML外部实体注入)漏洞


    前言:

     堕落了三个月,现在因为被找实习而困扰,着实自己能力不足,从今天开始 每天沉淀一点点 ,准备秋招 加油

    注意:

    本文章参考qax的网络安全java代码审计,记录自己的学习过程,还希望各位博主 师傅 大佬 勿喷,还希望大家指出错误

    XXE 漏洞:

    原理:当应用程序解析XML输入时,再没有禁用外部实体的加载而导致加载 了外部文件及代码时,就会造成XXE漏洞

    利用方式:攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件),导致可加载恶意外部文件,利用file协议造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。

    危害:任意文件读取,内网探测,攻击内网站点(结合SSRF),命令执行 ,dos攻击

    XML (参考webgoat)

    什么是 XML 实体?

    XML 实体允许定义标记,在分析 XML 文档时,这些标记将被内容替换。通常有三种类型的实体:

    • 内部实体

    • 外部实体

    • 参数实体。

    必须在文档类型定义 (DTD) 中创建一个实体,让我们从一个示例开始:

      正如你所看到的,一旦XML文档被解析器处理,它就会用定义的常量“Jo Smith”替换定义的实体。正如你所看到的,这有很多优点,因为你可以在一个地方更改为例如“约翰史密斯”。js js

    在 Java 应用程序中,XML 可用于将数据从客户端获取到服务器,我们都熟悉 JSON API,我们也可以使用 xml 来获取信息。大多数情况下,框架会根据 xml 结构自动填充 Java 对象,例如:

    例子:

    让我们看一个 XXE 注入的例子,在上一节中我们看到 XML 实体可以按如下方式使用:

    1. ]>
    2. &js;
    外部 DTD 声明

    定义这些实体还可以在外部文件中定义另一个 DTD,例如:

    1. webgoat@webgoat.org
    2. webwolf@webwolf.org
    3. Your app is great, but contains flaws
    4. Hi, your application contains some SQL injections

    可以定义如下:email.dtd

    如果 XML 解析器配置为允许外部 DTD 或实体,则可以使用以下命令更改以下 XML 代码片段:

    1. ]>
    2. &js;

    现在会发生什么?我们从本地文件系统定义了一个包含,XML 解析器将加载文件,并将在引用实体的任何位置添加内容。假设 XML 消息返回给用户,该消息将是:

    额外的文档类型定义 (DOCTYPE) 是您始终可以添加到 xml 文档中的内容,如果启用了解析器设置以允许处理外部实体,则查找 XXE 注入的良好开端。

    靶场训练 

    我们直接进入靶场环境

    1. 参考Drunkbaby师傅审计思路

    我们随便输入一个评论然后抓包得到:

    它会直接会被处理为XML数据,并且经过测试发现没有进行任何的检查或者过滤,reponse返回sorry,意思就是失败那根据这个,我们可以将xml数据中添加XML entity,并采用file:///的方式获取根目录的文件(linux系统就可以读取/etc/passwd等)

    paylaod:

    "1.0"?>root [root SYSTEM "file:///C:/">]><comment><text>&root;text>comment>

     其中root可以换成其他字符串,但是不要违反XML的命名要求。得到下面就说明成功

    这时候c盘文件目录全部被读取泄露 

    我们审计一下源代码 

    1. @PostMapping(path = "xxe/simple", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
    2. @ResponseBody
    3. public AttackResult createNewComment(HttpServletRequest request, @RequestBody String commentStr) {
    4. String error = "";
    5. try {
    6. var comment = comments.parseXml(commentStr);
    7. comments.addComment(comment, false);
    8. if (checkSolution(comment)) {
    9. return success(this).build();
    10. }
    11. } catch (Exception e) {
    12. error = ExceptionUtils.getStackTrace(e);
    13. }
    14. return failed(this).output(error).build();
    15. }

    我们主要看下面代码

    1. var comment = comments.parseXml(commentStr);
    2. //var comment = comments.parseXml(commentStr);: 解析传入的XML字符串commentStr,并将结果存储在名为comment的变量中。这里使用了一个名为comments的对象(类型未知)的parseXml方法来执行解析操作。

    跳转到 Comments.parseXml 去,主要描述了 parseXml 如何处理 commentStr。 

    关注下面两行

    1. var jc = JAXBContext.newInstance(Comment.class);
    2. var xif = XMLInputFactory.newInstance();
    • 前置知识:JAXB 作为 JDK 的一部分,能便捷地将 Java 对象与 XML 进行相互转换。
    • JAXBContext 是整个 JAXB API 的入口。主要用来构建 JAXB 实例newInstance()
    • Marshaller接口,将Java对象序列化为XML数据。
    • Unmarshaller接口,将XML数据反序列化为Java对象。

    接下来要讲的是产生 XXE 的代码块原因

    1. var unmarshaller = jc.createUnmarshaller();
    2. return (Comment) unmarshaller.unmarshal(xsr);

    此处创建一个 Unmarshaller 对象。返回的值是 XML 经过unmarshal 方法处理的值。由于 unmarshal 在执行过程中解析了 XML(这里类似于反序列化的意思),导致 XXE 注入。

    当把 XML 格式的字符串传递给 Unmarshaller 接口转变成 Java 对象时,会解析一遍 XML,如果传入的值可控就会导致 XXE 注入攻击。

    将接受的XML格式评论解析为评论的对象

    1. comments.addComment(comment, false);//将解析后的评论对象comment添加到名为comments的对象(类型未知)中,以便将其保存到评论列表中。第二个参数false表示该评论不是管理员评论。
    2. if (checkSolution(comment)) {
    3. return success(this).build();
    4. }

    就是这里就没对接受的参数进行过滤或者禁用 就直接开始进行check,然后攻击者就可以构造恶意的代码进行攻击

    2. REST框架XXE

    我们也继续输入1得到

    抓包发现 发送的请求不是xml格式 而是json格式 

    我们修改为json格式得到报错 

    根据XML解析器的不同,您可能会得到更好的错误消息,在这种情况下,消息有点神秘,这意味着我们没有发送有效的xml。

     我们使用上一关的paylaod继续读取C盘

    成功读取C盘内容 

    审计:

    ContentTypeAssignment.java

    1. public AttackResult createNewUser(
    2. HttpServletRequest request,
    3. @RequestBody String commentStr,
    4. @RequestHeader("Content-Type") String contentType) {
    5. AttackResult attackResult = failed(this).build();
    6. if (APPLICATION_JSON_VALUE.equals(contentType)) {
    7. comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true));
    8. attackResult = failed(this).feedback("xxe.content.type.feedback.json").build();
    9. }
    10. if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {
    11. String error = "";
    12. try {
    13. Comment comment = comments.parseXml(commentStr);
    14. comments.addComment(comment, false);
    15. if (checkSolution(comment)) {
    16. attackResult = success(this).build();
    17. }
    18. } catch (Exception e) {
    19. error = ExceptionUtils.getStackTrace(e);
    20. attackResult = failed(this).feedback("xxe.content.type.feedback.xml").output(error).build();
    21. }
    22. }
    23. return attackResult;

    并没有对Content-Type 进行严格的过滤。 然后也是使用了parsexml函数 跟上提一样

    3.XXE DOS攻击

    使用相同的 XXE 攻击,我们可以对服务器执行 DOS 服务攻击。此类攻击的一个例子是:

    1. "1.0"?>
    2. lolz [
    3. lol "lol">
    4. lolz (#PCDATA)>
    5. lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
    6. lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
    7. lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
    8. lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
    9. lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
    10. lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
    11. lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
    12. lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
    13. lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
    14. ]>
    15. <lolz>&lol9;lolz>

    当 XML 解析器加载此文档时,它会看到它包含一个根元素“lolz”,其中包含文本“&lol9;”。但是,“&lol9;”是一个已定义的实体,它扩展为包含十个“&lol8;”字符串的字符串。每个“&lol8;”字符串都是一个定义的实体,可扩展为十个“&lol7;”字符串,依此类推。在处理完所有实体扩展后,这个小的(< 1 KB)的 XML 块实际上将占用近 3 GB 的内存。

    修复(参考百度开发者中心):

    1. 验证输入数据:对所有输入数据进行严格的验证和过滤,确保没有恶意的内容被注入到应用程序中。对所有用户输入进行适当的验证和清理,可以有效地防止攻击者利用XXE漏洞进行攻击。
    2. 禁用外部实体引用:在处理XML数据时,禁用或限制对外部实体的引用。这可以通过配置XML解析器来实现,确保应用程序不会加载外部实体,从而减少被攻击的风险。
    3. 使用安全的XML解析器:选择经过安全加固的XML解析器,并遵循最佳实践来使用它们。这些解析器通常具有内置的安全功能,能够检测和防范XXE攻击。
    4. 限制实体大小:设置合理的实体大小限制,防止攻击者通过大量数据来耗尽资源或触发拒绝服务攻击。
    5. 日志记录和监控:启用详细的日志记录和监控机制,以便及时发现和响应任何可疑的活动。通过监控应用程序的行为和异常模式,可以快速检测并应对潜在的XXE攻击。
    6. 定期更新和维护:保持系统和应用程序的最新状态,及时修复已知的安全漏洞。定期更新和维护可以确保您的系统不受最新的XXE攻击威胁。
    7. 安全培训和意识提升:对开发人员和运维人员进行安全培训,提高他们对XXE漏洞的认识和防范意识。只有当整个团队都意识到安全问题并采取相应的防护措施时,才能更有效地防止XXE攻击。
    8. 使用Web应用防火墙WAF:部署一个有效的Web应用防火墙可以提供额外的防护层,监测并阻止恶意请求和已知的攻击模式。WAF可以帮助识别并拦截包含XXE漏洞的恶意请求,保护应用程序免受攻击。
    9. 代码审查和安全测试:实施严格的代码审查和安全测试流程,确保应用程序在开发阶段就避免了潜在的安全风险。通过专业的安全测试工具和团队,可以检测出应用程序中存在的XXE漏洞以及其他安全问题。
    10. 数据加密和保护:对敏感数据进行加密存储和传输,降低数据泄露的风险。即使攻击者能够利用XXE漏洞获取敏感信息,加密措施也可以使数据难以被利用。

    源码地址

     https://github.com/WebGoat/WebGoat/tree/main/src/main/java/org/owasp/webgoat/lessons/xxe

  • 相关阅读:
    SpringCloud Alibaba微服务第5章之Gateway
    Leetcode刷题详解——子集
    单流 TCP 100Gbps+ 难题的直观解释
    常用的表格检测识别方法 - 表格区域检测方法(下)
    Web3小知识集锦
    Centos7 安装Mysql 8.0.30
    数据库连接池的概念和原理
    每日4道算法题——第001天
    vscode 创建 运行c++ 项目
    2024年申报国自然项目基金撰写及技巧
  • 原文地址:https://blog.csdn.net/m0_63138919/article/details/136721527