abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · mysql-set-role-leftover
类别: 权限残留(以 mysqld UID 执行 FILE;非操作系统本地提权) 可达性: 远程
MySQL Community Server mysqld 26.7.0(06a5c1c)- Oracle
SET ROLE ALL EXCEPT rfile(或在没有默认角色时执行 SET ROLE DEFAULT)会清空活动角色列表,随后 checkout_access_maps() 直接返回,未调用 set_master_access(user->access)。CURRENT_ROLE() 返回 NONE。角色所聚合的静态全局权限位(FILE、PROCESS、SUPER 等)仍保留在 m_master_access 中。check_access 会读取该残留权限。实验环境:残留的 FILE 权限以 mysqld UID 写入 INTO OUTFILE。
SET ROLE NONE 才是恢复 ACL_USER::access 的路径。动态权限(SYSTEM_USER)会被丢弃。数据库级别的残留问题已经修复(Bug#35386565)。默认账户没有角色。
| ID | 暂无 CVE |
| 类别 | 权限残留(以 mysqld UID 执行 FILE;非操作系统本地提权) |
| 可达性 | 远程(已认证 SQL) |
| CWE | CWE-269 |
| CVSS | 高危:8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| 产品 | MySQL Community Server mysqld |
| 受影响版本 | 26.7.0(06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8) |
| 认证 | 已认证;受害者被授予一个携带静态全局 ACL 的角色(实验环境中为 FILE) |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅限 127.0.0.1。见证文件。残留 FILE 写入。 |
持有一个被授予携带 FILE(或其他静态全局权限位)角色的账户。对该角色执行 SET ROLE,然后对其执行 SET ROLE ALL EXCEPT。CURRENT_ROLE() 报告 NONE。SELECT 'witness' INTO OUTFILE 仍会以 mysqld UID 在 secure_file_priv 下写入。
一个使用 SET ROLE ALL EXCEPT dangerous_role 或 SET ROLE DEFAULT 进行沙箱隔离、然后信任 CURRENT_ROLE() 的应用程序,仍然拥有那些静态权限位。SET ROLE NONE 才会真正丢弃它们。
该残留并不会授予账户从未通过角色获得的 FILE 权限。它只是未能在角色停用后丢弃 FILE。
与三个客户端残留问题相同的 26.7.0 排查过程。默认守护进程未公开的严重/高危问题为空。ACL / 角色部分仍然存在这个空角色提前返回。
void Security_context::checkout_access_maps(void) {
if (m_acl_map != nullptr) {
get_global_acl_cache()->return_acl_map(m_acl_map);
m_acl_map = nullptr;
}
if (m_active_roles.size() == 0) return;
// ...
}
activate_role_all(ALL EXCEPT)和空的 activate_role_default 都会调用该 checkout。而 activate_role_none 随后会执行 set_master_access(user->access)。
已记录的弯路:第一次残留测试 SELECT note FROM lab.t INTO OUTFILE 返回 1142(db_acl() 缓存为 0)。常量 SELECT 'witness' INTO OUTFILE 才是 FILE 的判定依据。
cd lab
./run.sh
镜像 mysql:26.7.0。发布端口 127.0.0.1:18630。角色 rfile 拥有 FILE。受害者拥有 GRANT SELECT ON lab.* 和 GRANT rfile,file_priv=N,无默认角色。登录时 outfile 返回 1227。SET ROLE rfile 后 outfile 成功。SET ROLE ALL EXCEPT rfile 使 CURRENT_ROLE() 为 NONE;残留 outfile 写入 /var/lib/mysql-files/MYSQL-SET-ROLE-LEFTOVER-WITNESS。SET ROLE NONE 后再次返回 1227。
SUCCESS mysql-set-role-leftover before-file=denied with-role=yes leftover-role=NONE leftover-file=yes after-none=denied dump=26.7.0 image=mysql:26.7.0 MYSQL-SET-ROLE-LEFTOVER-WITNESS
当 m_active_roles 为空时,checkout_access_maps() 应像 SET ROLE NONE 已经做的那样调用 set_master_access(user->access)。空的 ALL EXCEPT / DEFAULT 不应保留先前聚合的权限映射。
06a5c1c99c377fc41b2eba1ea244e8b220bdc3c8)sql/auth/sql_security_ctx.cc checkout_access_mapssql/auth/roles.cc activate_role_all / activate_role_none