Wasmtime fixed a critical sandbox escape bug (CVSS 9.3)
Wasmtime, 비동기 콜백의 스택 버퍼 오버플로 수정
Wasmtime의 비동기 콜백 결과 타입 검증이 빠져 악성 WebAssembly 컴포넌트가 네이티브 스택에 최대 약 16KB의 데이터를 쓸 수 있는 취약점이 발견됐습니다. Wasmtime 48.0.4와 49.0.2에서 수정했으며, 패치 전에는 비동기 컴포넌트 기능을 끄거나 수정된 wasmparser를 사용해야 합니다.
- 주제
에디터 노트
이번 취약점은 wasmparser의 타입 검사 오류가 Wasmtime의 여러 신뢰 가정과 맞물려 스택 쓰기로 이어졌다는 점이 구체적으로 드러납니다. 콜백 시그니처를 검증하는 단계뿐 아니라 컴파일러와 런타임에도 경계 검사가 없었고, 권고문은 이 결함을 샌드박스 탈출로 다루라고 명시합니다. 댓글은 오타의 인간적인 측면과 정적 분석 도구의 한계를 언급하지만, SAST가 실제로 이 오류를 탐지하지 못했을 것이라는 말은 댓글 작성자의 추정입니다. 권고문은 탐지 도구를 평가하지 않습니다. 공개된 대응은 수정 버전으로 올리거나 비동기 기능을 끄고, 수정된 wasmparser로 먼저 검증하는 것입니다.
AI 요약
Wasmtime에서 컴포넌트 모델의 비동기 콜백 타입을 제대로 검증하지 않아 네이티브 스택 버퍼 오버플로가 발생합니다. 악성 게스트는 프로세스 네이티브 스택에 자신이 고른 데이터를 최대 약 16KB까지 쓸 수 있으며, 반환 주소를 덮어쓰면 호스트 코드로 제어를 넘기거나 프로세스를 중단시킬 수 있습니다. 주소 공간 배치 난수화(ASLR)와 비실행 스택이 단순한 코드 실행 시도를 막을 수는 있지만, Wasmtime은 임베더가 이를 임의 코드 실행을 동반할 수 있는 샌드박스 탈출 취약점으로 취급해야 한다고 안내합니다.
취약점 발생 과정
Wasmtime은 WebAssembly 모듈과 컴포넌트의 유효성을 wasmparser에 맡깁니다. 이번에는 wasmparser v0.259.0 이하에서 비동기 리프트(async-lifted) 내보내기에 쓰이는 콜백 함수의 타입 시그니처 검증이 잘못됐습니다. 올바른 검증 조건은 함수가 i32 매개변수 세 개를 받고 i32 결과 하나를 반환하는지 확인하는 것입니다. 그러나 오타 때문에 함수가 i32 매개변수 세 개를 받거나 i32 매개변수 하나를 받는지만 확인했고, 반환 타입은 검사하지 않았습니다. 그 결과 유효하지 않은 컴포넌트가 거부되지 않고 통과했습니다.
Wasmtime도 컴포넌트를 내부 표현으로 변환할 때 콜백 함수의 인덱스만 기록하고 반환 타입과 인자 수를 재검증하지 않았습니다. wasmparser가 이미 확인했다고 가정했기 때문입니다. 이후 컴파일러는 콜백 호출용 호스트-투-게스트 트램폴린을 만들면서 대상 함수 시그니처에 맞는 매개변수·결과 배열 크기가 충분한지 런타임에 확인하지 않았습니다. 런타임 역시 실제 콜백의 결과 개수가 아니라 예상한 결과 개수에 맞춰 스택에 반환 영역을 할당했습니다. 이 세 단계에서 검증이 이어지지 않아 게스트가 더 큰 결과를 기록할 때 스택 버퍼를 넘겨 쓸 수 있었습니다.
패치와 우회 방법
Wasmtime은 48.0.4와 49.0.2에서 문제를 수정했습니다. 패치 전에는 component-model-async 기능을 끄면 비동기 콜백을 포함한 비동기 기능이 있는 컴포넌트를 Wasmtime이 거부합니다. 또는 wasmparser v1.260.0 이상으로 컴포넌트를 먼저 검증해 잘못된 컴포넌트를 거부한 뒤 Wasmtime에 전달할 수 있습니다.
Reddit 반응
- @u/Feeling_Simple_9371 — 이 일정에서 오타 하나로 CVSS 9.3이 나온 건 그럴듯합니다. &&를 || 대신 쓴 건 너무나 인간적인 실수입니다. 누군가는 커피를 세 잔 마시고 그 줄만 들여다보다가 그냥 지나쳤을 겁니다.
- @u/Western-Obligation47 — 안타깝게도 SAST나 Semgrep 같은 의미 기반 SAST도 이 문제를 잡아내지 못했을 겁니다.
- @u/Konsti219 — Clanker
원문: Wasmtime 보안 권고 / 번역·요약: Trawling