E-Nexsh: Achieving an Effectively Non-Executable Stack and Heap Via System-Call Policing
e-NeXSh: Achieving an Effectively Non-Executable Stack and Heap via System-Call Policing
Gaurav S. Kc Angelos D. Keromytis Google, Inc. Columbia University [email protected] [email protected]
Abstract code that has been injected into the process’ memory, or existing functions in the Standard C library (LIBC) or else- We present e-NeXSh, a novel security approach that where in the program code. In either case, the attacker is utilises kernel and LIBC support for efficiently defending able to compromise the process, and generally can gain con- systems against process-subversion attacks. Such attacks trol of the whole system if the attacked process was running exploit vulnerabilities in software to override its program with root privileges (this is often the case with server dae- control-flow and consequently invoke system calls, caus- mons). ing out-of-process damage. Our technique defeats such at- To cause any real damage outside of the compro- tacks by monitoring all LIBC function and system-call in- mised process, e.g., to spawn a shell or to open the vocations, and validating them against process-specific in- /etc/passwd file for editing, the attacker needs to access formation that strictly prescribes the permissible behaviour kernel resources via system calls. There has been signif- for the program (unlike general sandboxing techniques that icant research in recent years resulting in a wide range of require manually maintained, explicit policies, we use the process-sandboxing techniques that monitor applications’ program code itself as a guideline for an implicit policy). system-call invocations [27, 31, 32, 33, 48, 49, 50, 58]. Any deviation from this behaviour is considered malicious, These systems generally require manual effort to specify and we halt the attack, limiting its damage to within the explicit sandboxing policies, except when such policies can subverted process. be automatically generated from application code or train- We implemented e-NeXSh as a set of modifications to the ing runs. Then, the policies are often either imprecise, pro-
linux-2.4.18-3 kernel and a new user-space shared ducing a large number of false positives, or involve signif- ¢ library (e-NeXSh.so). The technique is transparent, re- icant ( 2 £ ) overheads — these are described in more de-
quiring no modifications to existing libraries or applica- tail in ¤ 5. Other techniques prevent the execution of code tions. e-NeXSh was able to successfully defeat both code- in data memory [3, 5, 10, 13, 38, 40, 55] to defeat code- injection and libc-based attacks in our effectiveness tests. injection attacks, randomise the addresses of functions in The technique is simple and lightweight, demonstrating no the Standard C library (LIBC) [3, 14, 20] to deter libc- measurable overhead for select UNIX utilities, and a negli- based attacks, use static analyses to remove vulnerabilities gible 1.55% performance impact on the Apache web server. from software [12, 19, 21, 35, 44, 46, 59], or instrument ap- plication code to detect run-time attacks [22, 47, 28, 57]. There exist problems and/or limitations of these systems too, including large overheads or breaking of applications, 1 Introduction the possibility of mimicry or brute-force attacks that can bypass the defence mechanisms, and the inability to specify In recent years, the issue of process-subversion attacks or protect all vulnerabilities, respectively. These limitations has become very important, as is evidenced by the number are also covered in ¤ 5. of CERT advisories [2]. These are attacks that exploit pro- In this paper we present e-NeXSh, a simple and gramming errors in software to compromise running sys- lightweight technique that uses process-specific informa- tems. Such errors allow the attacker to override the pro- tion — this information consists of disassembly data indi- gram’s control logic, causing the program to execute code cating the memory boundaries of all functions in the pro- of their choosing. This code is either malicious executable gram, as well as the call sites for system-call invocations in the program code — to defeat both code-injection and ¡ This work was carried out while author was at Columbia University. libc-based attacks. The technique’s novelty lies in how it builds on the system-call interception model used by Intru- the security] to run unaffected. sion Detection Systems (IDS), and extends the idea to user- The rest of this paper is structured as follows: we present
space code to monitor invocations of LIBC functions. We an overview of our approach in ¤ 2. We describe our imple-
utilise the program code and its disassembly information mentation of e-NeXSh in ¤ 3, and present an evaluation of ¤
as guidelines for an implicit policy to prescribe normal pro- our technique in ¤ 4. We discuss related work in 5, and ¤ gram behaviour, rather than manually defining explicit poli- some remaining issues in ¤ 6, and conclude in 7. cies. We show that e-NeXSh creates an “effectively” non- executable stack and heap that permit the execution of all 2 Approach code except system-call invocations (even via LIBC func- tions). This makes our technique practical even for applica- Published guidelines [4, 6, 9] and analyses [7, 15, 23, 24] tions that have a genuine need for an executable stack. We of process-subversion attacks indicate that these attacks have evaluated a prototype implementation of our technique generally contain the following integral elements: the trig- on x86/Linux, and have demonstrated efficacy at defeating gering of some security vulnerability in the target appli- both libc-based and code-injection attacks, including 100% cation, causing an overwrite of some code pointer memory effectiveness against Wilander’s benchmark test-suite [64], location, making it point to malicious code of the attacker’s in our evaluations. We provide further discussion in ¤ 5. choosing. These elements comprise the anatomy of attacks, Our implementation consists of two parts: a user-space and is illustrated in figure 1. Then, as the program contin- component to intercept and validate LIBC function invoca- ues execution, it eventually activates this overwritten code tions, and a kernel component to do the same for system-call pointer, and begins executing the attack code in question. invocations. The user-space component (implemented as a shared library: e-NeXSh.so) intercepts invocations of r y e t t e i LIBC functions, and validates the call chain against the pro- e l t e n r i i t i d r e b u o o g gram’s binary code and its disassembly information. This w a c p c r r g - l e i e e e a
Initiate Invoke r x v n component can detect libc-based attacks that redirect the d l T E M O o u Attack System Call