abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sqlite-fj-using-auth
技术分析文章:https://abraxaslabs.tech/research/sqlite-fj-using-auth
类别: 权限残留 影响范围: 本地
SQLite 3.53.4(b09c88c / SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc)- Hwaci
lookupName() 会将 FULL JOIN USING 的列改写为 coalesce(...)(TK_FUNCTION)。sqlite3AuthRead 仅对 TK_COLUMN / TK_TRIGGER 执行,因此 USING 列永远不会触发 SQLITE_READ 回调。一个安装了 sqlite3_set_authorizer 并对 t2.x 的 READ 设置为 DENY/IGNORE 的嵌入方,仍然可以通过 SELECT x FROM t1 FULL JOIN t2 USING(x) 返回该列。
默认打开时授权器处于关闭状态。这是该 C API 的残留问题。并非 RCE。FULL JOIN ON 和 LEFT JOIN USING 仍会被拒绝 / 不会泄露。显式使用 coalesce(t2.x) 仍会经过授权。
| ID | 暂无 CVE |
| 类别 | 权限残留(列级授权器跳过) |
| 影响范围 | 本地(嵌入方 sqlite3_set_authorizer;攻击者 SQL) |
| CWE | CWE-863、CWE-284 |
| CVSS | 高危:7.5 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| 产品 | SQLite(GitHub 镜像 sqlite/sqlite) |
| 受影响版本 | 3.53.4(b09c88c14082339b66c7b7158d609a771e64ca69)。仅 3.54 才有的授权器 FULL JOIN USING 修复(2cb2287768)未包含在此 GA 版本中。 |
| 授权 | 嵌入方安装了 sqlite3_set_authorizer;默认回调为 NULL |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1:18840。见证字符串。并非 RCE。 |
针对将 sqlite3_set_authorizer 用作列级 ACL 的嵌入方,准备 SELECT x FROM t1 FULL JOIN t2 USING(x)(或 NATURAL FULL JOIN)。裸 SELECT x FROM t2 会被拒绝(SQLITE_AUTH 23)。FULL JOIN USING 形式会返回被拒绝 READ 的列。不会触发任何 READ t2.x 回调。
除非嵌入方安装授权器,否则授权器处于关闭状态。默认的 sqlite3_open 不存在此残留问题。并非 RCE。
在 PHP 之后,对 3.53.4 进行了二十次源码排查。跳过列表已经列出了 3.54 的 FULL JOIN USING 授权器签入。它在最新的 GA 版本中仍然缺失。在 lookupname_end 处,pExpr->op 为 TK_FUNCTION,因此 AuthRead 门控永远不会执行。WRC_Prune 还会阻止遍历器深入 coalesce 参数。
lookupname_end:
if( cnt==1 ){
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pParse->db->xAuth
&& (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER)
){
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
}
#endif
已记录的误判:将 authorizer 视为默认开启;期望 LEFT JOIN USING 或 FULL JOIN ON 会泄露;期望显式 coalesce(t2.x) 会跳过 AuthRead;在 3.54.0 仍为草稿时将其固定。
cd lab
./run.sh
构建官方 sqlite-src-3530400 amalgamation。测试框架为 lab/auth.c。回环地址 127.0.0.1:18840。授权器 DENY READ t2.x。SELECT x FROM t2 被拒绝。SELECT x FROM t1 FULL JOIN t2 USING(x) 返回见证结果,0 次 READ t2.x。FULL JOIN ON 被拒绝。LEFT JOIN USING 无泄漏。IGNORE 基线为 NULL;IGNORE FULL JOIN USING 仍然泄漏。
SUCCESS sqlite-fj-using-auth how=full-join-using-skip-authread baseline=denied fj-using=witness fj-on=denied left-using=no-leak SQLITE-FJ-USING-AUTH-WITNESS
在 coalesce 重写之后,对每个 pFJMatch 子节点循环调用 sqlite3AuthRead,就像 trunk 2cb2287768 / Git 5694c3bb 在 3.54 中所做的那样。仅对 a[0] 进行授权(bbd69ce274)是不够的。LEFT JOIN USING 和 FULL JOIN ON 已经会进行授权;它们不属于这个遗留问题。
b09c88c14082339b66c7b7158d609a771e64ca69)src/resolve.c 中的 lookupName coalesce 重写与 AuthRead 门控src/auth.c 中的 sqlite3AuthRead / sqlite3AuthReadCol