Professional Documents
Culture Documents
(CT-6611 )
.
Managing Privilege
• Mistakes in privilege management are often errors of omission.
- That is, programs that should be managing their privilege fail to do so.
Table. Function prototypes and descriptions for Linux privilege management functions.
No matter which platform and functions you use, always pay attention to the return
value of a privilege management call.
Attackers might be able to cause privilege management functions to fail by
exhausting resources or altering the way a program is executed.
When a call to a privilege management function fails unexpectedly, ensure that the
program’s behavior remains secure.
• The majority of privileged programs perform three key operations on their
privileges:
• Drop privileges with the intention of regaining it
• Drop privileges permanently
• Regain previously stored privileges
…
Table. Function prototypes and descriptions for a reduced privilege management API.
int restore_priv() Copy the privileged user ID from the saved uid
to the effective uid.
3. The program later performs a filesystem operation using the same filename
and assumes that the previously checked property still holds.
• The code in Example next, contains a TOCTOU vulnerability discovered in the lpr
printing utility. (lpr -- Line printer remote)
…
Example : File access race condition vulnerability in code from lpr.
for (int i=1; i < argc; i++) {
/* make sure that the user can read the file, then open it */
if (!access(argv[i], O_RDONLY)) {
fd = open(argv[i], O_RDONLY);
}
print(fd);
}
• The lpr utility is installed setuid root to enable users to communicate with
printers on the system.
- The program accepts filenames on its command line,
- attempts to open the corresponding files, and
- prints their contents.
Because it runs as root and, therefore, can read any file on the filesystem,
- lpr must check to make sure that the user has permission to print the
requested file, by calling access(),
which checks if the user has permission to access the file.
…
• b/c both access() and open() take a string parameter instead of a file handle,
- the attacker has a race window of opportunity to change the file.
• Figure bellow, shows the way the operations in lpr could interleave with the
execution of an attacker’s code in a successful attack.
• An attacker invokes lpr with the argument /tmp/attack
and redirects the file to point to the system file /etc/shadow
between the time it is checked and when it is used.
lpr Attacker
Time 0: access(“/tmp/attack”)
Time 1: unlink(“/tmp/attack”)
Time 2: symlink(“/etc/shadow”,“/tmp/attack”)
Time 3: open(“/tmp/attack”)
Or
• Any process running on a computer has its own address space, which includes
that process’ instructions and data.
• The stack grows automatically when accessed, up to a size set by the kernel
(which can be adjusted with setrlimit(RLIMIT_STACK, ...)). The heap grows when
the memory allocator invokes the brk() or sbrk() system call, mapping more
pages of physical memory into the process’s virtual address space.
…
What is Stack?
• Every time a function is called, the machine allocates some stack memory for
it. When a new local variables is declared, more stack memory is allocated for
that function to store the variable. Such allocations make the stack grow
downwards. After the function returns, the stack memory of this function is
deallocated, which means all local variables become invalid. The allocation
and deallocation for stack memory is automatically done. The variables
allocated on the stack are called stack variables, or automatic variables.
• A stack is a “last in, first out” (LIFO) data structure that allows two basic
operations: push and pop. The push operation puts a new value on the top of
the stack, and the pop operation removes the most recent value from the
stack.
• The stack segment holds automatic variables, control-flow information,
exception records, and other temporary information required for nesting of
functions.
• The stack is used for storing local variables defined inside functions, as well as
storing data related to function calls, such as return address, arguments, etc.
• The stack segment grows downwards, towards lower memory addresses.
…
What Is a Heap?
• A heap is an area of memory that a program can use for storage of
dynamic data. Unlike stack, heap memory can be dynamically allocated.
• Any segment that is writable can be referred to as a heap although often
only the segments specifically allocated for use by malloc() are considered
true heaps. This memory is global, i.e. it can be accessed and modified
from anywhere within a program and is not localized to the function
where it is allocated. This is accomplished using 'pointers' to reference
dynamically allocated memory which in turn leads to a small degradation
in performance as compared to using local variables(on the stack).
• The heap segment is where dynamic variables are stored. These variables
can be allocated and released at runtime.
• The heap is used to provide space for dynamic memory allocation. This
area is managed by malloc, calloc, realloc, free, etc.
• Unlike stack segments, heap segments grow upwards, towards higher
memory addresses.
…
Stack Memory Allocation:
Stack memory allocation takes place on contiguous blocks of memory.
The compiler calculates how much memory to allocate for each type of variable
specified in the program.
When the function call is completed, the memory for the variables is released.
This all happens using some predefined routines in the compiler.
A programmer does not have to worry about stack memory allocation and
deallocation of stack variables.
This kind of memory allocation is also known as Temporary memory allocation
because as soon as the method finishes its execution all the data belonging to
that method flushes out from the stack automatically.
This means any value stored in the stack memory scheme is accessible as long as
the method hasn’t completed its execution and is currently in a running state.
Key Points:
• It’s a temporary memory allocation scheme where the data members are
accessible only if the method( ) that contained them is currently running.
…
• It allocates or de-allocates the memory automatically as soon as the
corresponding method completes its execution.
• Stack memory allocation is considered safer as compared to heap memory
allocation because the data stored can only be accessed by the owner
thread.
• Memory allocation and de-allocation are faster as compared to Heap-
memory allocation.
• Stack memory has less storage space as compared to Heap-memory.
int main()
{
// All these variables get memory
// allocated on stack
int a;
int b[10];
int n = 20;
int c[n];
}
…
Heap Memory Allocation:
The memory is allocated during the execution of instructions written by programmers.
It is termed a heap because it is a collection of memory space that programmers can
allocate and deallocate.
Every time when we construct an object it always creates in Heap-space and the
referencing information to these objects is always stored in Stack-memory.
Heap memory allocation isn’t as safe as Stack memory allocation because the data
stored in this space is accessible or visible to all threads.
If a programmer does not handle this memory well, a memory leak can happen in the
program.
Key Points
• This memory allocation scheme is different from the Stack-space allocation, here
no automatic de-allocation feature is provided. We need to use a Garbage
collector to remove the old unused objects in order to use the memory efficiently.
• The processing time(Accessing time) of this memory is quite slow as compared to
Stack-memory.
• Heap memory is also not as threaded-safe as Stack-memory because data stored
in Heap-memory are visible to all threads.
• The size of the Heap-memory is quite larger as compared to the Stack-memory.
• Heap memory is accessible or exists as long as the whole application(or program)
runs.
…
stdlib.h provides with standard library functions to access, modify and manage
dynamic memory. Commonly used functions include malloc and free:
// Dynamically allocate 10 bytes
char *buffer = (char *)malloc(10);
strcpy(buffer, "hello");
printf("%s\n", buffer); // prints "hello"
// Frees/unallocates the dynamic memory allocated earlier
free(buffer);
These functions provide a layer between the developer and the operating
system that efficiently manages heap memory. It is the responsibility of the
developer to 'free' any allocated memory after using it exactly once.
Internally, these functions use two system calls sbrk and mmap to request
and release heap memory from the operating system.
To allocate heap memory in C++, use the keyword new followed by the
constructor of what you want to allocate. The return value of new operator
will be the address of what you just created (which points to somewhere in
the heap).
…
int main()
{
// This memory for 10 integers
// is allocated on heap.
int *ptr = new int[10]; // C++ memory allocation
}
Intermixed example of both kinds of memory allocation Heap and Stack in C++:
#include <iostream>
using namespace std;
int main()
{
//Stack Overflow
#include<stdio.h>
void fun(int a) {
if (a== 0)
return;
a += 1;
printf("\n");
printf("%d",a);
fun(a);
}
int main() {
int a = 5;
fun(a);
}
…
Stack overflows occur as a result of improper bounds-checking by string-handling
functions in the C and C++ languages.
Example, shows a very basic piece of code that is vulnerable to stack overflow.
int main(){
main();
}
or the similar
int add(int n)
{
return n + add(n + 1);
}
…
There are various ways to exploit stack overflow vulnerabilities
Stack Smashing
Off-by-One Overflow
Return-to-library
Pointer Subterfuge
…
Heap Overflows
• The heap is the other memory region where buffer overflow
vulnerabilities are exploited. Heaps are used by processes to store their
dynamic variables and data with varying sizes at runtime.
• Memory allocations from the heap can be done using HeapAlloc in
Windows API, malloc in C, and new in C++. Similarly, memory can be
released using the HeapFree, free, and delete function calls, respectively.
• By overflowing a buffer on the heap, an attacker can overwrite the
metadata of the adjacent chunk.
• Heap-based buffer overflow vulnerabilities can be exploited when a chunk
of memory is freed, and heap manager tries to update the doubly linked
lists of free chunks. At this point, with the help of forced unlink operation,
heap-based buffer overflows allow the attacker to write an arbitrary value
anywhere in memory. Potential targets can be function pointers, pointers
to exception handlers, etc.
• Example code, illustrates a basic piece of code that is vulnerable to heap-
based buffer overflow.
…
.
• The term heap overflow can be used for many bug primitives.
• Heap overflow may overwrite other date allocated on heap
• By exploiting the behavior of memory management routines, may
overwrite an arbitrary memory location with a small amount of data.
…
Heap Exploitation
• The glibc library provides functions such as free and malloc to help
developers manage the heap memory according to their use cases. It is
the responsibility of the developer to:
free any memory he/she has obtained using malloc .
Do not free the same memory more than once.
Ensure that memory usage does not go beyond the amount of memory
requested, in other terms, prevent heap overflows.