专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
看雪学苑  ·  多款 Chrome 扩展 ... ·  2 天前  
小鹿学Java  ·  微信怎么更换实名认证?详细步骤与注意事项 ·  2 天前  
小鹿学Java  ·  微信怎么更换实名认证?详细步骤与注意事项 ·  2 天前  
51好读  ›  专栏  ›  看雪学苑

Redis漏洞分析,ACL篇

看雪学苑  · 公众号  · 互联网安全  · 2025-06-06 17:58

正文

请到「今天看啥」查看全文


(pat->flags == ACL_WRITE_PERMISSION) {
base = sdscatlen( base , "%W~" , 3 );
} else {
# assert failure
→       serverPanic( "Invalid key pattern flag detected" );
}
return sdscatsds( base , pat->pattern);
}


那么我们审计规则处理函数ACLSetSelector,尝试从中寻找漏洞。大致看一下处理逻辑,首先根据规则首字符(op[0])分出基本块,注意到处理%规则符时,会进入一个循环,在此循环中给flags赋值,这里的flags就是sdsCatPatternString索引的对象。

考虑这样一种边界条件,在%之后的规则符是~,这样控制流会跳出循环,而flags依旧是初始值0,同时函数返回C_OK,指示命令成功执行。


src/acl.
intACLSetSelector(aclSelector *selector, constchar* op, size_t oplen) {
    ...
    } else if (op[0] == '~' || op[0] == '%') {
if (selector->flags & SELECTOR_FLAG_ALLKEYS) {
            errno = EEXIST;
return C_ERR;
        }
int flags = 0;
size_t offset = 1;
if (op[0] == '%') {
for (; offset < oplen; offset++) {
if (toupper(op[offset]) == 'R' && !(flags & ACL_READ_PERMISSION)) {
                    flags |= ACL_READ_PERMISSION;
                } else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) {
                    flags |= ACL_WRITE_PERMISSION;
                # 跳出循环
→               } else if (op[offset] == '~') {
                    offset++;
break;
                } else {
                    errno = EINVAL;
return C_ERR;
                }
            }
        } else {
            flags = ACL_ALL_PERMISSION;
        }
        ...
    } else if (op[0] == '&') {
    ...
    }
    ...
return C_OK;
}


该漏洞的成因是,处理逻辑没有考虑到边界条件,在未对flags赋值之前就可以跳出循环。


补丁

所以针对该边界条件,补丁对其进行了检测,增加了对flags的非零判断。


src/acl.c 
@@ -1051,7 +1051,7 @@ intACLSetSelector(aclSelector *selector, constchar* op, size_t oplen) {

    flags |= ACL_READ_PERMISSION;

else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) {

    flags |= ACL_WRITE_PERMISSION;

- } else if (op[offset] == '~') {
+ } else if (op[offset] == '~' && flags) {

    offset++;

break;

else {


CVE-2024-51741 断言错误,DoS

披露时间:2025年1月6日
复现版本: 7.4.1
补丁版本: 7.4.2



在分析上一个漏洞成因时,是否发现了ACLSetSelector其中还潜伏着一个漏洞?


另一个漏洞

这次PoC更简单。


ACL SETUSER user %
ACL GETUSER user


回顾ACLSetSelector的处理逻辑,如果我们构造一个只有%的规则,会发生什么?结果是直接跳出for循环,触发panic。


src/acl.
intACLSetSelector(aclSelector *selector, constchar* op, size_t oplen) {

    ...

    } else if (op[0] == '~' || op[0] == '%') {
if (selector->flags & SELECTOR_FLAG_ALLKEYS) {
            errno = EEXIST;
return C_ERR;
        }
int flags = 0;
size_t offset = 1;
if (op[0] == '%') {
            # 直接跳出循环
→           for (; offset < oplen; offset++) {
if (toupper(op[offset]) == 'R' && !(flags & ACL_READ_PERMISSION)) {
                    flags |= ACL_READ_PERMISSION;
                } else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) {
                    flags |= ACL_WRITE_PERMISSION;
                } else if (op[offset] == '~' && flags) {
                    offset++;
break;
                } else {
                    errno = EINVAL;
return C_ERR;
                }
            }
        } else






请到「今天看啥」查看全文