Locking Down Javascript Engines
Total Page:16
File Type:pdf, Size:1020Kb
NoJITsu: Locking Down JavaScript Engines Taemin Park∗, Karel Dhondt†, David Gens∗, Yeoul Na∗, Stijn Volckaert†, Michael Franz∗ ∗Department of Computer Science, University of California, Irvine †Department of Computer Science, imec-DistriNet, KU Leuven NDSS 2020 1 Importance of JavaScript Engine Protection • Every browser has a JavaScript engine • JavaScript engines are always exposed to malicious scripts JavaScript engine 2 JIT Spraying Semantic of a different Start point D9D0 FNOP Start here 54 PUSH ESP 3c 35 CMP AL,35 Script JIT’ed code Original semantic 58 POP EAX var y = ( 90 NOP 0x3c54d0d9 ^ B8D9D0543C MOV EAX,3C54D0D9 90 NOP 0x3c909058 ^ 355890903C XOR EAX,3C909058 3c 35 CMP AL,35 0x3c59f46a ^ 356AF4593C XOR EAX,3C59F46A 6a F4 PUSH -0C 0x3c90c801 ^ 3501C8903C XOR EAX,3C90C801 59 POP ECX 0x3c9030d9 ^ 35D930903C XOR EAX,3C9030D9 3c 35 CMP AL,35 0x3c53535b ^ JIT 355B53533C XOR EAX,3C53535B 01c8 ADD EAX,ECX …….) compile 90 NOP 3C 35 CMP AL,35 D930 FSTENV DS:[EAX] • Embed malicioUs codes in the hUge nUmber of conStants with XOR operation • Trigger a vUlnerability to jUmp in the middle of codeS Writing JIT-Spray Shellcode for fun and profit, Alexey SintSov AthanaSakiS, M., AthanaSopouloS, E., PolychronakiS, M., PortokalidiS, G., & IoannidiS, S. (2015). The Devil iS in the ConstantS: BypaSSing DefenseS in BrowSer JIT EngineS. PreSented at the ProceedingS 2015 Network 3 and DiStributed SyStem Security SympoSium. Advanced Attacks and Defenses on JIT’ed Code • Attack utilizing race condition • Corrupt JIT IR when it is being compiled • Write on JIT’ed region when JIT’ed code is emitted to memory • Putting JIT compilation into a separate process or trusted execution environment compileJIT compilation Isolation unit compile JIT IR Write Interpreter mprotect(W) emit Write JIT’ed code mprotect(R/X) JavaScript engine Song, C., Zhang, C., Wang, T., Lee, W., & Melski, D. (2015). Exploiting and Protecting Dynamic Code Generation. Presented at the Proceedings 2015 Network and Distributed System Security Symposium. 4 Frassetto, T., Gens, D., Liebchen, C., & Sadeghi, A.-R. (2017). JITGuard: Hardening Just-in-time Compilers with SGX (pp. 2405–2419). New York, New York, USA: ACM Contribution • Attack: Bytecode Interpreter attack • Change the behavior of interpreter execution by corrupting core data of the interpreter • Lead to arbitrary system call • Defense: NoJITsu • Fine-Grained Memory access control • Protect JIT’ed code and the core data of interpreter • Thorough Evaluation 5 JavaScript Engine Execution Flow and Core Data JavaScript Bytecode Compiler Bytecode Object Script Interpreter Object Table Data Dispatcher Load 1 Bytecode instruction Load / Store Arithmetic Function call JIT IR JIT Compiler JIT’ed code 6 Core data Bytecode Interpreter Attack • Corrupt the function call routine to run a system call • Attack on the SpiderMonkey • Threat model • Memory-corruption vulnerability • Arbitrary read / write capability • Code-injection defense • W⨁X enforced • Light weight code-reuse defense • ASLR, coarse-grained CFI 7 Bytecode Interpreter Attack Script foo Bytecode foo object Table foo(){ Load argument &Arg obj cos(30) Load function &Func obj } Call function VUL_CVE_2019_11707() Type confusion vulnerability obj Func obj Context obj Arg obj Arbitrary read / write ) ….. &system&cos “cmd” 30 VUL_CVE_2019_11707() foo() system(*cosfunc) (”(&contextcmd”) , 30arg ) Interpreter 8 NoJITsu Key1, WritableRead-only Key6, Read-only Key2, Writable Key15, Read-only • Fine-grained memory access control through Intel Memory Protection Key • Intel MPK (Memory Protection Key) Key5, Execute-only Key1,Key1, Read Writable-only • A new hardware feature to control the protection of memory • Fast permission change Memory (Thread1) • Support execute-only permission • Thread local Key1, Writable Key6, Writable Key2, Read-only Key1, Read-only Key15, Writable Register Key5, Read-only Key1, Read-only Memory (Thread2) 9 NoJITsu Thread Thread Bytecode BytecodeBytecode(R) set_pkey(W,key) Write Write Object table ObjectObject tablestable (R) (R/W) (R) Sensitive set_pkey(R,key) JS Object PrimitiveJS Object object (R) object (R) mprotect(W) JIT IR JITJIT IR IR (R) set_pkey(W,key) Write Write Write JIT’ed code (R/X) JIT’edJIT’ed codecode (X) (X) mprotect(R/X) set_pkey(X,key) Legacy NoJITSu • Need to open write window For leGal write instructions • How do we Find all write instructions to each kind oF data. • How do we implement permission chanGes For them. 10 Bytecode, Object Table, JIT IR and JIT’ed Code • Bytecode, indirection table Compile_bytecode() • Only need write permission at bytecode compilation { ….. • JIT’ed code, JIT IR ….. • Only need write permission at JIT compilation saved_pkru = set_pkru(W, key_bytecode) • JIT’ed code contains data needing read-permission write bytecode • Jump table, Large constant recover_pkru(saved_pkru) ….. ….. JIT’ed code } (Machine instruction + Data) Machine Instruction Data (Execute-only) (Read-only) 11 JavaScript Object • There are a huge number of write access instructions to JS object throughout JS code base. Manual effort? Static analysis? JavaScript Engine code base Dynamic analysis JS Object pool 12 Dynamic Analysis foo(){ Segmentation …. fault Custom signal …. handler write write instruction (Read(Writable)-only) Instrumented code JS Object pool Is MPK violation? Became writable? saved_pkru = set_pkru(W, key_obj) for(I = 0 ; I < 100000 ; i++) } { Add function foo foo(); } foo() recover_pkru(saved_pkru) { saved_pkru = set_pkru(W, key_obj) … … Function list recover_pkru(saved_pkru) 13 } Dynamic Analysis – Input Set JavaScript Engine code base JS Object pool 14 Dynamic Analysis – Input Set • Member accessor, Payload Accessor, Initialization accessor, GC accessor • Gateways to write on JS object and extensively shared among other functions • Use official JavaScript test suites as our input set • Include test cases for kinds of objects JavaScript Engine code base Member Payload Initialization GC accessor Accessor accessor accessor JS Object pool 15 Evaluation • Coverage of Dynamic Object-Flow Analysis • Pick only 1/6 of full test suites as input set for dynamic analysis • Successfully run full test suites without error JIT test suites Full test suites (6,000 test cases) (30,000 test cases) JavaScript Engine Function list with NoJITsu • Code-Reuse attack and bytecode interpreter attack • Successfully stop JIT-ROP and our bytecode interpreter attack 16 Evaluation • Performance • LongSpider benchmarks • Intel Xeon silver 4112 machine under Ubuntu 18.04.1 LTS 17 Evaluation • Performance • LongSpider benchmarks • Intel Xeon silver 4112 machine under Ubuntu 18.04.1 LTS 5% overhead 3% overhead 18 Conclusion • Demonstrate a new attack that leverages the interpreter to execute arbitrary shell commands • Propose NoJITsu, hardware-backed fine-grained memory access protection for JS engines • Evaluate our defense, showing the effectiveness in code-reuse attack and our bytecode interpreter attack on JS engines with a moderate overhead 19 Thank You Q&A 20 Performance Optimization • Hoist protections out of loops bar() { saved_pkru = set_pkru(W, key_bytecode) for(I = 0 ; I < 100000 ; i++) { foo(); } foo() recover_pkru(saved_pkru) { } saved_pkru = set_pkru(W, key_bytecode) … … recover_pkru(saved_pkru) } 21 Dynamic Analysis {Well-defined Input set} JavaScript Engine Function list JavaScript Engine For Dynamic with protection analysis changes foo() { What is the well-defined saved_pkru = set_pkru(W, key_bytecode) … input set? … recover_pkru(saved_pkru) } 22 Machine Code and Data Separation Code pointers Large constants jmp* rip, offset offset jmp* rip, 2 jmp* rip, offset hlt 2 Jump Jump address Padding Jump table offset table jmp* rip, 2 Jump address hlt 2 Jump address Jump address Large constants Machine instruction Relocation Table Relocation Table Data Code pointers 23 Evaluation 24.