Nuclei DSL 夺舍记:虚拟机沙箱降维兼容 Nuclei DSL
2023-6-21 17:58:42 Author: Yak Project(查看原文) 阅读量:13 收藏

Nuclei 是一个被广泛使用的漏洞模版程序,它可以发起一系列的请求,并从请求中获取请求的结果是否符合某些条件,也可以从这些请求中提取用户期望的数据。为了增强 Nuclei 的表现力,它在一些版本中新增了 DSL 机制,DSL 本身是一个非常优秀的工程实践,可以极大增强文本内容的计算能力和逻辑表现力;准确的说 Nuclei DSL 并不是图灵完备的 DSL,它仅仅是使用了表达式的计算和逻辑运算特性来达成其运算目的。在这种情况下,Nuclei 通过 DSL 来实现逻辑表达其实还是相对非常直观的。
作为技术同学,我们对这种简单的代码其实非常容易理解,因为它的语法(github.com/Knetic/govaluate)习惯本质上和一些主流编程语言的表达式计算部分非常相似。
一些编写 POC 检测框架的同学也会去学习或使用它类似的库实现 DSL 的功能。

有趣的需求

Nuclei 开源了大量的模版,这些模版我们先抛开质量保证不谈(🐶),其表达简单,轻便快速可快速修改,短时间内积累了大量的忠实拥趸。在人力有限的情况下,直接“拿来”确实可以节省很多时间和精力。但是想要“缝合”其实并不是一个简单的事情。

首先“缝合”本身的在自己运营资源不足的情况下,是无法让运营效果超过一个成熟社区的;不断的 patch 其实远不如直接“加入”;基于这种原因,最直接的“缝合”也并不会让技术变得服务于人,徒增 “X years ago” 的 github dead repos 而已。
回归我们所提出的“安全基础设施”“能力融合”的概念,如果我们实现了 Nuclei 的格式,但是它与现有的各种基础设施完全割裂,那么这个能力集成其实是违背初衷的。

演变

Yaklang 和 Yakit 作为网络安全基础设施系统,我们实现了大量的神奇的安全基础技术和工程技术,在这个过程中,关于 Nuclei 的集成其实也被多次提及;早期版本,我们通过对 Nuclei 源码进行打补丁,为 Nuclei 定制 loader 编写了一个 Yaklang 的代码库以保持和 Nuclei 基本相同的执行效果。
这样做显然有很多缺陷
  • Nuclei 的网络基础设施和 Yaklang 的不一样,发包无法自动记录到 History,也无法留痕。

  • Interactsh OOB 的策略需要更深度的 hook 和 patch,这样修改 Nuclei 的代码,升级版本会遇到比较大的问题。

  • Nuclei 从设计上就是一个命令行工具,它使用全局对象、注册协议和无额外控制的文件系统行为造成了巨大的麻烦。

  • 在 Nuclei 的 DSL 推出后,DSL 造成了更大量的资源浪费和功能重复实现。

这些缺陷其实对于一个基础设施来说,非常致命;与此同时本身实现一个 PoC 框架其实是一个非常简单的的事情,以至于近几年 PoC 框架甚至成为练手和学习项目。
不管是 Knetic/govaluate 还是 Google/CEL 其实本质上做的事情都是一样的,但是它作为一个 “容器”,你仍然需要把自己的安全能力函数和依赖“注入”进去,我相信...编写这些框架的“内置函数”并不是一个愉快的体验吧?
与此同时,YakVM 的工程实现赋予了我们对“语法”的完全控制权,我们甚至发现,Yaklang 本身的基础语法,甚至完全兼容 Knetic/govaluateGoogle/CEL,但是因为 Yaklang 本身非常成熟的内置库的机制和表达式 Lambda 演算证明,Yaklang 可以实现对这两个库非常好的兼容性,除了 ?? 这种“奇怪”的运算符不打算支持之外,Yaklang 语法内甚至可以通过闭包函数直接执行代码段,执行语句序列,并从最后一个栈帧的缓存值中获取表达式执行的结果。
当我们发现这一个现象的时候,其实自己也被吓了一跳。因此,我们甚至可以抛弃表达式容器构造其他程序的 DSL,来对其他程序直接进行无痛兼容,并且可以直接剔除掉所有我不爱副作用;我们发现这个技术其实非常常见,也并不是一个很离谱的技术,大家更多的时候会叫它“虚拟机沙箱”

降维兼容其他DSL容器

作为对比,在 PocSuite 兼容 Nuclei 格式的 Templates PoC 的时候,它会使用 Python 的 eval 来实现,这样如果我们是不是能在 PoC 中直接执行其他库的代码呢?这当然是可以的,这会引发非常大的安全问题,当你要执行不可控的 Templates 的时候,基本就等同于任意代码执行了。
同样,我们如果希望使用一个干净的 VM 来执行代码,这样会从源头上避免“代码执行”,也可以杜绝代码与操作系统进行不期望的交互。
我们在此就不赘述 YakVM 的核心原理了,我们实现了 YakVM 之后,主动剔除了 Yaklang 内置的各种函数之后,就可以得到一个沙箱。我们可以构建沙箱的时候,传入一个 map[string]any ,YakVM 会根据传入的 map 的成员,自动构建它的定义并且和 Yaklang 语法做类型兼容。
我们按上面的例子,随意加一些扩展,我们发现,注入变量或者定义初始化函数,数字运行,执行表达式,使用 Yaklang 的安全沙盒变得非常丝滑,甚至我们在执行的过程中,都很难感受到静态类型到类型转换的过程。
正如我们在 Yaklang 开源发布会 上的说法,Yaklang 在嵌入式和脚本编写时的体验已经很优秀了,甚至于在 Yakit 和 Yaklang GRPC 接口中,我们用了大量的 Yaklang 和 Golang 混合编程的代码,同时我们的研发同学并没有在实现的过程中有任何“不适”。

夺舍 Nuclei

其实在 Yaklang 中,大家用到的 Nuclei 其实早已经不是 Nuclei 原版了。我们实现这部分功能,其实仅仅用了几天实现,甚至我们最后发现,自己实现的内容不仅仅可以更好的追踪流量,同时执行效率和对 Yakit 的兼容度都得到了非常好的提升。
难道仅仅是夺舍这么简单吗?实际上我们甚至可以开发出一些 Nuclei 未实现的非常好用的 API,甚至调试也会变得非常方便:
当然,这只是一个简单的案例,我们如果仅仅只是重新实现了 Nuclei 的库的话,其实也并没有解决运营问题。

与 Web Fuzzer 的完美融合(7月上线)

Nuclei 的大部分核心功能在匹配和提取两个部分,这两个功能在 Web Fuzzer 中如果完整支持,Web Fuzzer 将会得到空前的强化,我们不仅仅可以实现匹配提取的更通用的规则化,并且我们将可以把“变量”机制从热加载中剥离;从而实现若干 Web Fuzzer 实例的串联。

当然,我们甚至可以直接从 Web Fuzzer 一键生成连带 Matchers 和 Extractors 的 Yaml PoC!

并且,任何你的 Web Fuzzer 的请求都可以直接使用任何 Yaml PoC 的模版进行扫描!

扫码添加好友

加入YAK技术交流群



文章来源: http://mp.weixin.qq.com/s?__biz=Mzk0MTM4NzIxMQ==&mid=2247499193&idx=1&sn=358edfbac354379bfc86dec970b8084e&chksm=c2d1811df5a6080b7dce43d1c24f79b4aeb7103774602fe31529b2e71c687c5f2d548fc62a95#rd
如有侵权请联系:admin#unsafe.sh