V8 Sandbox

송민준·2024년 10월 9일

도입

2021~23년 동안 원격 코드 실행으로 악용된 메모리 손상 취약점 중 60%가 V8 취약점이다.

ex

 1. for (int index = 0; index < length_; index++) {
 2.     JSValue js_value = buffer_[index];
 3.     int value = ToNumber(js_value).int_value();
 4.     if (value % 15 == 0)
 5.         buffer_[index] = JSString("fizzbuzz");
 6.     else if (value % 5 == 0)
 7.         buffer_[index] = JSString("buzz");
 8.     else if (value % 3 == 0)
 9.         buffer_[index] = JSString("fizz");
10. }

ToNumber는 obj.toString을 실행시키기 때문에 사용자가 임의로 조작한 함수를 실행시켜 의도치 않은 동작(배열의 크기를 조작해서 배열 범위를 벗어난 메모리에 접근하는 등)을 야기할 수 있다.

let obj = {
	toString: function() {
		buffer_.length_ = 1;
		return "100";
	}
};

V8 Sandbox

메모리 손상으로 인해 V8 엔진 내에서 발생하는 문제들이 프로세스의 다른 메모리 영역으로 확산되는 것을 방지하기 위한 솔루션

원리는 운영체제의 사용자 공간과 커널 공간을 분리하는 원리와 유사하다.

= V8 샌드박스는 V8 엔진의 힙 메모리를 다른 프로세스의 메모리와 분리해서 다른 프로세스에 영향을 미치지 않도록 함.

그리고 샌드박스는 하드웨어의 지원없이 소프트웨어 기반으로 구현되었다.

동작

V8 샌드박스는 V8 엔진의 데이터 타입을 변경해서 특정 포인터를 샌드박스 호환 형태로 변환하는 방식을 사용한다. → 샌드박스 외부 프로세스, 메모리 접근 시도 차단

내부 포인터 처리

  • 두가지 새로운 타입 도입 (포인터 및 크기 데이터 변환 방지)
    • sandbox_ptr_t (포인터 변환 방지): 샌드박스 내부에서 사용하는 포인터. 실제 메모리 주소 대신 샌드박스 시작 주소로부터의 오프셋을 사용한다. (외부 프로세스, 메모리 접근 시도 차단)
    • sandbox_size_t (크기 데이터 변환 방지): 메모리 크기를 나타내는 데이터 타입. 샌드박스 내의 메모리 크기를 제한한다.

외부 포인터 처리

외부 리소스(파일, 데이터베이스)와 상호작용을 해야 할 때도 있기 때문에 직접적인 메모리 참조를 위험하다.

그래서 간접적인 포인터 관리 방식을 사용한다.

  • external_ptr_t: 샌드박스 내부에서 외부 메모리 참조. 포인터 테이블이라는 특수한 테이블을 통해 외부 메모리에 접근한다.
    • 포인터 테이블: 외부 메모리에 대한 참조를 저장하는 테이블. 외부 포인터가 필요할 때 실제 주소가 이 테이블에 저장된다.
      • 메모리 접근 시도는 항상 이 테이블을 거치게 된다. 그래서 공격자가 메모리 주소를 악용하기 어렵다.

profile
개발자

0개의 댓글