白泽带你读论文 | Object Dependence Graph and Query

admin 2025年2月25日13:18:52评论10 views字数 4442阅读14分48秒阅读模式

如需转载请注明出处,侵权必究

Mining Node.js Vulnerabilities via Object Dependence Graph and Query

       本文发表于USENIX Security 2022,第一作者是来自约翰霍普金斯大学的Song Li。论文借鉴了代码属性图(Code Property Graph)的思想,针对JavaScript的一些动态特性提出了一种新的图结构称为对象依赖图(Object Dependence Graph),并将其应用于Node.js的漏洞挖掘工作中。

背景

Node.js是一个流行的JavaScript运行环境,可以在网络浏览器之外执行JavaScript代码,例如做为web服务器为客户端提供服务。Node.js生态系统包括数以百万计的NPM包,这些NPM包中存在多种已知漏洞(如命令注入,原型污染,内部道具篡改等)威胁着Node.js生态的安全。然而由于JavaScript的许多动态特性导致现有的研究针对Node.js的漏洞挖掘和JavaScript静态分析都存在一定的局限性

1.  前人工作提出了许多基于程序分析的方法来对Node.js上一些常见漏洞类型进行检测,如命令执行、原型污染等,并且取得了不错的成效。然而这些工作都是针对特定Node.js漏洞类型进行挖掘,现在还没有一个通用的框架能够用来检测所有类型的Node.js漏洞。

2.  在JavaScript以外的语言(如C/C++和PHP)中,漏洞检测的一个最新进展是建立一个代表目标程序不同属性的图结构,并执行图查询来挖掘漏洞。在已有的研究中,CPG(代码属性图)被证明在在挖掘C/C++和PHP中的许多类型的漏洞方面是有效的。然而CPG中没有对对象关系进行建模,例如基于JavaScript原型链的对象查找,因此无法用于检测JavaScript中常见的基于对象的漏洞,如原型污染和内部属性篡改等。

3.  先前的静态JavaScript分析的研究通过抽象解释与在线数据结构(如网格)一起为对象及其关系建模。然而已有抽象解释面临两个主要的挑战:一是以前的数据结构不适合离线(即抽象解释后)检测各种漏洞,他们的目标是特定类型的漏洞;二是对分支敏感性的取舍,如果不考虑分支敏感性依次解释所有的分支会损害分析的准确性,而如果考虑分支敏感性而进行并行解释的话又容易损害了扩展性。

设计与实现

1. ODG设计概述

ODG的实现是在CPG(代码属性图)的基础上进行扩展,如下图所示。图的上半部分是传统的代码属性图,在AST图基础上加入了CFG(控制流图)与PDG(程序依赖图)的边。图的下半部分是本文所定义的ODG,新增了对象(object)、变量(variable)和scope节点的定义,并为这些节点和对应的AST节点之间建边来表示对象与变量的对应关系、对象与对象之间关系、对象和AST节点的对应关系等。如表1所示,ODG中边区别与CPG的边表示的主要关系有:

◽ v(变量)->o(对象):表示的含义是变量v对应JavaScript对象o。

◽ o(对象)->v(变量):表示的含义是变量v是对象o的一个属性

◽ o(对象)->o(对象):表示不同对象之间的依赖关系,如数据流依赖。

◽ a(AST节点)-> o(对象):为AST图中表示变量的节点绑定对应的对象节点。

◽ o(对象)-> a(AST节点):表示对象o的定义,即将对象o与其对应的定义语句在AST中的根节点关联起来。

白泽带你读论文 | Object Dependence Graph and Query
白泽带你读论文 | Object Dependence Graph and Query

2. ODG构造

文中通过对程序语句进行抽象解释来构建程序所对应的ODG结构,对于不同的语句结构采用如下的处理方式:

◽ 变量定义:首先试图从ODG中查找该变量或属性,如果查询失败则会创建新的变量和对象节点,并连接相应的节点;如果查询成功,则重复使用现有的变量和对象节点,但为这些节点创建新的边。

