
Prometheus v3.15.0 - 높음 - 원격 - SSRF - http_sd __unix_socket__ UDS 스크레이프의 정리되지 않은 Dial 잔여물
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · prometheus-unix-socket-dial
분류: SSRF 도달 범위: 원격
Prometheus v3.15.0 (5241a27) - CNCF / Prometheus
v3.15.0에서 Unix Domain Socket 스크레이프가 추가되었습니다(#12024 / #18091). 이 경로는 운영자 허용 목록이 아니라 대상 레이블 __unix_socket__입니다. http_sd와 file_sd는 해당 레이블을 그대로 복사합니다. PopulateLabels는 이를 전혀 검증하지 않습니다. 그런 다음 newUnixSocketScrapeClient가 filepath.Clean도, 허용 목록도, ../ 또는 Linux 추상 @ 이름에 대한 거부도 없이 DialContext(ctx, "unix", socketPath)를 호출합니다.
TCP 스크레이프로는 이 작업을 할 수 없습니다. CheckTargetAddress는 여전히 /를 포함하는 __address__ 값을 버리므로, 주소로서의 unix:///var/run/docker.sock은 거부됩니다. 새로운 레이블이 바로 그 구멍입니다.
기본 구성은 이 레이블을 설정하지 않습니다. 인증되지 않은 HTTP로 Prometheus에 접근해도 작업을 추가할 수 없습니다. 이는 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 레이블 작성자 (또는 신뢰할 수 없는 메타데이터를 __unix_socket__으로 복사하는 relabel) |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1 전용 |
http_sd JSON(또는 쓰기 가능한 file_sd)에 대한 제어만으로 충분합니다. SD URL은 운영자 구성입니다. 남는 부분은 그룹 labels가 __unix_socket__을 설정할 수 있고 Prometheus가 이를 Dial한다는 점입니다.
| 권한 | 방법 / 싱크 | 랩 입증 또는 추론 |
|---|---|---|
| Prometheus UID가 열 수 있는 호스트 unix 소켓에 연결 | __unix_socket__으로부터 clientForTarget -> DialContext(ctx, "unix", socketPath) | 랩 입증. http_sd로부터의 경로 /sockets/jail/../oracle.sock; 스크레이프 상태 up |
해당 경로에서 ../ 따라가기 | filepath.Clean 없음 / .. 거부 없음 | 랩 입증. 커널이 순회를 /sockets/oracle.sock으로 해석 |
| Linux 추상 소켓 Dial | @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는 보통 노출 파싱에 실패하므로, 높음 등급은 Docker JSON의 TSDB 유출이 아니라 연결/GET에 대한 것 |
| Docker 변경 (컨테이너 생성, 쓰기) | 스크레이프 동사 | 닫힘. 스크레이프는 GET 전용 |
| 인증되지 않은 Prometheus HTTP로 스크레이프 작업 추가 | /-/reload, admin API | 닫힘. 두 플래그 모두 기본적으로 꺼져 있음; reload에는 본문이 없음 |
| 기본 예제 구성에서 사용 | __unix_socket__ 미설정; 예제는 TCP로 localhost:9090을 스크레이프 | 닫힘. 트리 내 k8s/consul/docker SD는 __meta_*만 내보냄; 해당 접두사는 relabel 후 삭제됨 |
벤더 보안 모델은 이미 SD가 TCP 스크레이프 대상을 선택하도록 허용합니다. 새로운 기본 요소는 __address__가 지정할 수 없었던 호스트 IPC입니다.
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는 여전히 주소의 /를 거부합니다. URL()은 __scheme__ / __address__ / __metrics_path__로부터 scheme/host/path를 유지합니다; 소켓은 dial 전용입니다.
이미 기록된 잘못된 방향: SD가 이미 TCP 대상을 선택하므로 이를 모델 내 NONE으로 평가하는 것(새로운 기본 요소는 호스트 IPC); unix:///var/run/docker.sock을 __address__로 두는 것을 구멍으로 취급하는 것(이는 거부됨); 기본 예제 구성이 이 잔여물이라고 주장하는 것. 극적인 요소: 리버스 셸. 오라클은 SD JSON이 지정한 소켓에서의 스크레이프 상태 up입니다.
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를 제공하고 두 개의 unix HTTP 오라클을 제공합니다: 파일시스템 /sockets/oracle.sock과 추상 @prom-lab-oracle. Prometheus는 127.0.0.1:19390에 게시됩니다. Admin API와 lifecycle은 꺼진 상태로 유지됩니다.
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, 둘 다 상태 up. TCP 슬래시는 활성 대상이 된 적이 없습니다.
SD로부터의 __unix_socket__을 정제된 절대 파일시스템 경로가 되기 전까지 Dial하지 마십시오. 빈 값, NUL, Linux 추상 @ 이름, 상대 경로, 그리고 filepath.Clean 후의 모든 ..를 거부하십시오. 스크레이프 YAML의 접두사 허용 목록이 더 강력합니다. 운영자 구성에서 온 것이 아니라면 PopulateDiscoveredLabels에서 레이블을 삭제하는 것도 SD 주입을 막습니다.
5241a27fe3c6983549fccc32f6e65917408c63cd)scrape/scrape.go · scrape/target.go · config/config.goGNU Affero GPL v3.0. LICENSE 참조. 루프백 랩 전용. 보증 없음.