1 / 58

Buffer Overflows, Race Conditions, and Privilege Escalations

Buffer Overflows, Race Conditions, and Privilege Escalations. Jin Choi <jin@cse.ogi.edu>. Administrative. Assignment 1 due this Wednesday (Jan. 13 th ) Email me your assignment at jin@cse.ogi.edu under the subject “cs510:malware:Assignment 1”. Overview. Buffer Overflows Race Conditions

carrie
Download Presentation

Buffer Overflows, Race Conditions, and Privilege Escalations

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Buffer Overflows, Race Conditions, and Privilege Escalations Jin Choi <jin@cse.ogi.edu>

  2. Administrative • Assignment 1 due this Wednesday (Jan. 13th) • Email me your assignment at jin@cse.ogi.edu under the subject “cs510:malware:Assignment 1”

  3. Overview • Buffer Overflows • Race Conditions • Privilege Escalations

  4. Buffer Overflows • Most common form of security vulnerability in the last 1.5 decades • Dominate remote network penetration attacks (but also used in local exploits) • A Bugtraq mailing list survey on “What do you think is the leading cause of security vulnerability?”: 2/3 answered Buffer Overflow 1/3 answered misconfiguration

  5. Attacker Server Remote Buffer Overflow Example • Attacker sends a string as input, size of which is larger than the input buffer allocated by the remote server Input buffer allocated by server for input Attacker’s input

  6. Attacker Server Remote Buffer Overflow Example • If the server doesn’t do a boundary check, this string overflows the buffer and corrupts the address space of the server (e.g. overwrites the return address on the stack) Corrupts server’s adjacent address space

  7. start_code = 0x0 Code Data New binary BSS Heap 0x4000000 Code Code Program interpreter (ld.so) Data Data BSS BSS Stack start_stack Ptr to Args & Env Arguments Environment 0xC0000000 Process’ Address Space

  8. Stack Frame (Activation Record) • Built at the beginning of a function size of a word (e.g. 4 bytes) Higher memory address Function parameters SFP + 8 Return address Stack grows high to low addresses Old base pointer (Saved Frame Pointer) SFP Lower memory address Local variables

  9. Stack Frame pushl decrements esp by 4 and stores the operand at the address pointed to by the new esp Function Call void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } high addr 1 esp (stack pointer) Assembly: pushl $1 pushl $2 pushl $3 call function low addr

  10. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame Function Call high addr 1 2 esp Assembly: pushl $1 pushl $2 pushl $3 call function low addr

  11. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame Function Call high addr 1 2 3 esp Assembly: pushl $1 pushl $2 pushl $3 call function low addr

  12. Stack Frame call saves instruction pointer (IP). We’ll call the saved IP the return address (RET) Function Call void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } high addr 1 2 3 Assembly: pushl $1 pushl $2 pushl $3 call function return address esp low addr

  13. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame callee saves the old base pointer Function Prologue(code that builds the stack frame at the beginning of a function) high addr 1 2 3 return address saved frame pointer esp Assembly: pushl %ebp movl %esp, %ebp subl $8, %esp low addr

  14. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame Callee sets new value for Frame Pointer Function Prologue(code that builds the stack frame at the beginning of a function) high addr 1 2 3 return address saved frame pointer ebp := esp Assembly: pushl %ebp movl %esp, %ebp subl $8, %esp low addr

  15. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame Allocate space for local variable Function Prologue(code that builds the stack frame at the beginning of a function) high addr 1 2 3 return address saved frame pointer Assembly: pushl %ebp movl %esp, %ebp subl $8, %esp esp … low addr

  16. void function(int a, int b, int c){ char buffer[8]; } void main() { function(1,2,3); } Stack Frame Allocate space for local variable Function Prologue(code that builds the stack frame at the beginning of a function) high addr 1 2 ebp - 12 3 ebp - 8 return address saved frame pointer ebp Assembly: pushl %ebp movl %esp, %ebp subl $8, %esp ebp + 4 esp … low addr

  17. C idiom of allocating a small buffer to get user or parameter input is so common void get_input(char * input){ char buf[100]; strcpy(buf, input); … } However, lack of bounds check is ALSO common  Unfamiliarity with language Ignorance about security issues Performance issue Excuse, excuse… Buf before and after the strcpy() when sizeof(buf)>100 Adjacent memory space in the address space overwritten with the content of buffer!! Typical Buffer Overflow (E.g. “Stack Smashing”) Before After high Address of input Address of input Return address Return address Saved frame pointer Saved frame pointer Buf low

  18. What does the input consist? • One possibility is to put the address of the attack code in every 4 bytes (hoping that one of the 4 bytes will overwrite the return address) • This assumes that the attack code already exists somewhere in the address space of the victim Contains address of the attack code      

  19. How can we place arbitrary instruction (attack code) into its address space? • One way is to place the code in the buffer we are overflowing, and overwrite the return address so it points back into the buffer. place address that points to the start of the buffer place attack code (word-aligned)          start address of buffer

  20. Buffer Overflow • Mostly relevant to C/C++ • Not in languages that support automatic memory management • Java (dynamic bounds checks) • Perl (automatic buffer resizing)

  21. Buffer Overflows • Attacker’s goal • Subvert the function of a privileged program to take control of that program • The higher the privilege the better. In UNIX, root is the highest • To achieve the goal, must achieve two sub-goals: • Arrange the attack code to be available in the victim program’s address space • Have the victim program to jump to the attack code

  22. Buffer Overflows • Attack code typically contains exec(/bin/sh) • Gives the attacker a shell prompt with the privilege of the victim program • If the victim has a root privilege, then the attacker owns the host

  23. Classification of Buffer Overflow attacks • Classify attacks according to how the two sub-goals are achieved • Arrange the attack code to be available in the victim program’s address space • Inject it • It’s already present • Have the victim program to jump to the attack code • Corrupt code pointers: program state that points at code thereby changing the execution path or control flow

  24. Ways to arrange the attack code:Inject it • Attacker provides a string as input to the victim program, and the victim program stores it in a “buffer” • Buffer can be located anywhere in victim’s address space: • On the stack • On the heap (malloc’d variables) • In the static data area (.data, .bss) • But not in .text (Read-only)

  25. Ways to arrange the attack code:It’s already present • Use existing code in the victim’s address space • E.g. libc (linked to virtually every C program) that has the code that executes “exec(arg)” • Attacker then uses a buffer overflow to corrupt arg and another buffer overflow to corrupt a code pointer to point into libc at the appropriate code fragment

  26. Have the victim program to jump to the attack code • Corrupt the state of an adjacent part of the program’s state, e.g. adjacent pointers • Find a program with lack of bounds checking on input • Feed input larger than the size of allocated buffer • Overflow of buffer alters adjacent code pointer • Distinguishing criteria • Kind of state corrupted • In principle, state can be any kind of state • In practice, state is mostly code pointers: program state that points at code • Location of the state in memory

  27. Kinds of State to Corrupt • Activation Records (Stack Frame) • Overwrites the return address that the program should jump to when the function exits (a.k.a. “Stack smashing attack”) • Function Pointers • “void (* foo)()” – “pointer to function returning void” • Can be allocated anywhere (stack, heap, .data) • Attacker only needs to find an overflowable buffer adjacent to the function pointer • Later when the victim makes a call, it will instead jump to the attacker’s desired location • E.g. superprobe program in Linux • setjmp(jmp_buf) and longjmp(jmp_buf) • Used in C/C++ • Inter-procedural goto • Typically used in error handling (checkpoint & rollback point) • Like function pointers, longjmp buffer can be located anywhere, so attacker only needs to find an adjacent buffer (overflowable) • E.g. Perl 5.003

  28. Defenses • Write Correct Code • expensive proposition • Direct Compiler Approach • E.g. Compaq C Compiler supports “-check_bound” option • Indirect Compiler Approach • Integrity checking • Activation Record Integrity (StackGuard) • Code Pointer Integrity (PointGuard)

  29. Race Conditions

  30. Race Conditions • In multi-process or multi-threaded environment, tasks/threads can interact each other through: • Shared memory • File system • Signals • Results of tasks depend on relative timing of events

  31. Race Conditions • Synonym for non-deterministic behavior • Often issue of robustness hence many important security implications • Certain assumption needs to hold for some duration for intended behavior, but the assumption can be invalidated • May leave further actions that rely on the assumption unpredictable (at least not what was intended) • “Window of vulnerability” • The time interval in which assumption can be invalidated

  32. Window of Vulnerability • Actions can be application-level or OS-level (e.g. syscalls) • Attacker acts during the time interval trying to violate the assumptions before the second action occurs • Interval can be very short but the attacker can extend it by slowing down the victim machine (by performing computation-intensive actions e.g. DoS attack) Time Interval Action 1 Action 2 Time

  33. Make sequence of actions (operations) atomic? • Can use synchronization primitives to enforce atomicity of a sequence of operations atomic to ensure security properties. • Critical section has to be as small as possible • However a tradeoff is… Performance Number of programs

  34. Race Conditions • We’ll look at common race condition problems relevant to security • TOCTTOU (Time Of Check To Time Of Use) flaws • File System TOCTTOU : Name-Object binding flaws • Non-FS TOCTTOU : ptrace(), execve()

  35. What is “TOCTTOU Flaw”? • Semantic Characteristic • Occurs when two events occur and the second depends upon the first Time Syscall 1 (Time Of Check) Syscall 2 (Time Of Use) Time Interval where attacker can race in and invalidate the assumption that syscall 2 depends upon

  36. File System TOCTTOU: Name-Object Binding Flaws • Arise when object identifiers are fallaciously assumed to remain bound to an object • UNIX system provides two different forms of naming, with different semantics • File path name • File descriptor • The difference comes from the way the addresses resolve to the actual objects • File path names are resolved by indirection, requiring the naming and addressing at least one intermediate object other than the actual file object being addressed (indirect pointer to object) E.g. symlink, inode • File descriptors are resolved by accessing the file being addressed (direct pointer to object) • Indirect -> Opens up window of vulnerability

  37. File System TOCTTOU: Name-Object Binding Flaws • Symbolic Link Races (Temporary File Race) Suppose Process A runs with root privilege wants to create /tmp/foo • Process A calls lstat(/tmp/foo,…) to check if /tmp/foo already exists • If lstat() returned -1 with ENOENT (i.e. /tmp/foo does not exist) open the file and write to it. Window of vulnerability exists between 1 and 2. A process with a normal privilege could race in and create a symlink /tmp/foo that points to /etc/passwd, resulting Process A overwrite the content of /etc/passwd, corrupting the file.

  38. File System TOCTTOU: Name-Object Binding Flaws • Calls that require file path name as argument are troublesome • E.g. access(), open(), creat(), mkdir(), unlink(), rmdir(), chown(), symlink(), link(), rename(), chroot(),… • “troublesome” because TOCTTOU binding flaw arises when at least one of two sequential system calls refer to the same object using a file path name.

  39. File System TOCTTOU: Name-Object Binding Flaws • Example: SETUID program: • if (access (filename, W_OK) == 0) { • if ((fd = open(filename, O_WRONLY)) == NULL){ • perror(filename); • return(0); • } /* now write to the file */ • If the attacker changes the object referred to by filename between 1 and 2, the second object will be opened even if its access was never checked (access to the first object was checked)

  40. Non-FS TOCTTOU • Race condition in Linux/BSD kernel ptrace()/execve() • ptrace() system call • Typically used in debugging applications. E.g. GDB, strace • Used to access other process’ registers and memory (address space) E.g. the tracing process can change the instruction pointer of the traced process to point to the attacker’s code. • Can only attach to processes with the same UID (user ID), except when the tracing process is the root process • execve() system call • Used to execute program • setuid functionality (modifies the process EUID to file owner’s UID)

  41. UNIX User ID Model Revisited • USER ID MODEL • Each user has a unique UID • UID determines which resources a user can access • UID of 0 == ROOT; process can access all system resources • Each process has 3 UIDs: (1) real UID: identifies process OWNER (2) effective UID: used in access control decisions (3) saved user ID: stores a previous UID so that it can be restored later Similarly, each process has 3 groupIDs: real/effective/saved GID

  42. UNIX User ID Model Revisited • When a process executes a program via execve(), that executing process keeps ITS OWN UIDs unless the SETUID bit in the new file is set. • if the SETUID bit is set in the program file, then calling setuid() modifies process' EUID to the file owner's UID

  43. Non-FS Race Conditions • Security hole (race condition) in execve() • First checks whether process is being traced • Open program image (may block) • Allocate memory (may block) • If SETUID bit is set on the program file, then set process’ EUID according to the file owner’s UID • Window of vulnerability exists between step 1 and step 4 • Blocking kernel operations allow other user processes to run • Attacker can race in and attach via ptrace() • Example: ptrace-kmod attack

  44. Privilege Escalation

  45. Privilege Escalation • Allows a user with normal privileges (local) or no privileges to gain (and possibly retain) root privileges illegally. • Uses vulnerabilities such as • Buffer Overflow Vulnerabilities • Race Condition Vulnerabilities • Others..

  46. Privilege Escalation • Using Buffer Overflow • E.g. inject code into address space of a privileged program (root-owned setuid program) • Using Race Condition • E.g. Race condition exists in execve() • Using Other Vulnerabilities • E.g. Exploit flaws in kernel code • E.g. Flaw in mremap()in Linux 2.4.20

  47. Privilege Escalation: Using Buffer Overflow • Inject code into address space of a privileged program (root-owned setuid program) • What code do we inject? exec(“/bin/sh”) to gain a root shell.

  48. Privilege Escalation: Using Race Condition • Using Race Condition • E.g. Race condition in execve() • Use ptrace() to attach to the victim process

  49. Privilege Escalation: Using Race ConditionExample: ptrace-kmod Attack • When a process requests a feature which is in a module (e.g. socket(AF_SECURITY, …)), the kernel creates a thread (on behalf of the calling process i.e. as if the process that invoked socket(AF_SECURITY, …) called fork() and execve(“/sbin/modprobe”) ) that calls execve("/sbin/modprobe") inside which sets EUID/EGID to 0 (since modprobe is root-owned). Due to the race condition in execve(), the calling process can attach to the modprobe before the execve() sets the EUID/EGID to 0 but after execve() checks whether process is being traced.

More Related