◽ 分支处理:首先尝试确定分支条件的值,并选择相应的分支。如果不能确定分支条件值,操作语义就取决于分支的敏感性。

  • 在分支敏感模式下,为每个分支创建一个唯一的分支标签,通过标签来区别同一个变量在不同分支的状态。

  • 在分支不敏感的模式下,依次对所有分支顺序进行抽象解释,后来的分支中创建的对象和边将覆盖在早期分支中创建的对象和边。

  • 默认模式是分支敏感模式,但如果对于一个特定的函数来说对象的数量超过一定数量(如10k),工具将切换到分支不敏感模式。

◽ 函数定义处理:如果函数没有定义在一个无名的闭包中,则添加新的变量以及对象节点,并创建对象与变量节点之间的边,然后处理与原型相关的边。

◽ 函数调用处理:

  • 在预调用阶段,查找函数对象并创建相应的对象节点和控制流边。

  • 在调用阶段,首先处理所有的参数,改变当前的scope节点(用于区分不同的抽象解释作用域)和this指针,然后跳转到对应函数的AST根节点。在函数返回语句中,处理函数返回的对象并创建相应的数据流边。

  • 由于工具使用当前作用域处理函数调用并返回到准确的调用位置,因此是一种上下文敏感的方法。

◽ 循环与递归调用处理:工具抽象地解释了一个循环(或一个递归调用),直到循环(或递归调用)之外不再有新的对象被查找为止。同时工具还为循环(和递归调用)设置了一个最小和最大的限制。

3. 图查询定义和漏洞挖掘建模

为了方便利用ODG图进行漏洞挖掘,本文借鉴CPG的思想对一些基础的图查询以及图遍历操作进行建模,如表2所示。主要是思路就是将常用的一些操作定义为图查询的原子操作,如表示查找对象o所对应的定义语句,表示在AST中匹配特定的语句结构并返回其AST根节点p(如寻找o1[o2]=o3的语句结构)等。不同图查询操作可以通过交、并等关系构成更加复杂的图查询操作。

白泽带你读论文 | Object Dependence Graph and Query

有了这些基础的图查询操作,论文针对Node.js的常见漏洞类型进行了建模,如表3所示。通过人工分析总结出不同漏洞类型的特征对应的图查询操作组合,利用这些固定的图查询模式来对目标程序进行漏洞挖掘,找到所有符合对应漏洞特征的代码位置并将其标记为潜在漏洞。

例如对于内部属性篡改中对于原型属性篡改的漏洞有如下图查询模式:

◽ 首先确定对象o1存在原型且原型中存在一个属性o5

◽ 其次找到符合o1[o2]=o3语法结构并且o2和o3都可控的代码位置loc

◽ 最后确定在修改位置loc的控制流后继中存在对o1原型的属性o5的使用。

白泽带你读论文 | Object Dependence Graph and Query

实验

1. ODG对于Node.js漏洞挖掘的通用性

论文收集了330个已知的Node.js漏洞,并进行了分类,总结出16类Node.js漏洞类型。如表4所示,经过评估,ODG+CFG+AST的组合支持对其中大部分的漏洞类型建模(13/16)。

白泽带你读论文 | Object Dependence Graph and Query

2. 工具在挖掘Node.js 0-day漏洞方面的能力

论文在30万个NPM包上对工具进行了评估。结果如表5所示,在爆出的2964个漏洞报告中,人工检验其中的264个漏洞报告,发现其中180个为真实漏洞,并最终收到70个CVE编号。

白泽带你读论文 | Object Dependence Graph and Query

 3. 与已知的工具对比

论文选取一些现有工作作为benchmark,如表6所示。其中为了满足对比的需要,论文还对一些工具进行修改来支持对Node.js漏洞检测。

白泽带你读论文 | Object Dependence Graph and Query

从实验结果来看,论文与现有工作相比不论是漏洞挖掘数量还是漏洞的漏报率和误报率方面的表现都更优异。

白泽带你读论文 | Object Dependence Graph and Query
白泽带你读论文 | Object Dependence Graph and Query

4. 程序抽象解释过程的工具性能

