1Common Implementation FlawsDawn [email protected] for Today• Next few lectures are about software security– Can have perfect design, specification, algorithms, but still have implementation vulnerabilities!• Examine common implementation flaws– Many security-critical apps use C, and C has peculiar pitfalls • Implementation flaws can occur with improper use of language, libraries, OS, or app logic• Real goal:– Put on the attacker’s hat: how to exploit a vulnerable program for fun & profit!3Simple Example• char buf[80];void vulnerable() {gets(buf);}• gets() reads all input bytes available on stdin, and stores them into buf[]• What if input has more than 80 bytes?– gets() writes past end of buf, overwriting some other part of memory– This is a bug!• Results?– Program crash/core-dump?– Much worse consequences possible…4Modified Example• char buf[80];int authenticated = 0; void vulnerable() {gets(buf);}• A login routine sets authenticated flag only if user proves knowledge of password• What’s the risk?–authenticated stored immediately after buf– Attacker “writes” data after end of buf• Attacker supplies 81 bytes (81stset non-zero)– Makes authenticated flag true!– Attacker gains access: security breach!5More Serious Exploit Example• char buf[80];int (*fnptr)();void vulnerable() {gets(buf);}• Function pointer fnptr invoked elsewhere• What can attacker do?– Can overwrite fnptr with any address, redirecting program execution! • Crafty attacker:– Input contains malicious machine instructions, followed by pointer to overwrite fnptr– When fnptr is next invoked, flow of control re-directed to malicious code• This is a malicious code injection attack6Buffer Overrun Vulnerabilities• Most common class of implementation flaw (used to be)– Web application implementation flaw is taking over• C does not guarantee type safety– Programmer exposed to bare machine– No bounds-checking for array or pointer accesses• Buffer overrun (or buffer overflow) vulnerabilities– Out-of-bounds memory accesses used to corrupt program’s intended behavior7Buffer Overrun Exploits• Demonstrate how adversaries might be able to use a buffer overrun bug to seize control– This is very bad!• Consider: web server receives requests from clients and processes them– With a buffer overrun in the code, malicious client could seize control of server process– If server is running as root, attacker gains root access and can leave a backdoor» System has been “0wned”• Buffer overrun vulnerabilities and malicious code injection attacks are primary/favorite method used by worm writers 8Buffer Overflow Exploit History• First Internet worm (Morris worm) spread using several attacks–One used buffer overrun to overwrite authenticated flag in in.fingerd(network finger daemon)• Attackers have discovered much more effective methods of malicious code injection…9C Program Memory Layout• Text region (program’s executable code)• Heap, (dynamically allocated data)– Grows/shrinks as objects allocated/freed• Stack (local variable storage)– Grows/shrinks with function calls/returns• Function call pushes new stack frame on stack– Frame includes space for function’s local vars– Intel (x86) machines stack grows “down”– Stack pointer (SP) reg points to current frame– Stack extends from SP to the end of memory0xFF…F0x00…0heap … stacktext region10C Program Execution• Instruction pointer (IP) register points to next machine instruction to execute• Caller sets up arguments on stack• Procedure call instruction:– Pushes current IP onto stack (return addr)– Jumps to beginning of function being called• Compiler inserts prologue into each function– Pushes current SP value of SP onto stack– Allocates stack space for local variables by decrementing SP by appropriate amount• Function return:– Old SP and return address retrieved from stack, and stack frame popped from stack– Execution continues from return address11Stack Smashing Attack• void vulnerable() {char buf[80];gets(buf);}• When vulnerable() is called, stack frame is pushed onto stack• Given “too-long” input, saved SP and return addr will be overwritten• This is the stack smashing attack!…caller’s stack framebuf saved SP ret addr12Stack Smashing Attack• First, attacker stashes malicious code sequence somewhere in program’s address space• Next, attacker provides carefully-chosen 88-byte sequence– Last four bytes chosen to hold code’s address overwrite saved return address• When vulnerable() returns, CPU loads attacker’s return addr – handing control over to attacker's malicious code• Stack smashing exploit reference:– “Smashing the Stack for Fun and Profit,” written by Aleph One in November 199613Buffer Overrun Summary• Attackers developed techniques for when:– Buffer stored on the heap instead of on stack– Can only overflow buffer by one byte– Characters written to buffer are limited (e.g., only uppercase characters)– …• Exploiting buffer overruns appears mysterious, complex, or incredibly hard to exploit – Reality – it is none of the above!• Worms exploit these bugs all the time– Code Red II compromised 250K machines by exploiting IIS buffer overrun14Format String Vulnerabilities• void vulnerable() {char buf[80];if (fgets(buf, sizeof buf, stdin) == NULL)return;printf(buf);}• Do you see the bug?• Last line should be printf("%s", buf)– If buf contains “%”chars, printf() will look for non-existent args, and may crash or core-dump trying to chase missing pointers• Reality is worse…15Attack Examples• Attacker can learn about function’s stack frame contents if they can see what’s printed– Use string “%x:%x” to see the first two words of stack memory• What does this string (“%x:%x:%s”) do?– Prints first two words of stack memory– Treats next stack memory word as memory addr and prints everything until first '\0'• Where does that last word of stack memory come from?– Somewhere in printf()’s stack frame or, given enough %x specifiers to walk past end of printf()’sstack frame, comes from somewhere in vulnerable()'s stack frame16A Further Refinement• buf is stored in vulnerable()’s stack frame– Attacker controls buf’s contents and, thus, part of vulnerable()’s stack frame – Where %s specifier gets its memory
View Full Document