|
Writeup Authors
- Michael Dalton - mwdalton at cs.stanford.edu
- Douglas Wightman - wightman at stanford.edu
Talk Overview
- Speaker: Alex Sotirov
- Vulnerability engineer, Determina
- Reverse engineers software to find vulnerabilities, bugs
- ANI Bug
- Described critical new bug in WinXP/Vista
- Reverse Engineering
- Described tools for reverse engineering
- Showed how reverse engineered ANI Bug
- Exploitation
- Discussed Windows security mechanisms (ASLR, /GS)
- Describes how ANI exploit bypasses them
- Gave secure design rules and lessons learned
ANI exploit
- Buffer overflow in dynamic cursor handling routines in Windows system code
- Exploited host ran on VMWare
- Exploit gives full access (arbitrary command execution) - spawned shell
- In real-world, inject DLLs because shell functionality in windows is restricted
- Privilege level same as user running browser
- Patch took 3 months for Microsoft to issue
- Needed to edit 4 lines
- Usually 'audit all surrouding code' - part of secure development practices at Microsoft
- Why are security patch lifecycles so long?
Reverse Engineering
- Goal: understand assembly code in binaries
- Why reverse engineer Microsoft patches?
- Vulnerabilities not well described (or described at all)
- Patches often 'silently' fix security flaws
- Need to tell clients of Determina if they are protected
- Reverse Engineering Tools
- IDA Pro
- Platform/framework for static analysis of binaries
- Handles disassembly, visualization, etc
- Robust plugin infrastructure
- http://www.datarescue.com/
- Bindiff
- Plugin for IDA Pro
- Shows semantic differences between functions in binary object files
- Useful for determining what functions were changed by Microsoft's patch
- VMWare
- Can use VM for 'backwards' debugging
- Take VM snapshots, roll back to previous snapshot when need to examine past state
- How new ANI bug was discovered
- Apply Microsoft's 2005 patch for previous ANI bug
- Use BinDiff to determine what functions were changed
- Length check (must equal 36) inserted in LoadCursorIconFromFileMap before call to ReadChunk
- Without this check => stack overflow
- But what about other functions that call ReadChunk?
- Found other call site, LoadAniIcon
- No length check => new vulnerability!
Exploitation
- Must bypass Vista Security Mechanisms
- Data Execute Protection (DEP)
- Microsoft /GS stack protection (stackguard)
- Address Space Layout Randomization
- stackguard not apply to ANI exploit, ASLR and DEP are bypassed
- DEP
- Intel, AMD recently added support for executable bit on pages
- Can prevent code injection - no executing code on stack/heap
- Opt-in on Windows, turned off by default for legacy apps
- Would break JIT, self-modifying code, etc
- Weakness: existing code gives attacker all they need
- Can break by using ret into libc, or returning into DLLs that disable DEP
- ANI bug uses latter technique - disable DEP and jump into exploit payload
- Microsoft /GS stack protection (stackguard)
- Reorders local variables, places canary before frame pointer/stack pointer
- If canary value changes before function return, terminate with security error
- Similar to open source ProPolice
- Propolice has been merged into GCC 4.x
- ANI exploit overlays a structure, not an array
- /GS protection only protects arrays, canary not even compiled into vulnerable function
- No need to bypass directly
- Can also bypass by exploiting overflows that are not on the stack, or clobbering local pointers to overwrite canary to known value
- Address Space Layout Randomization (ASLR)
- Changes mappings of dynamic linked libraries, stack, heap to have 8 bits of entropy/randomness
- Limitation is due to Application Binary Interface, alignment restrictions, 32-bit address space
- Will improve when full 64-bit address spaces supported
- Mitigate attacks with harcoded addresses
- 8 bits of entropy is very small
- 1 in 256 chance of success is pretty good if attacking millions of hosts....
- But can we do better anyway?
- (Side note: could also bypass ASLR by using anything with a fixed address/non-randomized, which includes certain libraries)
- Bypassing ASLR: heap spraying
- Combat this imprecision by having a huge section of memory with payload
- Pad with tons of nops
- Preferably hundreds of MB in size
- If our value is off by a few KB, who cares? Just land in a sea of nops
- Bypassing ASLR: least significant byte overwrites
- Even simpler method possible
- x86 is little endian, least significant bytes are overwritten first in a buffer overflow
- If we can find a pointer that is within 64KB of our payload...
- Just overwrite least significant 2 bytes of pointer with our expected value
- Now we have a 1 in 16 chance of success!
- This is because bits 0-11 form the page offset, which is not randomized
- Only bits 12-15 may be randomized, giving us a 1 in 16 chance of success
- Putting it all together - bypassing ASLR+DEP
- ANI routine includes exception handler that recovers from access violations
- So just supply 256 ANI files (brute force the 8 bits of entropy) to find location of function in ntdll to disable DEP...
- Any access violations caught, ignored by ANI routine exception handler
- Exploit jumps to existing DEP disable code, then executes payload
- Don't need to brute force location of payload due to use of heap spraying
Secure Software Design
- Security is difficult to retrofit
- Design secure by default!
- Adapting security to legacy applications (e.g. Windows) extremely difficult, costly
- Field is a moving target
- Even the most secure designs can only protect against known vulnerabilities
- Stay abreast of industry developments, changes
- Ex: discovery of format string bugs in 2001, or rise of cross-site scripting bugs
- Language matters
- Type-safe languages (Java, Ruby, Lisp, etc) eliminate entire classes of vulnerabilities, such as buffer overflows
- But no language is perfectly safe
- Higher-level semantic bugs such as cross-site scripting, SQL injection, directory traversal, or logical flaws (e.g. improper authorization or protocol design errors) can occur in any language
- C++ is a security nightmare
- Design principles
- Decompose system into trusted/untrusted components
- Principle of least privilege
- E.g. OpenSSH Privilege Separation
- All communication interfaces should be simple, easy to verify, completely defined
- Ambiguity and complexity are the enemies of security and reliability
- Verify all information that crosses trust boundaries
- Small number of places where untrusted information is validated before entering system
- Should be easy to understand, verify
- Plan to Fail
- All software has bugs
- Deploy mitigation strategies
|
|