论文衡量了工具在给定时间上限内对于NPM包的代码覆盖率以及分析效率的表现。如下图所示,在30秒的限制内,有40%以上包代码覆盖率接近100%。而在对分支敏感的情况下,工具在30秒内完成了85%的包的分析,在对分支不敏感的模式下,完成了93%的包的分析。

白泽带你读论文 | Object Dependence Graph and Query
白泽带你读论文 | Object Dependence Graph and Query

5. 混合的分支敏感模式的效率

文中将只使用分支敏感模式和分支不敏感模式与论文中提出的混合模式进行对比,结果如表11所示,混合的模式相比与固定使用某一种模式而言能够发现更多的漏洞。

白泽带你读论文 | Object Dependence Graph and Query

总结

1.  本文提出了一种新颖的图结构,称为对象依赖图(ODG),用来建模JavaScript对象及其与AST节点在定义和使用方面的关系。

2.  针对各种Node.js漏洞特别是原型链污染、内部属性篡改设计了对应的离线图查询模式用于漏洞检测。

3.  实现了一个工具原型ODGGen,使用抽象解释来生成Node.js包对应ODG结构用于漏洞检测。

4.  在真实世界的NPM软件包上对ODGEN进行评估发现了43个应用级和137个软件包级的0day漏洞(70个被分配了CVE标识符)。

Q&A

Q1:本文提出的ODG+AST+CFG与CPG有哪些区别?

CPG(代码属性图)是整合了PDG+CFG+AST的图结构,而ODG+AST+CFG在CPG的基础上保留了AST和CFG部分,并新增了对象、变量和scope节点,在这些节点和AST节点之间建边来表示对象与变量的对应关系、对象与对象之间关系、对象和AST节点的对应关系等,使用更加细粒度的对象间的依赖关系来替代原来CPG中的PDG。

Q2:文中提到Hybrid branch-sensive是什么实现的?

ODGEN的默认情况是抽象地解释并行所有的分支,但是如果对象节点的数量爆炸,ODGEN会切换回按照函数的顺序进行分支解释,即默认模式是分支敏感的,不过针对图中的节点数量设计了一个阈值,如果一旦对象节点数量超过这个阈值就会切换到分支不敏感的模式。

Q3:文中总结工具出现误报的主要原因是哪些?

◽ 未建模的路径约束:对于NodeJS的内建函数,论文只对5%以上的包使用到了的内建函数进行建模。

◽ 无法处理的路径约束。

◽ 一些预期功能被错认成了漏洞。

Q4:文中总结工具出现漏洞的主要原因是哪些?

◽ 一些Node.js的内建函数没有分析导致数据流依赖缺失。

◽ 每个包只给30s的分析上限,超时导致ODG没有构建完善。

Q5:文中提到的工具局限性有哪些?

◽ 支持的JavaScript特性:文中的原型只实现了那些被5%以上的包所使用的特性

◽ 异步回调和事件:ODGEN的原型实施采用了一个队列结构来存储注册期间的异步回调,并逐一调用它们,但这样的建模不太完善,因为只是处理在实际执行中可能发生的许多可能性之一。

◽ 抽象解释中的for循环和递归调用的处理:ODGEN广泛地执行for循环,直到循环外不再有新的对象被查询。引入最小值限制为了防止一些外部对象没有被深入建模,引入最大值限制是为了避免死循环和减少性能开销。这样建模同样存在一定的局限性。

◽ 动态包含的文件:在静态分析中,工具不能分析任何取决于用户输入而动态包含的文件。只是静态分析固有的局限性。

◽ 净化函数:工具的原型实现在分析数据流时采用了一系列的净化函数,例如parseInt。目前,该列表是通过手动生成的,不够完善。

文案:HZA

排版:YST

戳“阅读原文”即可查看论文原文哦~

复旦白泽战队

一个有情怀的安全团队

还没有关注复旦白泽战队?

公众号、知乎、微博搜索:复旦白泽战队也能找到我们哦~

白泽带你读论文 | Object Dependence Graph and Query

原文始发于微信公众号(复旦白泽战队):白泽带你读论文 | Object Dependence Graph and Query

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月25日13:18:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   白泽带你读论文 | Object Dependence Graph and Queryhttps://cn-sec.com/archives/850898.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息