
Prometheus v3.15.0 - Alta - Remoto - Fuga de credenciales - remote_write google_iam/azuread reenvía Bearer en 3xx entre hosts
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · prometheus-bearer-redirect
Clase: Fuga de credenciales Alcance: Remoto
Prometheus v3.15.0 (5241a27) - CNCF / Prometheus
prometheus/common v0.71.0 ya elimina las credenciales de scrape / HTTPClientConfig en redirecciones entre hosts (isCrossHostRedirect, #901). NewWriteClient construye ese cliente primero y luego envuelve azuread.NewAzureADRoundTripper o googleiam.NewRoundTripper fuera de la eliminación. follow_redirects sigue teniendo true por defecto.
Si la URL de remote_write configurada responde 301/302/307 hacia otro host, Prometheus envía Authorization: Bearer junto con el token monitoring.write de Azure AD o GCP a ese host. Go ya había descartado la cabecera copiada. Estos RoundTrippers la vuelven a establecer.
No es CVE-2026-42151 (volcado de client_secret en /-/config). El prometheus.yml por defecto no tiene remote_write. Esto está condicionado a azuread: o google_iam:.
| ID | sin CVE todavía |
| Clase | Fuga de credenciales (Bearer de remote_write en 3xx entre hosts) |
| Alcance | Remoto (saliente desde Prometheus hacia un objetivo 3xx) |
| CWE | CWE-201 |
| CVSS | Alto: 8.6 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N |
| Producto | Prometheus |
| Afectado | v3.15.0 (5241a27fe3c6983549fccc32f6e65917408c63cd), imagen prom/prometheus:v3.15.0 |
| Auth | remote_write condicionado por configuración con azuread: o google_iam: |
| Licencia | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
El operador tiene remote_write con azuread: o google_iam:. La URL de RW, o un salto al que responde 3xx, es un host que el atacante controla.
| Privilegio | Método / sink | Probado en lab o inferido |
|---|---|---|
Leer el Bearer monitoring.write de GCP en vivo en un 3xx entre hosts | POST de remote_write con google_iam, 307 hacia otro host | Probado en lab. El oráculo POST /write recibió Authorization: Bearer lab-gcp-PROMETHEUS-BEARER-REDIRECT-WITNESS |
Misma fuga para azuread | azureADRoundTripper.RoundTrip siempre hace Header.Set("Authorization", "Bearer "+token) sin isCrossHostRedirect | Inferido del código fijado. Mismo punto de envoltura en NewWriteClient. El lab usó google_iam, así que no llamó a Azure |
| Reutilizar ese token contra Azure Monitor / GCP Monitoring como esa identidad | El token es una credencial de nube real cuando esos bloques de auth están configurados | Inferido. El lab generó un token de prueba; no llamó a Azure ni a GCP |
| Scrape / oauth2 / basic / bearer en el mismo pin | RoundTrippers de HTTPClientConfig de common v0.71.0 | Probado en lab, cerrado. El GET de scrape oauth2 siguió el 302 hacia el mismo oráculo sin Authorization |
| OSS por defecto | remote_write vacío | Cerrado |
remote_write.headers estableciendo Authorization | rechazado | Cerrado |
/-/config volcando client_secret | CVE-2026-42151; el campo está tipado como Secret en este pin | Cerrado |
| Admin / ciclo de vida de Prometheus | flags desactivados por defecto | Cerrado |
| RCE / una shell | no es este remanente | Cerrado |
Fijé el tag v3.15.0 de prometheus/prometheus después de la oleada de redacción de secretos y límites de snappy de 3.11/3.12. Diecinueve búsquedas. OSS por defecto: API de admin, ciclo de vida HTTP, receptor de remote-write y receptor OTLP desactivados. Common #901 está en v0.71.0. El remanente son los dos envoltorios de remote_write que quedan fuera de ese cliente.
func (rt *azureADRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
accessToken, err := rt.tokenProvider.getAccessToken(req.Context())
// ...
req.Header.Set("Authorization", bearerAccessToken)
return rt.next.RoundTrip(req)
}
googleiam.NewRoundTripper es google.golang.org/api/transport/http -> oauth2.Transport, que hace SetAuthHeader en cada salto.
Caminos equivocados ya registrados: volver a reportar CVE-2026-42151; tratar el scrape oauth2 como si aún filtrara (no lo hace); llamar a esto un Alto de instalación por defecto (no lo es - remote_write está vacío hasta que lo activas). Teatro: una reverse shell. El oráculo es un Bearer en el POST redirigido.
python3 prometheus-bearer-redirect-Abraxas-Labs.py
o
cd lab
./run.sh
Solo loopback: Prometheus http://127.0.0.1:19380, oráculo http://127.0.0.1:19381. Imagen prom/prometheus:v3.15.0. run.sh escribe un gcp-sa.json de lab con token_uri: http://hop:8080/token para que google_iam nunca hable con Google.
SUCCESS prometheus-bearer-redirect how=live rw-method=POST rw-bearer=yes token-has-witness=yes scrape-method=GET scrape-bearer=no PROMETHEUS-BEARER-REDIRECT-WITNESS
Omitir la inclusión del Bearer de Azure AD / Google IAM cuando isCrossHostRedirect(req), igual que common #901. No volver a establecer Authorization después de que Go lo descartó en un 3xx entre hosts.
5241a27fe3c6983549fccc32f6e65917408c63cd)storage/remote/client.go · storage/remote/azuread/azuread.go · storage/remote/googleiam/googleiam.goGNU Affero GPL v3.0. Ver LICENSE. Solo lab en loopback. Sin garantía.