WebAssembly의 Binary Security

choehojun·2023년 6월 26일
1

WebAssembly

목록 보기
4/4

서론

이 포스트는 Everything old is new again: binary security of webassembly 논문의 내용을 정리한 내용이다. 더 자세한 내용을 알고 싶으면 위의 논문을 참고하길 바란다.

WebAssembly의 두 가지 memory

  • managed memory : managed memory는 VM에 의해 직접적으로 관리되는 storage로, local variables, global variables, 그리고 return addresses가 저장되어 VM에 의해 관리된다.

  • unmanaged memory : 이는 linear memory라고도 불리우며, wasm 파일과 JS 파일에서 읽고 쓰이는 데이터가 연속적으로 저장되는 버퍼이다. 또한, string, array, list와 같은 non-scalar 데이터들은 unmanaged memory에 저장된다. unmanaged memoryoffset이 정해져있므며, memory.grow instruction에 의해서 offset이 늘어나 동적으로 memory를 확장할 수 있다. WebAssembly는 C나 C++와는 다르게, 메모리 전체에 접근할 수 있는 것이 아니라 현재 알려진 offset을 통하여 현재 할당된 메모리 영역에만 접근할 수 있다.

WebAssembly의 Binary Security

이미지 출처: https://dl.acm.org/doi/pdf/10.5555/3489212.3489225

위의 이미지를 보면, WebAssembly 파일에는 DEPSSP 와 같은 일반적인 mitigation들이 적용되어 있지 않다. 따라서, modern compiler에 의해서 C/C++에서는 이제 거의 수행할 수 없는 buffer overflowstack overflow와 같은 공격들을 WebAssembly에서는 수행할 수 있다. 다만, return addressmanaged memory에 저장되어 VM에 의해 직접적으로 관리되기 때문에, ROP와 같은 공격들은 수행할 수 없고, unmanaged memory에 대하여 overflow류 공격들을 수행하여 data corruption을 발생시켜서 indirect call의 redirection을 발생시킨다던지, eval(), exec()과 같은 위험한 API 함수에 들어가는 argument의 내용을 변경시키는 등의 공격을 수행할 수 있다. 더 자세한 예시는 밑에서 설명하도록 하겠다.

공격 예시 (1)

이미지 출처: https://dl.acm.org/doi/pdf/10.5555/3489212.3489225

위 공격은 CVE-2018-14550 취약점이 존재하는 libpng C 라이브러리를 이용해 공격을 수행하는 예시이다. libpng 라이브러리는 PNM 파일을 PNG 파일로 변경시켜주는 라이브러리인데, 이를 수행할 때 buffer overflow가 발생하여 exploit할 수 있는 CVE-2018-144550 취약점이 존재한다. 하지만, modern compiler 들에서는 stack canary를 제공하여 이러한 취약점을 방어할 수 있는데, WebAssembly 파일은 stack canary가 제공되지 않아 이러한 취약점을 통해 공격을 수행할 수 있다. 만약, buffer overflow를 통하여 위의 C++ 코드의 <img> 태그 부분을 <script> 태그로 바꿔서 이를 실행시킬 수 있다면, XSS 공격을 수행할 수 있을 것이다. 이는 WebAssembly에서 string literalunmanaged memory에 저장된다는 사실과 여기에는 stack canary가 적용되어 있지 않다는 사실을 이용한 공격이다.

공격 예시 (2)

이 공격의 이해를 위해서는, 이전 포스트를 참고하면 좋을 것 같다.

이미지 출처: https://dl.acm.org/doi/pdf/10.5555/3489212.3489225

간단히 설명하자면, WebAssembly에서 indirect call을 수행할 때, call_indirect instruction을 수행하는데, 이 instruction은 unmanaged stack의 value를 pop하여 이 값을 table section의 index로 활용한다. 그리고, 그 index에 해당하는 함수를 불러올 때 type-correctness를 보장하기 위하여 VM은 정적으로 type-checking을 수행하는데, WebAssembly에는 i32, i64, f32, f64의 4가지 primitive type만이 존재하여 redirection 공격의 폭을 넓힐 수 있다.

이미지 출처: https://dl.acm.org/doi/pdf/10.5555/3489212.3489225

위 사진은 이러한 사실을 이용하여 공격을 수행할 수 있는 코드의 예시인데, C++ 코드에서는 log_happy, log_unhappy 함수의 signature와 exec 함수의 signature가 다른데, WebAssembly에서는 이러한 세 함수의 함수 signature가 모두 같다. 따라서, log_happylog_unhappy 함수에 대한 indirect call이 수행되기 전에, call_indirect instruction 실행 전에 unmanaged stack의 맨 위 값을 table section에서 exec 함수의 포인터가 저장되어 있는 index로 바꾸면, 정적 type-checking을 통과하여 정상적으로 실행된다.

공격 예시 (3)

이미지 출처: https://dl.acm.org/doi/pdf/10.5555/3489212.3489225

마지막 공격은 unmanaged memory에 저장되는 string literal을 변경하여 수행할 수 있는 공격인데, 위 C++ 코드에서는 fopen의 인자들을 constant string 값으로 주고 있는데, C/C++를 컴파일하면 이러한 string literal.rodata 섹션에 저장되어 이를 바꿀 수 없다. 하지만, WebAssembly에서는 이러한 값이 unmanaged memory에 저장되어 이러한 값을 바꿀 수 있다. 따라서, "file.txt" 값을 변경하여 fopen을 통해 여는 파일을 변경할 수 있고, "a"를 변경하여 mode를 변경할 수도 있다. 또한, fprintf의 인자로 넘겨지는 "Append constant text."를 변경하여 파일에 쓰려고 하는 string을 변경할 수도 있을 것이다.

결론

WebAssembly에는 DEP, SSP와 같은 일반적인 방어 기법이 적용되지 않고, primitive type의 개수도 제한적으로 존재하여 binary security에 치명적인 결함이 존재한다. 그리고, 이러한 사실을 이용하여 공격을 수행하는 예시들을 위에서 설명하였다.

참고 문헌

profile
보안 전공을 희망하는 학부생

0개의 댓글