
प्रोमेथियस v3.15.0 - उच्च - रिमोट - SSRF - http_sd __unix_socket__ अनसैनिटाइज़्ड डायल UDS स्क्रैप का अवशेष
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · prometheus-unix-socket-dial
राइट-अप: https://abraxaslabs.tech/research/prometheus-unix-socket-dial
वर्ग: SSRF पहुँच: रिमोट
Prometheus v3.15.0 (5241a27) - CNCF / Prometheus
v3.15.0 में Unix Domain Socket स्क्रैप जोड़ा गया (#12024 / #18091)। यह पथ एक टारगेट लेबल __unix_socket__ है, ऑपरेटर allowlist नहीं। http_sd और file_sd उस लेबल को जैसा है वैसा ही कॉपी कर देते हैं। PopulateLabels इसे कभी मान्य नहीं करता। इसके बाद newUnixSocketScrapeClient बिना किसी filepath.Clean, बिना allowlist, और ../ या Linux abstract @ नामों को अस्वीकार किए बिना DialContext(ctx, "unix", socketPath) कॉल करता है।
TCP स्क्रैप ऐसा नहीं कर सकता। CheckTargetAddress अभी भी उन __address__ मानों को हटा देता है जिनमें / होता है, इसलिए पते के रूप में unix:///var/run/docker.sock अस्वीकार कर दिया जाता है। नया लेबल ही यह छिद्र है।
स्टॉक कॉन्फ़िग लेबल सेट नहीं करता। Prometheus पर बिना प्रमाणीकरण वाला HTTP जॉब्स नहीं जोड़ सकता। यह SD-गेटेड है।
| ID | अभी तक कोई CVE नहीं |
| वर्ग | SSRF (SD लेबल से असैनिटाइज़्ड unix Dial) |
| पहुँच | रिमोट (SD-गेटेड: http_sd / file_sd का लेखक) |
| CWE | CWE-918, CWE-22 |
| CVSS | उच्च: 8.6 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N |
| उत्पाद | Prometheus |
| प्रभावित | v3.15.0 (5241a27fe3c6983549fccc32f6e65917408c63cd), इमेज prom/prometheus:v3.15.0 |
| प्रमाणीकरण | SD-गेटेड: http_sd / file_sd लेबल का लेखक (या एक relabel जो अविश्वसनीय मेटा को __unix_socket__ में कॉपी करता है) |
| लाइसेंस | GNU Affero GPL v3.0 |
| लैब | केवल 127.0.0.1 |
http_sd JSON (या लिखने योग्य file_sd) पर नियंत्रण ही पर्याप्त है। SD URL ऑपरेटर कॉन्फ़िग है। बची हुई बात यह है कि समूह labels __unix_socket__ सेट कर सकते हैं और Prometheus उस पर Dial करेगा।
| विशेषाधिकार | विधि / सिंक | प्रयोगशाला-प्रमाणित या अनुमानित |
|---|---|---|
| उस होस्ट यूनिक्स सॉकेट से कनेक्ट करें जिसे Prometheus UID खोल सकता है | clientForTarget -> DialContext(ctx, "unix", socketPath) जो __unix_socket__ से आता है | प्रयोगशाला-प्रमाणित। http_sd से पथ /sockets/jail/../oracle.sock; स्क्रैप स्वास्थ्य up |
उस पथ में ../ का अनुसरण करें | कोई filepath.Clean नहीं / कोई .. अस्वीकृति नहीं | प्रयोगशाला-प्रमाणित। कर्नेल ने ट्रैवर्सल को /sockets/oracle.sock में हल किया |
| Linux एब्स्ट्रैक्ट सॉकेट को डायल करें | @name का वही Dial | प्रयोगशाला-प्रमाणित। __unix_socket__=@prom-lab-oracle; स्क्रैप स्वास्थ्य up |
| उस सॉकेट पर Prometheus UID के रूप में HTTP GET करें | स्क्रैप GET है; __metrics_path__ अनुरोध पथ है | प्रयोगशाला-प्रमाणित। GET /fs-traversal और /abstract; User-Agent Prometheus/; lab_witness अंतर्ग्रहीत |
| उन सॉकेट तक पहुँचें जिन्हें TCP स्क्रैप नाम नहीं दे सकता | CheckTargetAddress __address__ में / को अस्वीकार करता है | प्रयोगशाला-प्रमाणित। __address__ के रूप में unix:///var/run/docker.sock ने is not a valid hostname लॉग किया; सक्रिय लक्ष्य नहीं; prometheus_target_sync_failed_total=1 |
| यदि वे सॉकेट दायरे में हों तो Docker Engine / kubelet HTTP API पर GET करें | __unix_socket__=/var/run/docker.sock के साथ एक Docker API पथ | अनुमानित। वही अनसैनिटाइज़्ड Dial। यह प्रयोगशाला वास्तविक इंजन सॉकेट माउंट नहीं करती। JSON API आमतौर पर एक्सपोज़िशन पार्स में विफल होते हैं, इसलिए High कनेक्ट/GET है, Docker JSON का TSDB एक्सफ़िल नहीं |
| Docker को परिवर्तित करें (कंटेनर बनाएँ, लिखें) | स्क्रैप क्रियाएँ | बंद। स्क्रैप केवल-GET है |
| अन-ऑथ Prometheus HTTP पर स्क्रैप जॉब जोड़ें | /-/reload, admin API | बंद। दोनों फ़्लैग डिफ़ॉल्ट रूप से बंद; reload में कोई बॉडी नहीं |
| इसे डिफ़ॉल्ट उदाहरण कॉन्फ़िग पर उपयोग करें | __unix_socket__ अनसेट; उदाहरण TCP पर localhost:9090 स्क्रैप करता है | बंद। इन-ट्री k8s/consul/docker SD केवल __meta_* उत्सर्जित करते हैं; वे प्रीफ़िक्स relabel के बाद हटा दिए जाते हैं |
विक्रेता का सुरक्षा मॉडल पहले से ही SD को TCP स्क्रैप लक्ष्य चुनने देता है। नया प्रिमिटिव होस्ट IPC है जिसे __address__ नाम नहीं दे सकता था।
मैंने UDS स्क्रैप के लिए 3.15 FEATURE लाइन के बाद prometheus/prometheus v3.15.0 को पिन किया। इस पिन पर डिफ़ॉल्ट OSS में admin API, lifecycle HTTP, remote-write receiver, और OTLP receiver बंद हैं। PopulateDiscoveredLabels हर http_sd समूह लेबल को कॉपी करता है। __unix_socket__ __meta_* नहीं है, इसलिए यह मेटा वाइप से बच जाता है। PopulateLabels केवल __address__ की जाँच करता है।
func (sp *scrapePool) clientForTarget(t *Target) *http.Client {
socketPath := t.labels.Get(UnixSocketLabel)
if socketPath == "" {
return sp.client
}
client, err := newUnixSocketScrapeClient(socketPath, ...)
func newUnixSocketScrapeClient(socketPath string, ...) (*http.Client, error) {
optFuncs = append([]config_util.HTTPClientOption{config_util.WithDialContextFunc(
func(ctx context.Context, _, _ string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", socketPath)
},
)}, optFuncs...)
CheckTargetAddress अभी भी address में / को अस्वीकार करता है। URL() __scheme__ / __address__ / __metrics_path__ से scheme/host/path रखता है; socket केवल dial-only है।
पहले से दर्ज गलत मोड़: इसे in-model NONE के रूप में स्कोर करना क्योंकि SD पहले से ही TCP लक्ष्य चुनता है (नया primitive host IPC है); unix:///var/run/docker.sock को __address__ के रूप में छेद मानना (यह अस्वीकृत है); दावा करना कि डिफ़ॉल्ट उदाहरण कॉन्फ़िग यह अवशेष है। नाटक: एक reverse shell। Oracle उन sockets पर scrape health up है जिन्हें SD JSON ने नाम दिया।
python3 prometheus-unix-socket-dial-Abraxas-Labs.py
या
cd lab
./run.sh
prom/prometheus:v3.15.0 एक Python साइडकार के साथ नेटन्स (netns) साझा करता है। साइडकार 127.0.0.1:8080/targets.json पर http_sd और दो यूनिक्स HTTP ओरेकल परोसता है: फ़ाइलसिस्टम /sockets/oracle.sock और एब्सट्रैक्ट @prom-lab-oracle। Prometheus 127.0.0.1:19390 पर प्रकाशित है। Admin API और लाइफसाइकिल बंद रहते हैं।
SUCCESS prometheus-unix-socket-dial sd=http_sd fs-traversal=yes abstract=yes tcp-slash-rejected=yes how=sd-labels PROMETHEUS-UNIX-SOCKET-DIAL-WITNESS
IOC: scrapeUrl=http://localhost:1/fs-traversal और /abstract, दोनों का health up है। TCP slash कभी भी सक्रिय लक्ष्य नहीं बना।
SD से __unix_socket__ को तब तक Dial न करें जब तक कि यह एक सैनिटाइज़ किया गया निरपेक्ष फ़ाइलसिस्टम पथ न हो। खाली मान, NUL, Linux abstract @ नाम, सापेक्ष पथ, और filepath.Clean के बाद कोई भी .. अस्वीकार करें। scrape YAML से प्राप्त prefixes की allowlist अधिक मज़बूत होती है। PopulateDiscoveredLabels से label को तब तक हटाना जब तक कि यह operator config से न आया हो, SD injection को भी बंद कर देता है।