跳到主要内容

规则文件结构

在使用 SyntaxFlow 技术过程中,理解规则文件(.sf 文件)的结构至关重要。这些文件包含特定的语句和表达式,用于定义如何在代码中搜索特定模式和行为。本章节将通过几个实际案例来展示规则文件的编写方法,并解释每个组成部分的功能和作用。

在后面的叙述中,我们通常将 SyntaxFlow 规则简称为 SF 文件 或 SF 规则。

规则的四个组成部分​

SF 规则文件的结构通常遵循以下模式:

  • 描述性说明 desc:提供规则的概览和目的。
  • 审计语句:定义特定的代码模式或行为来捕捉和分析。
    • 过滤器:通过条件表达式过滤和选择代码的特定部分。
    • 变量命名 as:用于后续引用的结果命名。
  • 条件检查 check:根据审计语句的结果来断言和输出相应的信息。
  • 结果报告 alert: alert 来通知报告生成器或前端(IRify)需要重点关注的或者存在漏洞的变量信息。

注意:虽然 desc 和 check 并非必须,但我们强烈建议在编写规则时包含这两个语句,以便让规则的输出更易于理解。在上述所有的内容中,审计语句 是最核心的部分。

阅读规则时,应先找出查询定位了什么,再检查过滤与追踪条件,最后确认哪些结果被报告。desc 说明规则的意图,check 解释匹配状态,alert 将关注的值交给报告流程;它们的作用不能互相替代。


规则案例与阅读方法​

XXE 漏洞检测规则 (xxe.sf)​

desc(
title: "Check XXE Vulnerability in DocumentBuilderFactory",
title_zh: "检查 DocumentBuilderFactory 中的 XXE 漏洞",
risk:XXE,
type:Vulnerability,
desc: <<<TEXT
该规则旨在检查 Java 中 DocumentBuilderFactory 的使用是否存在 XXE 漏洞。XXE(XML External Entity)漏洞可能导致敏感信息泄露或远程代码执行。通过确保 DocumentBuilderFactory 实例未设置危险特性,可以防止此类攻击。
TEXT
solution: <<<TEXT
复核解析器的外部实体与 DTD 配置,根据所使用的实现明确限制不需要的外部访问。仅检查是否调用过配置方法,不能判断参数值及最终配置是否安全。
TEXT
)

DocumentBuilderFactory.newInstance()?{!((.setFeature) || (.setXIncludeAware) || (.setExpandEntityReferences))} as $entry;
$entry.*Builder().parse(* #-> as $source);

check $source then "XXE Attack" else "XXE Safe";
alert $source for {
message:"XXE Attack Detected",
level: high,
}

解读:

  1. desc 语句 描述规则一些基础信息。
    • title 和 title_zh 提供规则的标题和中文标题。
    • risk 指定风险类型为 XXE。
    • desc 和 solution 提供规则的详细描述和解决方案。其中<<<TEXT为heredoc语法,使用该语法使得我们可以在描述信息或者解决方案里面写各种格式的文本内容,而不用担心不符合SyntaxFlow语法错误。
  2. 审计表达式 中的 ?{} 结构筛选未发现调用 setFeature、setXIncludeAware 或 setExpandEntityReferences 方法。 #-> 运算符追踪从 parse 方法传入的参数的顶级定义,以识别可能的攻击载体。
  3. check 语句 检查 $source 是否包含匹配结果。
    • 如果 $source 存在,示例打印 XXE Attack,否则打印 XXE Safe。这些字符串是规则作者定义的说明,不是引擎对安全性的证明。
  4. alert 语句 如果$source存在,那么就会输出结果,结果的风险等级为high。输出的结果可以在前端页面IRify或者导出的漏洞报告查看。
示例的判断边界

这条教学规则检查的是相关配置调用是否出现,没有验证配置参数的取值。出现配置调用也可能使用了不安全的值;没有匹配到输入来源也不意味着解析器安全。正式规则应补充配置值、输入可控性与调用路径的检查。


URL 请求检测规则 (url-open-connection.sf)​

URL(* #-> * as $source).openConnection().getResponseMessage() as $sink;

check $sink then "Request From URL" else "No Response From URL";
alert $sink for{
message:"Request From URL Detected",
level:info,
}

解读:

  • 此规则追踪 URL 对象创建到发起网络请求的完整流程。
  • $source 表示 URL 的来源,而 $sink 表示从该 URL 获得的响应。
  • 使用 check 语句 来确定是否成功从 URL 获取了响应。
  • 使用 alert 语句 来输出检测到的 URL 请求信息,便于后续分析。

本地文件写入检测规则 (local-file-write.sf)​

Files.write(, * #-> as $params) as $sink;
$params?{.getBytes()} as $source;

check $source then "Local Files Writer" else "No Files Written";

alert $source for{
message:"Local Files Write Detected",
level:info,
}

解读:

  • 此规则检查 Files.write 方法的调用,并追踪写入操作中使用的参数。
  • 通过检查是否调用了 getBytes 方法来确认是否有数据被写入。

验证一条规则​

为规则准备至少两类样例:需要报告的代码,以及只存在相似调用但不应报告的代码。修改输入来源、配置值或中间调用后重新编译,观察命名结果与 alert 是否按预期变化。

优先复核源码位置与依赖路径,再讨论风险等级。规则的目的、语言范围、关键假设与已知限制,应在描述中写清楚。

后续阅读​

运算符速查​

常用运算符和语法​

  • #->:追踪变量的定义(Use-Def 链)。
  • ?{}:条件过滤,确保满足特定的条件。
  • as:为匹配的结果命名,便于后续引用。

参考链接​