在这里了解当今互联网的最新动态
在这里了解当今
在做一个Bug bounty的项目时,我发现了一个网站,它有一个很有意思的功能:它能让我使用一些用户控制的表达式过滤数据。比如说,我可以输入 book.proce > 100 表达式,使它只展示一些价格高于 $100 的书。直接输入 true 可以列出所有的书,输入 false 就会一本书都不显示。所以我可以知道我使用的表达式是对是错。
这个功能引起了我的注意,因此我尝试着输入更复杂的表达式,比如 (1+1).toString()==="2" (值为 true)和 (1+1).toString()===5 (值为 false)。这显然是 JavaScript 代码,因此我猜测这个表达式在 NodeJS server 中被作为参数传给了一个类似 eval 的函数。到了这里,我感觉我快要发现一个远程执行漏洞了。然而,当我想要测试一个更加复杂的表达式时,它报错了,提示我输入的表达式非法。我猜测这应该不是 eval 函数,而应该是一个 JavaScript 的沙箱。
沙箱都是再一个受控的环境中执行非可信的代码,而这一般都是很难确保不出问题的。大多数情况下,我们都能找到一些方法来绕过沙箱的保护机制。特别是对于像 JavaScript 这样复杂,特性臃肿的语言,沙箱的漏洞可能会更多。这个问题吸引了我的注意,所以我决定花一些时间来打破这个沙箱的防护机制。我学习了 JavaScript 的一些内部机制,用来发现和利用沙箱的 RCE 漏洞。
我首先要确定这个网站使用了什么库来实现的沙箱,因为 NodeJS 中有几十个类似的库,在许多情况下,它们都存在一些漏洞。当然,也有可能这是一个开发人员自己写的库,但是我忽略了这种可能,因为单纯的网站开发人员不太可能花大把的时间来做这种语言底层的事情。
最后,通过分析网站的错误日志,我推断处它们应该使用的是 static-eval ,这是一个不太流行的库(由 substack写的,这个人再 NodeJS 社区中非常有名)。尽管它的文档中写了,它并不是被设计来作为沙箱的,但是我仍然十分确定他在这个网站中被用作了沙箱。
绕过 static-eval
static-eval的基本思想是使用 esprima 库解析 JS 表达式并将其转换为 AST(抽象语法树)。static-eval 通过分析这个AST 对我输入的表达式进行评估。如果发现一些奇怪的东西,函数就抛出异常,我的代码就不会执行。一开始,我有点灰心丧气,因为我意识到沙箱对它所接受的表达式有很大的限制。我甚至不能在表达式中使用 for 或 while 语句,所以做一些需要迭代算法的事情是几乎不可能的。无论如何,我坚持着继续寻找漏洞。
一开始,我并没有发现任何 bug,所以我查看了 static-eval 项目的 commits 和 pull requests 的所有记录。 我发现 pull requests #18 修复了两个沙箱逃逸的 bug,而这正是我所寻找的。 我还发现了这个 pr 作者的博客,在这篇文章里,他深入分析了这个漏洞。同时,我在立即在这个网站中测试这个漏洞,然而,他们使用了一个新版本的 static-eval,这个版本的 static-eval 早就把这个漏洞补上了。我立即尝试在我测试的网站中使用这种技术,但不幸的是,他们使用的是更新的静态评估版本,已经修补了这个漏洞。但是,知道有人发现过这种漏洞,这让我更加自信,所以我一直在寻找绕过它的新方法。
接下来,我深入分析了这两个漏洞,以期望能够为我找到新的漏洞寻找灵感。
第一个漏洞:
第一个漏洞使用了 function constructor 来生成恶意函数。
这种技术经常用于绕过沙箱。例如,大多数通过绕过 angular.js 沙箱来获得 XSS 的方法都使用一些有效载荷,它们最终都会访问和调用 function constructor。下面的表达式用来演示漏洞,能够打印系统环境变量(这应该是不被允许的,因为沙箱应该阻止它):
这是一个非常简单的修复,但它的效果出奇的好。当然,function constructor 只在函数中可用。所以我无法访问它。对象的 typeof 是不能被修改的,因此任何函数的 typeof 都将被设置为 function。
资讯列表