desc
语句:准备并编写基础描述
在学习编写 SyntaxFlow 规则之前,为了方便用户理解使用,我们使用 XXE 这个漏洞来进行教学,用户可以在手动实现对这个漏洞的分析检测过程中,掌握 SyntaxFlow 的编写技术。
准备要审计的代码
我们将存在 XXE 漏洞的 Java 代码保存为 XXE.java
,并将其存放在相应的包中。
package com.vuln.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@RestController(value = "/xxe")
public class XXEController {
@RequestMapping(value = "/one")
public String one(@RequestParam(value = "xml_str") String xmlStr) throws Exception {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(xmlStr.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
return "Hello World";
}
}
这段代码位于一个使用 Spring Framework 构建的 Web 应用中,定义了一个处理 XML 数据的控制器 XXEController
。控制器中的 one
方法用来处理通过 HTTP 请求传递的 XML 字符串。以下是代码的具体行为和存在的安全问题:
代码解释
-
@RestController(value = "/xxe")
注解定义了一个 RESTful 控制器,其所有请求的基础 URL 是/xxe
。 -
@RequestMapping(value = "/one")
注解表明,one
方法将处理对/xxe/one
的 HTTP 请求。 -
方法
one
接收请求参数
方法one
接收一个名为xml_str
的请求参数,这个参数通过@RequestParam
注解获得。这个参数预期包含 XML 格式的数据。 -
创建
DocumentBuilder
实例
DocumentBuilderFactory.newInstance().newDocumentBuilder()
创建了一个DocumentBuilder
实例,用于解析 XML 数据。 -
创建
InputStream
new ByteArrayInputStream(xmlStr.getBytes("UTF-8"))
创建了一个InputStream
,它从传入的字符串xml_str
中读取数据。 -
解 析 XML 数据
documentBuilder.parse(stream)
解析这个流,尝试构建一个 DOM 树。 -
规范化文档结构
doc.getDocumentElement().normalize()
规范化文档结构,确保 DOM 树的结构正确。
存在的 XXE 漏洞
这段代码存在 XML 外部实体 (XXE) 漏洞,原因如下:
-
默认的解析器设置
DocumentBuilderFactory
的默认配置不禁用外部实体的处理。这意味着如果 XML 输入包含对外部实体的引用,解析器将尝试解析这些实体。 -
安全风险
攻击者可以利用 XML 输入中的外部实体,引导服务器解析恶意内容。例如,攻击者可能会引入指向敏感文件(如/etc/passwd
)的实体,导致敏感信息泄露。此外,恶意的外部实体还可以用来触发拒绝服务攻击(DoS)等。
编译源码
进入 XXE.java
所在的目录,执行以下命令即可编译:
yak ssa -t . --program xxe
编译完成后,你将会在输出中看到以下日志,看到 finished compiling
则说明编译完成了。
[INFO] 2024-06-26 11:52:38 [ssacli:132] start to compile file: .
[INFO] 2024-06-26 11:52:38 [ssacli:148] compile save to database with program name: xxe
[INFO] 2024-06-26 11:52:38 [ssa:42] init ssa database: /Users/v1ll4n/yakit-projects/default-yakssa.db
[INFO] 2024-06-26 11:52:38 [language_parser:46] parse project in fs: *filesys.LocalFs, localpath: .
[INFO] 2024-06-26 11:52:38 [language_parser:152] file[XXE.java] is supported by language [java], use this language
[WARN] 2024-06-26 11:52:38 [visit_package:31] Dependencies Missed: Import package [org.springframework.web.bind.annotation.RequestMapping] but not found
...
...
...
[INFO] 2024-06-26 11:52:38 [language_parser:68] compile XXE.java cost: 194.70225ms
[INFO] 2024-06-26 11:52:38 [language_parser:72] program include files: 2 will not be as the entry from project
[WARN] 2024-06-26 11:52:38 [reducer:51] Compile error: parse file xxe.sf error: file[xxe.sf] is not supported by any language builder, skip this file
[INFO] 2024-06-26 11:52:38 [ssacli:163] finished compiling..., results: 1
编写描述
在大致了解了 SF 规则文 件之后,我们可以开始构建自己的 SF 文件。首先,创建一个名为 xxe.sf
的文件,并在文件中写入以下内容:
desc(title: "审计因为未设置 setFeature 等安全策略造成的XXE漏洞")
显然,这段代码仅仅添加了一点文件描述信息,并不会产生实际的审计效果。然而,添加描述有助于在结果输出时包含对结果的解读信息,因此仍然是非常必要的。
SPEC:语句 desc
// descriptionStatement 将使用 stringLiteral 描述 filterExpr
descriptionStatement: Desc ('(' descriptionItems? ')') | ('{' descriptionItems? '}');
descriptionItems: descriptionItem (',' descriptionItem)*;
descriptionItem
: stringLiteral
| stringLiteral ':' stringLiteral
;
在 SyntaxFlow
规则文件中,desc
语句用于为规则提供描述性的文本,这有助于理解规则的目的和应用场景。此语句可以包含一条或多条描述项,这些项可以单独列出或配对(键和值)。下面是关于如何编写 desc
语句的详细教程,以及如何通过案例来实际应用这些语句。