CouchDB中的远程代码执行漏洞
Max Justicz
2017年11月14日
摘要
CouchDB存在一个由数据库原生JSON解析器与文档验证时使用的JavaScript JSON解析器之间的差异导致的漏洞。由于CouchDB数据库通常直接暴露在互联网上,这使得大量安装实例能够实现权限提升,并最终实现远程代码执行。如果被利用,此漏洞可能允许修改npm注册表中的任意包。[编辑:我错了,主要的npm注册表未受影响。请参阅下面的更正。我的错!] CVE-2017-12635
背景
上次,我写了一个关于反序列化漏洞导致在rubygems.org(一个Ruby程序依赖库)上执行代码的问题。向上游项目依赖中注入恶意软件是一种可怕的攻击向量,我怀疑大多数组织都没有充分防范。
考虑到这一点,我开始在registry.npmjs.org(负责分发npm包的服务器)中寻找漏洞。根据他们的主页,npm注册表每周提供超过30亿(!)次包下载。
CouchDB
npm注册表使用CouchDB,这是我在此项目之前从未听说过的。基本思路是,它是一个“NoSQL”数据库,使数据复制非常容易。它有点像用于JSON blob(“文档”)的大型键值存储,具有数据验证、查询和用户身份验证功能,使其更接近成熟的数据库。CouchDB是用Erlang编写的,但允许用户在JavaScript中指定文档验证脚本。这些脚本在创建或更新文档时自动评估。它们在一个新进程中启动,并从Erlang端传递JSON序列化的文档。
CouchDB通过一个名为_users的特殊数据库管理用户帐户。当您在CouchDB数据库中创建或修改用户时(通常通过PUT到/_users/org.couchdb.user:your_username),服务器使用JavaScript validate_doc_update函数检查您提议的更改,以确保您不会尝试将自己设为管理员。
漏洞
问题在于JavaScript JSON解析器(用于验证脚本)与CouchDB内部使用的名为jiffy的解析器之间存在差异。看看它们各自如何处理像{“foo”:“bar”, “foo”:“baz”}这样的对象上的重复键:
Erlang:
|
|
Javascript:
|
|
对于给定的键,Erlang解析器将存储两个值,但JavaScript解析器仅存储最后一个值。不幸的是,CouchDB内部数据表示的getter函数仅返回第一个值:
|
|
因此,我们可以绕过所有相关的输入验证并创建一个管理员用户:
|
|
在Erlang领域,我们将看到自己具有_admin角色,而在JavaScript领域,我们似乎没有特殊权限。对攻击者来说幸运的是,除了输入验证脚本之外,几乎所有关于身份验证和授权的重要逻辑都发生在CouchDB的Erlang部分。
现在我们有了管理员帐户,我们可以完全控制数据库。从这里获取shell通常很容易,因为CouchDB允许您通过管理界面定义自定义query_server语言,这个功能基本上只是execv的包装。这个漏洞的一个有趣特点是,通过Web GUI检测有点棘手;如果您尝试通过管理控制台检查我们刚刚创建的用户,roles字段将显示为空,因为它在显示之前是在JavaScript中解析的!
对npm的影响
我一直在试图弄清楚npm是如何受到此漏洞影响的。由于我实际上没有利用此漏洞攻击npm的任何生产服务器,我必须根据公开信息对基础设施的哪些部分容易受到攻击的哪些部分做出有根据的猜测。
我几乎可以肯定registry.npmjs.org容易受到此攻击的权限提升/管理员帐户创建部分的影响,这将允许攻击者修改包。这是因为npm上的用户创建与原始CouchDB用户创建流程基本相同。然后,在作为我们新创建的管理员用户进行身份验证后,传递给后续验证脚本的用户上下文将显示_admin角色,允许我们通过注册表验证文档中的isAdmin检查。也就是说,根据Github上的内容,他们的生产服务器没有提供到管理员配置API的路由,这意味着我不确定该漏洞是否可以在该服务器上启用RCE。[编辑:事实证明,registry.npmjs.org只是暴露了一个与CouchDB用户创建流程相同的API,以保持与旧客户端的向后兼容性。自2015年初以来,它一直在使用自定义身份验证系统,因此不容易受到我的攻击。然而,下面提到的skim数据库受到了此漏洞的影响。对于在初始版本的博客文章中完全错误,我表示歉意!]
Npm还暴露了一个“skim数据库”,看起来确实容易受到攻击的RCE部分的影响,但我不清楚该数据库在当今基础设施中的使用方式。2014年的一篇博客文章表明所有写入都转到skimdb,但我不知道这是否仍然成立。
结论
使用多个解析器处理相同数据可能是一个坏主意。如果必须这样做,也许因为您的项目像CouchDB一样使用多种语言,请尽力确保解析器之间没有任何功能差异,就像这里一样。不幸的是,JSON标准没有指定重复键的行为。
感谢CouchDB团队有一个已发布的安全电子邮件地址,并迅速修复了此问题。
无耻的插播
如果您有兴趣抛弃#birdsite,并想使用一个真正尊重您自由的社交网络,您应该考虑加入Mastodon!它是一个联邦社交网络,意味着它以分布式方式工作,有点像电子邮件。加入我们的fediverse,帮助我们建立一个友好的安全社区!
联系
Max Justicz
max@justi.cz
mastodon.mit.edu/@maxj
我会在仅几篇文章后放弃这个博客吗?敬请关注并找出答案!