Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp Figured out size of buffer!
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaf41 parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaf41 parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaf42 parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaf42 parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadc41fe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadc41fe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp
Perfect for brute forcing • Forked process has same saved ret memory layout and contents as saved ebp 0xbadcaffe parent, including canary values! %ebp 0x41414141 • The fork on crash lets us try 0x41414141 different canary values 0x41414141 %esp Figured out size of canary!
Buffer overflow mitigations • Avoid unsafe functions (last lecture) • Stack canaries • Separate control stack • Memory writable or executable, not both (W^X) • Address space layout randomization (ASLR)
Separate control stack Problem: Control data is stored next to data Solution: Bridge the implementation and abstraction gap: separate the control stack User stack arg i+1 Control stack arg i %ebp local 1 saved ret local 2 saved ebp %esp %esp’
Safe stack Problem: Unsafe data structures stored next to control Solution: Move unsafe data structures to separate stack Safe stack arg i+1 arg i Unsafe stack saved ret saved ebp %ebp &i local var buf local var %esp’ %esp
How do we implement these? • There is no actual separate stack, we only have linear memory and loads/store instructions • Put the safe/separate stack in a random place in the address space ➤ Location of control/stack stack is secret
How do we defeat this? Find a function pointer and overwrite it to point to shellcode!
Buffer overflow mitigations • Avoid unsafe functions (last lecture) • Stack canaries • Separate control stack • Memory writable or executable, not both (W^X) • Address space layout randomization (ASLR)
W^X: write XOR execute • Goal: prevent execution of shell code from the stack • Insight: use memory page permission bits ➤ Use MMU to ensure memory cannot be both writeable and executable at same time • Many names for same idea: ➤ XN: eXecute Never ➤ W^X: Write XOR eXecute ➤ DEP: Data Execution Prevention
Recall our memory layout kernel user stack shared libs runtime heap static data segment text segment unused
Recall our memory layout kernel user stack rw shared libs rx runtime heap rw static data rw segment text segment rx unused
Recall our memory layout kernel user stack rw saved ret saved ebp shared libs rx %ebp buf[0-3] runtime heap rw %esp static data rw segment text segment rx unused
Recall our memory layout kernel shellcode user stack rw hijacked ret shared libs rx %ebp runtime heap rw %esp static data rw segment text segment rx unused
Recall our memory layout kernel shellcode user stack rw hijacked ret shared libs rx %ebp runtime heap rw %esp static data rw segment text segment rx unused
W^X tradeoffs • Easy to deploy: No code changes or recompilation • Fast: Enforced in hardware ➤ Downside: what do you do on embedded devices? • Some pages need to be both writeable and executable ➤ Why?
How can we defeat W^X? • Can still write to return address stored on the stack ➤ Jump to existing code • Search executable for code that does what you want ➤ E.g. if program calls system(“/bin/sh”) you’re done ➤ libc is a good source of code (return-into-libc attacks)
Normal system() call &cmd saved ret %esp
Redirecting control flow to system() • We redirected control flow in previous lecture to baz() saved ret saved ebp • Calling system() is the same, %ebp buf[4-7] but need to have argument to buff[0-3] %esp string “/bin/sh” on stack
saved ret saved ebp %ebp buf[4-7] buff[0-3] %esp
saved ret ???? %ebp %esp
&system ???? %ebp %esp
&cmd &exit &system ???? %ebp %esp
“/bin/sh” &cmd &exit &system ???? %ebp %esp
“/bin/sh” &cmd &exit &system ???? %ebp %esp mov %ebp, %esp leave = pop %ebp
“/bin/sh” &cmd &exit &system ???? %esp, %ebp mov %ebp, %esp leave = pop %ebp
%ebp ???? “/bin/sh” &cmd &exit &system %esp ???? mov %ebp, %esp leave = pop %ebp
%ebp ???? “/bin/sh” &cmd &exit &system %esp ???? ret = pop %eip
%ebp ???? “/bin/sh” &cmd &exit %esp &system ???? %eip &system ret = pop %eip
To system this looks like a normal call “/bin/sh” arg0 &cmd saved ret &exit %esp
But I want to execute shellcode, not just call system() !
Can we inject code?
Can we inject code?
Can we inject code? • Just-in-time compilers produce data that becomes executable code • JIT spraying: ➤ 1. Spray heap with shellcode (and NOP slides) ➤ 2. Overflow code pointer to point to spray area
What does JIT shellcode look like?
What does JIT shellcode look like?
What does JIT shellcode look like?
Buffer overflow mitigations • Avoid unsafe functions (last lecture) • Stack canaries • Separate control stack • Memory writable or executable, not both (W^X) • Address space layout randomization (ASLR)
ASLR kernel user stack • Traditional exploits need precise addresses ➤ stack-based overflows: shellcode shared libs ➤ return-into-libc: library addresses • Insight: Make it harder for attacker to runtime heap guess location of shellcode/libc by static data randomizing the address of different segment memory regions text segment unused
Recommend
More recommend