SyntaxFlow规则引擎能力迭代"

admin 2026-10-20 21:38:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

SyntaxFlow 规则引擎能力迭代

原创

YAK
YAK

Yak Project

2026年6月5日 17:40
湖南

在小说阅读器读本章

去阅读

SyntaxFlow 的 CFG 能力属于过程内(intra-procedural)控制流分析,在 SSA 基本块上工作。

目前,SyntaxFlow 规则已集成多项控制流分析工具。本文将重点阐述其新引入的本地调用(Native Call)功能更新。

一、目前的局限

在编写 SyntaxFlow 规则时,可能遇到如下的情况:

id := r.URL.Query().Get(\"id\") if !filterValidateID(id) {    http.Error(w, \"invalid id\", http.StatusBadRequest)    return}query := fmt.Sprintf(\"SELECT username FROM users WHERE id = %s\", id)_, _ = db.Query(query) // sink

单靠追踪数据流的上层定义链(def-use chain)这种思路,在此类问题上是行不通的。这是因为通过 db.Query 向上追踪数据流,只能找到filterValidateID和 r.URL.Query().Get,而找不到 if路径里面的 return 信息,此时使用纯数据流分析就很难判断 filterValidateID是否会影响后续 db.Query 的调用。

二、新增NativeCall的基础用法

YAK

1.getCfg

将 SyntaxFlow 命中(实参、赋值右值、调用等)映射到其所在的 SSA BasicBlock,作为内部 CfgCtx(func / block / inst)的统一锚点。


$sink as $sinkCfg$thenVal as $thenCfg


YAK

2.cfgGuards

以链上点为 sink,在同函数内扫描「头块 CFG 可达 sink」的二路分支:

1.若一侧到不了 sink、另一侧能到,则在截断侧识别 return / panic / break / continue,输出 GuardPredicateValue(形如 cfgGuard(kind=..., polarity=...))

2.若无合格分支,输出 kind=none 的合成守卫,避免过滤链断掉


$sinkCfg as $guards$arg?{opcode: return} as $retGuards$arg as $retGuards2


YAK

3.cfgDominates

从函数入口沿控制流到当前 cfg,是否必经 target cfg(图论:target 支配 current)。同块内可按指令序细化。返回布尔常量 true / false。

foo() as $callprintln(* #-> as $sinkArg)$call<getCfg()> as $callCfg$sinkArg<getCfg()> as $sinkCfg$callCfg<cfgPostDominates(target: \"$sinkCfg\")> as $pd  // true

YAK

4.cfgPostDominates

从当前 cfg 沿控制流到函数出口,是否必经 target(图论:target 后支配 current)。用于「往后走是否一定经过某点」。参数形式同 cfgDominates。

foo() as $callprintln(* #-> as $sinkArg)$call<getCfg()> as $callCfg$sinkArg<getCfg()> as $sinkCfg$callCfg<cfgPostDominates(target: \"$sinkCfg\")> as $pd  // true

YAK

5.使用案例

在了解上述4个 native call 后,之前在本文开头提到的案例就有解决方案了:

id := r.URL.Query().Get(\"id\") if !filterValidateID(id) {    http.Error(w, \"invalid id\", http.StatusBadRequest)    return}query := fmt.Sprintf(\"SELECT username FROM users WHERE id = %s\", id)_, _ = db.Query(query) // sink

核心思路为使用 cfgGuards 判断上述控制流中没有 return 类型的截断:

<include('golang-database-sql')> as $sink;<include('golang-user-input')> as $input;*.Query as $func;*.QueryRow as $func;// ---------- 1. getCfg:source / sink 锚点 ----------// 用户输入命中点 → 基本块(与 include $input 同源)$input as $srcHit;$srcHit<getCfg()> as $sourceCfg;// Query 实参 → sink 基本块$func(* as $param);$param<getCfg()> as $sinkCfg;// ---------- 2. cfgGuards:sink 侧分支截断(过滤 return 守卫) ----------// sink 块上:存在「另一侧 return、本侧能到 sink」时得到 earlyReturn 等;!opcode:return 保留可分析链$sinkCfg<cfgGuards()> as $guards;$param?{<cfgGuards()>?{!opcode: return}} as $paramOk;// ---------- 3. 数据流 + 再次用 cfgGuards exclude ----------$paramOk #{    until: `/Sprintf/`,    until: `*?{opcode:add}`,    include: <<<CODE* & $inputCODE,    exclude: <<<CODE*?{<cfgGuards(opcode: return)>}CODE,}-> as $path;// ---------- 4. cfgDominates:路径上的点须被 source 块支配 ----------// 从函数入口到该 SSA 点须必经 $sourceCfg(id 赋值所在控制流)$path?{*<cfgDominates(target: \"$sourceCfg\")>?{have: \"true\"}} as $high;alert $high for {    level: \"high\",    title: \"SQL injection (concat after validation)\"    title_zh: \"校验后仍拼接 SQL,且 source 支配污点路径\"    risk: \"SQL注入\",    message: \"已用 getCfg 锚定 source/sink,cfgGuards 剔除 return 截断分支,cfgDominates 要求路径必经用户输入;请改用 db.Query(\\\"... ?\\\", id)。\",}

三、新增NativeCall的高阶用法

YAK

1.cfgReachable

当前 cfg 能否沿 CFG 到达 targetcfg。返回 true / false。


$callerCfg as$path


1.icfg:是否仅过程内 CFG沿基本块 Succs 走,不进 callee、不从 return 回到 caller;

2.max_depth:限制「穿过多少次调用/返回」,防止 ICFG 搜太深(填写 -1 表示无限制);

3.max_nodes:BFS seen集合大小超过该值则整次搜索失败,返回空路径。

YAK

2.cfgReachPath

与 cfgReachable相同的起点、终点与 icfg 配置:可达时返回 (函数,块) 链证据字符串,不可达为空。

$callerCfg<cfgReachPath(target: \"$calleeCfg\", icfg: true, max_depth: 4)> as $path

过程内不可达时路径为空,可与 cfgReachable 搭配做规则调试输出。

YAK

3.cfgCondition

返回当前基本块上的条件摘要(inst / value / source / schema 等),覆盖 if、switch、loop、merge 继承等场景;无分支条件时可能为空。


$cfg as $cond


YAK

4.cfgConditionValues

与 cfgCondition 同源摘要,但直接给出条件关联的 SSA value 列表。

$cfg<cfgConditionValues()> as $v

YAK

5.reachabilityGuard

从函数入口出发,判断 target 是否在 mustExecute 意义下必执行(mode 目前仅 mustExecute)。

返回值(三种)

1.入口全路径必达且后支配成立 → 布尔 true

2.入口 CFG 不可达 target → false

3.否则 → 到达 target 路径上的条件 SSA value 列表(嵌套 if/loop 可能多项)

$from<reachabilityGuard(target=\"$to\", mode=\"mustExecute\")> as $guard

YAK

6.使用案例

id := r.URL.Query().Get(\"id\")tenant := r.URL.Query().Get(\"tenant\")role := r.Header.Get(\"X-Role\")// 过滤 1:ID 格式if !filterValidateID(id) {    http.Error(w, \"bad id\", http.StatusBadRequest)    return}// 过滤 2:租户if !filterMatchTenant(id, tenant) {    http.Error(w, \"tenant mismatch\", http.StatusForbidden)    return}// 过滤 3:角色(仅 admin/operator 可查)if !filterRequireRole(role, \"admin\", \"operator\") {    http.Error(w, \"forbidden\", http.StatusForbidden)    return}// 过滤 4:审计(不 return)filterAuditLog(w, \"getUser\", id)// 仍危险:校验通过后仍拼接limitStr := r.URL.Query().Get(\"limit\")limit, _ := strconv.Atoi(limitStr)if limit <= 0 {    limit = 10}query := fmt.Sprintf(    \"SELECT id, name FROM users WHERE id = %s AND tenant = '%s' LIMIT %d\",    id, tenant, limit,)_, _ = db.Query(query) // sink

在上述的案例中有3个关键的过滤函数 filterValidateID,filterMatchTenant,filterRequireRole,一个无效的过滤函数 filterAuditLog,控制流结构如下:

入口  → Get(id), Get(tenant), Header(role)  → [filterValidateID]     ─失败→ return  → [filterMatchTenant]    ─失败→ return  → [filterRequireRole]    ─失败→ return  → filterAuditLog         (无 return)  → Get(limit) → Sprintf   ─┐  → db.Query               ← sink(仅「三路校验都过」可达)

尽管我们可以通过串联 cfgGuards和 cfgCondition自底向上追溯调用链,但此方案存在局限:在进行代码扫描时,我们无法预知过滤函数的准确数量。若仅配置一次 cfgCondition,则大概率只能定位到调用链末端的最终过滤函数,而无法回溯到链上的所有中间函数。

下面 Syntaxflow 规则将使用 reachabilityGuard 一次性找到所有有效的过滤函数:


 as $fromdb.Query(* as $to)$from as $guard;

![](https://mmbiz.qpic.cn/sz_mmbiz_png/jibGAup6p72EBDdtxt22xia3Deuo9SibuhAYlPHTq2jISicn297TpdtZ60EowdMBckGoFNIQ75O8thXmDsfFddghgPy3FBKtF4AZPtibBW41h4VM/640?wx_fmt=png&from=appmsg#imgIndex=4)

reachabilityGuard 就是为了解决这个问题而出现的,它的含义为:控制流想要从 from 移动到 to 的途中需要满足的所有条件。

四、对旧的语法补充控制流分析功能

YAK

1.<dataflow(...)>

<dataflow(...)> 是 SyntaxFlow 的 native call,在原有 include / exclude / end 路径过滤之上,增加了 按 CFG 锚点裁剪的参数。

1.only_reachable:指定锚点符号(如 $thenCfg),通常来自 <getCfg>,也可以是 frame 里任意能映射到基本块的 SSA 值;只保留「定义点 CFG 能到达该锚点」的结果。

2.only_reachable_mode:控制 CFG 过滤时机。post 在 include/exclude 路径匹配完成后,再按锚点后滤结果;path 在枚举 dataflow 路径时,对每一步扩展做可达性约束。

3.strict:设为 true 时等价于 only_reachable_mode=\"path\",即启用路径级 CFG 过滤。

4.icfg:过程内 CFG 判不可达时,是否启用跨过程 ICFG 再判可达;用于 caller → callee 等跨函数场景。

5.max_depth:仅在 icfg: true 时生效,限制 ICFG 搜索时的调用深度上限(跨过程边层数)。

6.max_nodes:仅在 icfg: true 时生效,限制 CFG/ICFG BFS 访问的状态节点数,防止搜索过大;超出则视为不可达。

案例如下:

$sink<dataflow(<<<CODE    * #-> as $p    CODE,include: <<<INC    * & $input    INC,exclude: <<<EXC    *?{<cfgGuards(opcode: return)>}    EXC,only_reachable: \"$sinkCfg\",only_reachable_mode: \"post\")> as $high

YAK

2.{ ... } ->

扩展了3个CFG相关的配置项:

1.only\_reachable:能 CFG 到达锚点

2.include\_reachable:包含目标 CFG 锚点

3.exclude\_reachable:排除目标 CFG 锚点

语法案例:


$sink * #{    include: * & $source,    exclude: *?{opcode: call},    only_reachable: $thenCfg,    exclude_reachable: $badCfg,    until: * & $param,}-> as $out

include_reachable exclude_reachable 和之前已经存在的 include exclude 有不同的地方,在逻辑上它们的效果类似于剪枝,而后者的效果更倾向于过滤。

下面的案例可以帮助你理解:
c = \"test\"x = cif (c) {    a = \"thenStr\"    x = a} else {    b = \"elseStr\"    x = b}println(x)
println(* as $sink)a as $thenVal$sink * #{    include: `* & $thenVal`,}-> as $outInc // 得到 \"thenStr\"$thenVal<getCfg> as $thenCfg$sink * #{    include_reachable: `$thenCfg`,}-> as $outReach // 得到 \"thenStr\" 和 \"test\"

在第二个规则样例中,include_reachable的主要作用是包含 else 这条路径,因此在这条路径上的 \"test\" 也会被查找到,而第一个规则样例主要是为了在数据流中过滤某个变量,因此只保留了 \"thenStr\"。

五、总结

SyntaxFlow 的 CFG 能力是在既有 NativeCall 体系上的控制流语义扩展:

1.getCfg 提供统一基本块锚点

2.cfgGuards、cfgDominates、cfgReachable、reachabilityGuard 等链式 native 负责分支截断、必经关系与入口必达

3.dataflow() 与 # { ... } -> 则通过 only_reachable 及 post/path、icfg 等参数,在原有 include/exclude 路径模型上叠加「定义点是否 CFG 可达锚块」的过滤

控制流分析可以在保留数据流污点骨架的同时,显著减少 if/else 死分支、早 return 校验、phi 多值枚举带来的误报,并在内置规则中逐步替代依赖 opcode:phi 的间接写法。

未来总体目标是:让 SyntaxFlow 在「语法 + 数据流」之外,具备可编写、可组合、可回归的控制流感知规则表达能力,同时保持对存量规则的平滑兼容与渐进迁移。

END

更新记录

Yaklang 1.4.7-beta8

[Yakit]

  1. Http Fuzz 专注模式 UI 优化,减少错误日志输出以避免前端过载;

  2. gRPC TLS 启动支持查看证书信息

  3. 优化HTTPFuzzer发包错误提示并新增 TLS 自动重试能力;

  4. Codec 编解码支持自动解码 Key;RSA 加密支持 JavaScript 解码风格;

  5. 修复 file.save 覆盖逻辑失败问题;

  6. cli参数生成修正为有序模式

[Irify]

  1. 优化编译语言判断,提升准确率

  2. 修复C、GO、TS、Python的编译问题

[Memfit / AIgent]

  1. MCP 服务:重构升级 MCP 服务,提供外接 MCP 与 Memfit AI 工具;并新增 MCP 服务工具面板;

  2. 模型与执行修复:修复 directly answer 多次不退出的问题;

  3. 能力更新:深度规划支持并发执行任务,todo列表优化展示

YAK官方资源

Yak 语言官方教程:

https://yaklang.com/docs/intro/

Yakit 视频教程:

https://space.bilibili.com/437503777

Github下载地址:

https://github.com/yaklang/yakit

Yakit官网下载地址:

https://yaklang.com/

Yakit安装文档:

https://yaklang.com/products/download\_and\_install

Yakit使用文档:

https://yaklang.com/products/intro/

常见问题速查:

https://yaklang.com/products/FAQ


SyntaxFlow规则引擎能力迭代" 网络安全文章

SyntaxFlow规则引擎能力迭代"

本文介绍了SyntaxFlow规则引擎新增的NativeCall功能,重点解决纯数据流分析在控制流场景下的局限性。通过getCfg、cfgGuards、cfgDominates等工具实现过程内控制流分析,可精准识别SQL注入等漏洞路径。文档详细展示了如何通过cfgGuards排除return截断分支,并使用reachabilityGuard一次性定位所有有效过滤函数,为代码安全审计提供实用解决方案。
思科:注意无补丁但已遭利用的SD-WAN高危0day" 网络安全文章

思科:注意无补丁但已遭利用的SD-WAN高危0day"

思科发布安全公告称CatalystSD-WANManager存在无补丁高危0day漏洞CVE-2026-20245,已遭在野利用。该漏洞因输入验证不充分导致,允许低权限攻击者通过构造文件上传实现root提权。影响所有部署版本,思科提供了检测日志中恶意命令的妥协指标,建议管理员审计admin-tech文件并升级至5月14日版软件。
中国信息安全测评中心主任彭涛:走好智能体发展与安全的双赢路" 网络安全文章

中国信息安全测评中心主任彭涛:走好智能体发展与安全的双赢路"

本文探讨智能体在快速发展中面临的安全挑战与应对策略。文章指出智能体在赋能各行业的同时存在数据泄露、越权操作等风险,国内外均面临技术壁垒与安全威胁。我国通过《人工智能+行动意见》和《智能体规范应用实施意见》等政策强化安全监管,强调需在技术研发、部署应用全链条统筹发展与安全,实现智能体可持续发展。
评论:0   参与:  0