The Dynamics of Innocent Flesh on the Bone
The Dynamics of Innocent Flesh on the Bone Code Reuse Ten Years Later Victor van der Veen, Dennis Andriesse, Manolis Stamatogiannakis, Xi Chen†, Herbert Bos, and Cristiano Giuffrida Vrije Universiteit Amsterdam †Microsoft
Takeaway 1) Gadget finding: dynamic static analysis 2) Compare four classes of defenses Control-Flow Integrity | Information Hiding | Re-Randomization | Pointer Integrity 3) Break the state-of-the-art
Static Flesh on the Bone Shacham at CCS 2007 • ret 2 libc without any function call • Combine short instruction sequences to build gadgets • The first systematic formulation of code reuse Return-Oriented Programmin • Highly influential (900 citations) CCS 2017 Test of Time Award
Static Flesh on the Bone Impact • Shaped how we think about code reuse: 1. Analyze the geometry of victim binary code 2. Locate gadgets 3. Chain gadgets to craft an exploit • Initiated much research, almost an arms race Model never changed Discover gadgets by means of static analysis
Threat Model Baseline • ASLR + DEP + Coarse-Grained CFI + Shadow stack (no classic ROP) Attackers • Arbitrary memory read/write • Access to the binary • Goal is to divert control flow (no data-only attacks)
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program 2. Identify gadgets not covered by defenses 3. Publish! push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program 2. Identify gadgets not covered by defenses 3. Publish! Defender 1. Examine identified gadgets push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program 2. Identify gadgets not covered by defenses 3. Publish! Defender 1. Examine identified gadgets 2. Invent a way to restrict those 3. Publish! push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program 2. Identify gadgets not covered by defenses 3. Publish! Defender 1. Examine identified gadgets 2. Invent a way to restrict those 3. Publish! push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Victim binary code (gadgets) Code-Reuse Research Loop Attacker 1. Analyze the program 2. Identify gadgets not covered by defenses 3. Publish! Defender 1. Examine identified gadgets 2. Invent a way to restrict those 3. Publish! push push mov sub mov mov xor callq mov movl callq movabs movl movb mov mov movq movb cmp je sub je callq mov callq test je movl movb jmp mov xor movl callq movl movb movl movb movl movq movb callq test mov je mov mov callq test js cltq xor mov callq movq callq test mov je cmpb jne lea xor mov %r 15 %r 14 %r 13 %r 12 %rbp %rbx %edi, %ebx %rsi, %rbp $0 x 388, %rsp (%rsi), %rdi %fs: 0 x 28, %rax, 0 x 378(%rsp) %eax, %eax 40 db 00 $0 x 419 ac 1, %esi $0 x 6, %edi 402840 $0 x 4165 f 1, %esi $0 x 4165 da, %edi 4024 b 0 $0 x 4165 da, %edi 402470 $0 x 40 a 320, %edi $0 x 2, 0 x 21 bb 18(%rip) 413 c 30 $0 x 800000000, %rax $0 x 0, 0 x 21 c 5 af(%rip) $0 x 1, 0 x 21 c 650(%rip) %rax, 0 x 21 c 701(%rip) 0 x 21 bad 7(%rip), %eax $0 x 0, 0 x 21 c 700(%rip) $0 xffffffffffffffff, 0 x 21 c 6 ed(%rip) $0 x 0, 0 x 21 c 646(%rip) $0 x 2, %eax 403328 $0 x 3, %eax 402 aef $0 x 1, %eax 402 aca 402370 $0 x 1, %edi 4023 e 0 %eax, %eax 4035 a 6 $0 x 2, 0 x 21 c 672(%rip) $0 x 1, 0 x 21 c 60 b(%rip) 402 b 05 $0 x 7, %esi %edi, %edi $0 x 0, 0 x 21 c 658(%rip) 40 eca 0 $0 x 416603, %edi $0 x 0, 0 x 21 c 640(%rip) $0 x 0, 0 x 21 c 632(%rip) $0 x 0, 0 x 21 c 62 a(%rip) $0 x 0, 0 x 21 c 621(%rip) $0 x 0, 0 x 21 c 619(%rip) $0 x 0, 0 x 21 c 5 f 7(%rip) $0 x 0, 0 x 21 c 5 d 8(%rip) $0 x 1, 0 x 21 c 5 ca(%rip) $0 x 0, 0 x 21 c 5 c 1(%rip) $0 x 0, 0 x 21 c 5 b 9(%rip) $0 x 0, 0 x 21 c 5 aa(%rip) $0 x 0, 0 x 21 c 597(%rip) $0 x 0, 0 x 21 c 584(%rip) $0 x 0, 0 x 21 c 602(%rip) 402310 %rax, %r 12 402 bbf $0 x 4, %ecx $0 x 419200, %edx $0 x 419240, %esi %rax, %rdi 409 f 70 %eax, %eax 403343 %edi, %edi 0 x 419200(, %rax, 4), %esi 40 eca 0 $0 x 416611, %edi $0 x 50, 0 x 21 c 501(%rip) 402310 %rax, %r 12 402 be 5 $0 x 0, (%rax) 403564 0 x 30(%rsp), %rdx %eax, %eax $0 x 5413, %esi $0 x 1, %edi
Mindset of Defenders (Academics) Assume static analysis for gadget retrieval, we • Constrained control-flow transfers (CFI) • (re)Randomize code + data • Enforce pointer integrity State of the Art of War • Not many gadgets left (millions > thousands > dozens) • Remaining gadgets are hard to find Code-reuse attacks are hard
Mindset of Attackers (real world) Attackers • Do not care about gadgets or ROP chains or Turing completeness • Only need to call execve or mprotect with controllable args • Have no reason to limit themselves to static analysis What memory values should I modify to gain control? Change the Model this with Dynamic Taint Analysis
Dynamic Analysis What memory values should I modify to gain control? 1. Get the destination binary into a quiescent state 2. Taint attacker-controlled bytes (all of rw memory) 3. Monitor branches – taint sinks – that depend on tainted memory Callsite target + arguments 4. Dump taint source for each sink
Modeling Code-Reuse Defenses Write constraints What memory values can I modify? Arbitrary memory write: anything in data memory • Code pointers • Data pointers • Other values (integers, characters, …) A defense may limit what we can corrupt With Code Pointer Integrity, I cannot modify any pointer
Modeling Code-Reuse Defenses Target constraints What can I target? Arbitrary memory read: any function in code memory • All functions of the target binary • All functions of libc • + any other library A defense may limit what we can target With Control-Flow Integrity, I can only target a subset of all functions
Newton Automated gadget finding with Dynamic Analysis Binary + libraries Target constraints Write constraints Static analysis Dynamic analysis Newton Gadget Callsite cs is tainted by addresses and may call function Newton Gadgets
Newton in Practice (on nginx) Scenario 1/4 Baseline Target constraints • None – we can target anything Write constraints • None – we can corrupt everything
Memory map Baseline $>. /nginx localhost $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! nginx. text nginx. data [heap] [unmapped] libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf $>. /nginx localhost $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [heap] [unmapped] ngx_conf_t *conf; GET / HTTP/1. 0 libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf $>. /nginx localhost $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! ngx_conf_t *conf; conf->handler = ngx_proxy_handler; GET / HTTP/1. 0 [heap] [unmapped] libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State $>. /nginx localhost $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [heap] • Minimal set of interaction ngx_conf_t *conf; • Server is stable conf->handler = ngx_proxy_handler; • Only long-lived data in memory GET / HTTP/1. 0 [unmapped] libc. text libc. ro libc. data …
Memory map Baseline Quiescent State nginx. text nginx. data *conf [heap] [newton] $> taint-all-memory [unmapped] libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State [heap] [newton] $> taint-all-memory [newton] $> monitor-indirect-calls [unmapped] GET / HTTP/1. 0 libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State [newton] $> taint-all-memory [heap] *r [newton] $> monitor-indirect-calls [unmapped] GET / HTTP/1. 0 ngx_http_request_r *r; r->content_handler = conf->handler; libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State [newton] $> taint-all-memory [heap] *r [newton] $> monitor-indirect-calls [unmapped] GET / HTTP/1. 0 ngx_http_request_r *r; r->content_handler = conf->handler; r->content_handler(r) libc. text libc. ro libc. data …
Memory map nginx. text Baseline nginx. data *conf Quiescent State $>. /nginx localhost $> nc -v localhost 80 [heap] Arbitrary memory read/write Connection to localhost 80 port [tcp/http] succeeded! ngx_conf_t *conf; conf->handler = ngx_proxy_handler; GET / HTTP/1. 0 Baseline [unmapped] libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State [heap] • Let conf->handler point to system() [unmapped] libc. text libc. ro libc. data …
Memory map Baseline nginx. text nginx. data *conf Quiescent State [heap] • Let conf->handler point to system() • Send GET request [unmapped] libc. text system() libc. ro libc. data …
Memory map Baseline Quiescent State nginx. text nginx. data *conf [heap] *r • Let conf->handler point to system() • Send GET request [unmapped] ngx_http_request_r *r; r->content_handler = conf->handler; libc. text system() libc. ro libc. data …
Memory map Baseline Quiescent State nginx. text nginx. data *conf [heap] *r • Let conf->handler point to system() • Send GET request [unmapped] ngx_http_request_r *r; r->content_handler = conf->handler; r->content_handler(r); libc. text system() libc. ro libc. data …
Newton in Practice (on nginx) Scenario 1/4 Baseline Target constraints • None – we can target anything Write constraints • None – we can corrupt everything
Newton in Practice (on nginx) Scenario 2/4 Baseline + e. Xecute-not-Read (Xn. R) Target constraints • No access to code pages • Only target live code pointers Write constraints • None – we can corrupt everything
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State [heap] Quiescent State [unmapped] • Minimal set of interaction • Server is stable • Only long-lived data in memory libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State [heap] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> monitor-indirect-calls • Minimal set of interaction • Server is stable • Only long-lived data in memory libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State [heap] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> monitor-indirect-calls Scan data memory for code pointers • Minimal set of interaction • Server is stable • Only long-lived data in memory libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State conf->handler [heap] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> monitor-indirect-calls Scan data memory for code pointers • . data | heap | stack |. GOT | … • Typical nginx run: 767 live code pointers libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State conf->handler [heap] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> monitor-indirect-calls Scan data memory for code pointers • . data | heap | stack |. GOT | … • Typical nginx run: 767 live code pointers Including mprotect() libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State [heap] Arbitrary memory read/write [unmapped] Baseline + Xn. R • Minimal set of interaction • Server is stable • Only long-lived data in memory libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read nginx. text nginx. data *conf Quiescent State [heap] • Let conf->handler point to mprotect() • Send GET request [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read Quiescent State nginx. text nginx. data *conf [heap] *r • Let conf->handler point to mprotect() • Send GET request [unmapped] mprotect() ngx_http_request_r *r; libc. text libc. ro libc. data …
Memory map e. Xecute-not-Read Quiescent State nginx. text nginx. data *conf [heap] *r • Let conf->handler point to mprotect() • Send GET request [unmapped] mprotect() ngx_http_request_r *r; libc. text r->content_handler = conf->handler; r->content_handler(r); libc. ro libc. data …
Newton in Practice (on nginx) Scenario 2/4 Baseline + e. Xecute-not-Read (Xn. R) Target constraints • No access to code pages • Only target live code pointers Write constraints • None – we can corrupt everything
Newton in Practice (on nginx) Scenario 3/4 Baseline + Xn. R + Cryptographic CFI (CCFI) Target constraints • No access to code pages • Only target live code pointers Write constraints • We can corrupt everything, except code pointers
Memory map Cryptographic CFI $>. /nginx localhost nginx. text nginx. data [heap] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI $>. /nginx localhost nginx. data *ls [heap] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_listening_t *ls; ls->handler = http_init_connection; libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI $>. /nginx localhost $> nc -v localhost 80 nginx. data *ls [heap] *lc Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_listening_t *ls; ls->handler = http_init_connection; libc. text libc. ro ngx_connection_t *lc; lc->listening = ls libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State nginx. data *ls [heap] *lc Quiescent State [unmapped] libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State nginx. data *ls [heap] *lc [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State nginx. data *ls [heap] *lc [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> taint-wash-code-pointers mprotect() libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State nginx. data *ls [heap] *lc [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> taint-wash-code-pointers [newton] $> monitor-indirect-calls mprotect() libc. text GET / HTTP/1. 0 libc. ro lc->listening->handler(c); libc. data …
Memory map nginx. text Cryptographic CFI nginx. data *ls Quiescent State [heap] *lc Arbitrary memory read/write [unmapped] Baseline + Xn. R + CCFI mprotect() libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State • Construct counterfeit ls object nginx. data *ls [heap] *lc [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State • Construct counterfeit ls object nginx. data *ls [heap] *lc • Corrupt lc->listening data pointer (make it point to our ls) [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map nginx. text Cryptographic CFI Quiescent State • Construct counterfeit ls object nginx. data *ls *lc • Corrupt lc->listening data pointer (make it point to our ls) • Send GET request lc->listening->handler(lc); [heap] [unmapped] mprotect() libc. text libc. ro libc. data …
Newton in Practice (on nginx) Scenario 3/4 Baseline + Xn. R + CCFI Target constraints • No access to code pages • Only target live code pointers Write constraints • We can corrupt everything, except code pointers
Newton in Practice (on nginx) Scenario 4/4 Baseline + Xn. R + CPI Target constraints • No access to code pages • Only target live code pointers Write constraints • We can corrupt everything, except code and data pointers
Memory map Code-Pointer Integrity $>. /nginx localhost nginx. text nginx. data [heap] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity nginx. text nginx. data *ops $>. /nginx localhost [heap] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_http_log_op_s *ops; libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity $>. /nginx localhost nginx. text nginx. data *ops *v v[0] v[1] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_http_log_op_s *ops; ngx_http_variable_t *v; // array ops->data = 0; libc. text libc. ro libc. data … v[2]
Memory map Code-Pointer Integrity $>. /nginx localhost nginx. text nginx. data *ops *v 0 v[0] v[1] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_http_log_op_s *ops; ngx_http_variable_t *v; // array ops->data = 0; v[i]. get_handler = ngx_. . . libc. text libc. ro libc. data … v[2]
Memory map Code-Pointer Integrity $>. /nginx localhost nginx. text nginx. data *ops *v 0 v[0] v[1] $> nc -v localhost 80 Connection to localhost 80 port [tcp/http] succeeded! [unmapped] ngx_http_log_op_s *ops; ngx_http_variable_t *v; // array ops->data = 0; v[i]. get_handler = ngx_. . . libc. text libc. ro libc. data … v[2]
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] Quiescent State [unmapped] libc. text libc. ro libc. data … v[2]
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] [newton] $> get-live-code-pointers [unmapped] libc. text libc. ro libc. data … v[2]
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] v[2] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] v[2] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> taint-wash-code-pointers mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] v[2] [newton] $> get-live-code-pointers [newton] $> taint-all-memory [unmapped] [newton] $> taint-wash-code-pointers [newton] $> taint-wash-data-pointers [newton] $> monitor-indirect-calls GET / HTTP/1. 0 v[index]. get_handler(r, . . . ); mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity nginx. text nginx. data *ops 0 Quiescent State *v v[0] v[1] v[2] Arbitrary memory read/write [unmapped] Baseline + Xn. R + CPI libc. text libc. ro libc. data … mprotect()
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 0 v[0] v[1] v[2] • Overwrite data field in ops [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 3 v[0] v[1] v[2] • Overwrite data field in ops • data = 3; [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 4 v[0] v[1] v[2] • Overwrite data field in ops • data = 4; [unmapped] mprotect() libc. text libc. ro libc. data …
Memory map Code-Pointer Integrity Quiescent State nginx. text nginx. data *ops *v 5 v[0] v[1] v[2] • Overwrite data field in ops • data = 5; • Send GET request [unmapped] mprotect() v[5]. get_handler(r, . . . ); libc. text libc. ro libc. data …
Newton in Practice (on nginx) Scenario 4/4 Baseline + Xn. R + CPI Target constraints • No access to code pages • Only target live code pointers Write constraints • We can corrupt everything, except code and data pointers
Newton in Practice Controlling arguments • Examples only show to divert control-flow • Use the same mechanics for arguments
Modeling Defenses 30 defenses IFCC, MCFI, Type. Armor, Per. Input, Path. Armor, GRIFFIN, Flow. Guard, k. Bouncer, ROPecker Oxymoron, Readactor, Xn. R, Hide. M, LR 2, Khide, k. R^X, Heisenbyte, NEAR, Readactor++, Code. Armor, Shuffler, Re. Ranz, TASR, ASR 3, Runtime. ASLR, ASLR-Guard, Cryptographic CFI, CPS, CPI 8 target constraints 3 write constraints
Target constraints Equivalence classes! Write constraints
Controllable Callsites for nginx Write Constraint None ¬CPtr ¬Ptr Segregated Tainted 35 13 8 2
Controllable Callsites for nginx Write Constraint None ¬CPtr ¬Ptr Segregated Tainted 35 13 8 2
Controllable Callsites for nginx Write Constraint None ¬CPtr ¬Ptr Segregated Tainted 35 13 8 2
Controllable Callsites for nginx Write Constraint None ¬CPtr ¬Ptr Segregated Context-Sensitive CFI Tainted 35 13 8 2 • Minimal coverage with GET / HTTP/1. 0 • One callsite can be enough
#Allowed Targets for nginx Target Constraint nginx libc other all None 1, 035 2, 763 794 4, 592 Live 362 316 89 767 Source-level CFI 12 0 0 19
#Allowed Targets for nginx Target Constraint nginx libc other all None 1, 035 2, 763 794 4, 592 Live 362 316 89 767 Source-level CFI 12 0 0 19 ASLR + Shadow Stack + Coarse-grained CFI
#Allowed Targets for nginx Target Constraint nginx libc other all None 1, 035 2, 763 794 4, 592 Live 362 316 89 767 Source-level CFI 12 0 0 19 Readactor, Xn. R, Hide. M, LR 2, Khide, k. R^X, Heisenbyte, NEAR, Shuffler, Code. Armor, Re. Ranz, TASR, ASR 3, Runtime. ASLR, ASLR-Guard, Cryptographic CFI, CPS, CPI
#Allowed Targets for nginx Target Constraint nginx libc other all None 1, 035 2, 763 794 4, 592 Live 362 316 89 767 Source-level CFI 12 0 0 19 Enforced statically: results are for the median callsite
Similar Results for Other Servers Server apache redis … Write constraint None ¬CPtr ¬Ptr nginx Tainted 35 13 8 33 27 13 14 11 11 Targets Live 6, 113 1, 985 5, 381 4, 592 612 767
Conclusion https: //vusec. net/newton 10 years of code-reuse • Crafting code-reuse attacks is hard • Attacks and defenses assume static analysis Newton • Consider the dynamics and find that there is still leeway • Use reported gadgets to compare defenses The next 10 years of code-reuse • Combine state-of-the-art defenses to reduce exploitability • Reduce overhead of more heavyweight defenses
BACKUP SLIDES
Our Policy Open source everything
Segregated State Context-Sensitive CFI (Cs. CFI) • Target constraints are impractical: • How does the context-sensitive analysis works? • What is the branch history size? • When is validation performed? • Perfect Cs. CFI: arbitrarily large history, but not unlimited Write constraint • Limit writes to a segregated state
Segregated State Bypassing Context-Sensitive CFI (Cs. CFI) Segregated 1. Corrupt an independent and stable application state Historywith flushing 2. Send idempotent inputs that do not interfere the state 3. Send final input to trigger exploit setup in 1) Bypassing Cs. CFI in practice • Multiple connections handled by a single process • Connection-specific data of connection 1 as segregated state • Perform requests over connection 2 to flush history
Evaluating nginx – Target Constraints Target Constraint None Live +page nginx 1, 035 811 libc 2, 763 1, 264 other 794 411 all 4, 592 2, 486 Computed 363 323 100 786 Live ¬GOT Binary types Safe source types Source types 362 360 328 117 12 316 279 960 176 0 89 69 370 65 0 767 708 1, 665 376 19
Modeling Defenses Control-Flow Integrity • Limits the valid targets for a callsite • 4 types of target constraints Bypass context-Sensitive CFI with history flushing: write constraint IFCC, MCFI, Type. Armor, Per. Input, Path. Armor, GRIFFIN, Flow. Guard, k. Bouncer, ROPecker Information Hiding • Prevent code-reuse by hiding gadgets: no write constraint • 3 types of target constraints around live Oxymoron, Readactor, Xn. R, Hide. M, LR 2, Khide, k. R^X, Heisenbyte, NEAR, Readactor++, Code. Armor
Modeling Defenses Re-Randomization • Hide code-layout: only live targets • 3 classes of write constraints: none, ¬CPtr, ¬Ptr Shuffler, Code. Armor, Re. Ranz, TASR, ASR 3, Runtime. ASLR Pointer Integrity • Cannot craft new pointers: only live targets • 3 classes of write constraints: none, ¬CPtr, ¬Ptr ASLR-Guard, Cryptographic CFI, CPS, CPI
Bounds checking in CPI (Oct. 30) “CPI does (Soft. Bounds-style) bounds checking” • CPI paper is not explicit on this topic • Attacks work for simple toy programs compiled with –fcpi • Currently investigating, will update paper if necessary • Implementation bug: only protected writes, but not reads? https: //vusec. net/newton
- Slides: 94