CouchDB远程代码执行漏洞
Max Justicz
2017年11月14日
摘要
背景
作者此前曾报道过rubygems.org的反序列化漏洞导致代码执行的问题。向上游项目依赖注入恶意软件是一种危险的攻击向量,多数组织尚未做好充分防护。
基于此,作者开始研究registry.npmjs.org(npm包分发服务器)的漏洞。据其首页显示,npm注册表每周处理超过30亿次包下载。
CouchDB技术细节
npm注册表使用CouchDB,这是一种支持数据复制的"NoSQL"数据库。其核心是存储JSON文档的键值库,具备数据验证、查询和用户认证功能,使用Erlang编写但允许用户通过JavaScript编写文档验证脚本。
CouchDB通过_users
系统数据库管理用户账户。创建或修改用户时(通常通过PUT请求/_users/org.couchdb.user:用户名
),服务器会调用JavaScript的validate_doc_update
函数验证修改合法性。
漏洞原理
漏洞源于JavaScript JSON解析器与CouchDB内部jiffy解析器(Erlang实现)处理重复键的差异:
- Erlang解析器:
jiffy:decode("{\"foo\":\"bar\", \"foo\":\"baz\"}")
返回两个键值对 - JavaScript解析器:
JSON.parse()
仅保留最后一个键值
CouchDB内部数据获取函数couch_util:get_value
仅返回第一个匹配值,导致可构造特殊payload绕过验证:
|
|
Erlang端会识别roles
为["_admin"]
,而JavaScript端仅看到空数组,从而成功创建管理员账户。
权限提升与RCE
获取管理员权限后,可通过CouchDB的查询服务器语言配置功能(本质为execv
包装器)实现远程代码执行。值得注意的是,通过Web界面查看用户时因JavaScript解析会显示空角色字段,增加了隐蔽性。
对npm的影响分析
经考证,registry.npmjs.org虽采用类似CouchDB的用户创建流程,但自2015年起已使用自定义认证系统,因此不受此漏洞影响(作者初始判断有误)。但npm的"skim数据库"确实存在RCE风险,不过该组件在当前架构中的具体作用尚不明确。
结论与建议
使用多个解析器处理相同数据时,必须确保各解析器行为一致性。JSON标准未规定重复键处理方式更凸显了该问题的重要性。
致谢
感谢CouchDB团队通过security@邮箱快速响应并修复漏洞。