Preventing Hijacking Attacks1
Preventing Hijacking Attacks1
Hijacking is a type of network security attack in which the attacker takes control of a
communication.
Control flow
The order in which individual statements, instructions or function calls of an imperative program
are executed or evaluated.
• Alter a code pointer (i.e., value that influences program counter) or, Gain control of the
instruction pointer
A representation, using graph notation, of all paths that might be traversed through a program
during its execution.
It is a subclass of control hijacking attacks that subverts the intended control flow of a program
to previously injected malicious code Shellcode.
Shellcode is a malicious code supplied by attacker often saved in buffer being overflowed
Code-reuse attacks
Adding a new path to the CFG − Adversary is limited to the code nodes that are available in the
CFG
− Execute arbitrary code on target by hijacking the execution flow of a running program
Buffer overflows
Integer overflows
Heap overflows
“A condition at an interface under which more input can be placed into a buffer or data holding
area than the capacity allocated, overwriting other information.
−Attackers exploit such a condition to crash a system or to insert specially crafted code that
allows them to gain control of the system.”
Initially, A contains nothing but zero bytes, and B contains the number 1979.
variable name A B
hex value 00 00 00 00 00 00 00 00 07 BB
Now, the program attempts to store the null-terminated string "excessive" with ASCII encoding
in the A buffer.
strcpy(A, "excessive");
"excessive" is 9 characters long and encodes to 10 bytes including the null terminator, but A can
take only 8 bytes. By failing to check the length of the string, it also overwrites the value of B:
variable name A B
value 'e' 'x' 'c' 'e' 's' 's' 'i' 'v' 25856
hex 65 78 63 65 73 73 69 76 65 00
B's value has now been inadvertently replaced by a number formed from part of the character
string. In this example "e" followed by a zero byte would become 25856.
Writing data past the end of allocated memory can sometimes be detected by the operating
system to generate a segmentation fault error that terminates the process.
To prevent the buffer overflow from happening in this example, the call to strcpy could be
replaced with strlcpy, which takes the maximum capacity of A (including a null-termination
character) as an additional parameter and ensures that no more than this amount of data is written
to A:
When available, the strlcpy library function is preferred over strncpy which does not null-
terminate the destination buffer if the source string's length is greater than or equal to the size of
the buffer (the third argument passed to the function), therefore A may not be null-terminated
and cannot be treated as a valid C-style string.
• Memory corruption bugs in software written in low-level languages like C or C++ are
• one of the oldest problems in computer security.
• The lack of memory safety in these languages allows attackers to alter the program’s
behavior or take full control over it by hijacking its control flow.
• Recent code-injection attacks on iPhones, have shown a level of sophistication that is
able to bypass widely-deployed prevention mechanisms against code injection.
Attacks that divert a program’s control flow for malicious purposes are generally
known as control-hijacking attacks.
• In order to hijack control successfully, the attacker needs to know the correct target value
(i.e. the address of the payload) with which to overwrite the code pointer in step 2. That is
represented in a separate step 3 in Figure.
• Assuming a code pointer (e.g. a function pointer) has been successfully corrupted in the
first three steps, an attacker then proceeds by loading the corrupted pointer into the
instruction pointer, which points to next instruction a program executes.
• This can be achieved by executing an indirect control-flow transfer instruction, like a
return instruction, thus diverting the execution from the intended program controlflow.
• The final step of a control-flow hijack exploit is the execution of the payload, which is
often something malicious such as stealing private information, or gaining high privilege
on specific targets.
• Unlike complete memory safety, CPI relies on protecting only the integrity of sensitive
pointers (e.g. function pointer) to thwart control hijacking.
• Since sensitive pointers make up a subset of all pointers, CPI promises to provide strong
security at a very reasonable performance cost.
• CPI first over-approximately identifies all sensitive pointers via static analysis of the
code. Then, it stores metadata for checking validity of code pointers in a designated "safe
region" of memory.
• The metadata includes the value of the pointer and its lower and upper bounds.
Additionally, CPI adds instrumentation that propagates metadata when pointer operations
occur.
• CPI relies on a secret region which is kept in the same space as the process being
protected, to be isolated. It assumes it has to be leak-proof and cannot be disclosed.
• The NX bit, which stands for Never eXecute, is a technology used in CPUs to segregate
areas of memory for use by either storage of processor instructions (or code) or for
storage of data, a feature normally only found in Harvard architecture processors.
• An operating system with support for the NX bit may mark certain areas of memory as
non-executable.
• The processor will then refuse to execute any code residing in these areas of memory.
• The general technique, known as executable space protection, is used to prevent certain
types of malicious software from taking over computers by inserting their code into
another program's data storage area and running their own code from within this section;
this is known as a buffer overflow attack.
• The NX bit specifically refers to bit number 63 (i.e. the most significant bit) of a 64-bit
entry in the page table.
• If this bit is set to 0, then code can be executed from that page; if set to 1, code cannot be
executed from that page, and anything residing there is assumed to be data.
• DEP is a system-level memory protection feature that is built into the operating system
starting with Windows XP and Windows Server 2003.
• DEP enables the system to mark one or more pages of memory as non-executable.
Marking memory regions as non-executable means that code cannot be run from that
region of memory, which makes it harder for the exploitation of buffer overruns.
• DEP prevents code from being run from data pages such as the default heap, stacks, and
memory pools. If an application attempts to run code from a data page that is protected, a
memory access violation exception occurs, and if the exception is not handled, the calling
process is terminated.
• DEP is not intended to be a comprehensive defense against all exploits; it is intended to
be another tool that you can use to secure your application.
• If an application attempts to run code from a protected page, the application receives an
exception with the status code STATUS_ACCESS_VIOLATION.
• If your application must run code from a memory page, it must allocate and set the proper
virtual memory protection attributes.
• The allocated memory must be marked
• PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
or PAGE_EXECUTE_WRITECOPY when allocating memory.
• Heap allocations made by calling the malloc and HeapAlloc functions are non-
executable.
• Applications cannot run code from the default process heap or the stack.
• DEP is configured at system boot according to the no-execute page protection policy
setting in the boot configuration data.
Limitations:
Fix bugs:
1: Audit software
• Automated tools: Coverity, Prefast/Prefix.
Coverity Tool:
• It is a proprietary static code analysis tool from Synopsys. This product enables engineers
and security teams to find and fix software defects.
• Coverity is a static code analysis tool for C, C++, C#, Java, JavaScript, PHP, Python, .Net
Core, ASP.NET, Objective-C, Go, JSP, Ruby, Swift, Fortran, Scala, VB.NET, ioS,
and Typescript. It also supports more than 70 different frameworks for Java, JavaScript,
C# and other languages.
• The starting point with Coverity is what we call central analysis.
Periodically, an automated process will check out your code from your source control
system and then build and analyze it with Coverity.
PREfast Tool:
• PREfast is a utility for static code analysis (it means that analysis is done at compile
time). It can find defects in C/C++ code such as buffer overruns, null pointer
dereferencing, forgetting to check function return value and so on. Especially it is good in
checking kernel-mode code due to a larger set of rules which the code has to follow. You
can treat PREfast as a tool for an automatic code review.
• To make its job better, PREfast has to know additional information about the code. That’s
where annotations come into the action.
Stack Smashing
As stack smashing has grown into a very serious vulnerability, certain technologies are
implemented to overcome the stack smashing disaster. Stack buffer overflow protection
changes the organization of data in the stack frame of a function call to include canary
values.
• These values when destroyed indicate that a buffer preceding it in memory has been
overflowed. Canary values monitor buffer overflows and are placed between the control
data and the buffer on the stack. This ensures that a buffer overflow corrupts the canary
first. A failed verification of canary data signifies an overflow in the stack.
• The three types of canary are Random, Terminator, and Random XOR.
• Solar Designer'' has developed a Linux patch that makes the stack non-executable,
precisely to address the stack smashing problem.
• This patch simply makes the stack portion of a user process's virtual address space non-
executable, so that attack code injected onto the stack cannot be executed.
• This patch offers the advantages of zero performance penalty, and that programs work
and are protected without re-compilation. However, it does necessitate running a
specially-patched kernel, unless this extension is adopted as standard.
Limitations:
• In addition to the above vulnerabilities, making the stack non-executable fails to address
the problem of buffer overflow attacks that do not place attack code on the stack.
• The attacker may inject the attack code into a heap-allocated or statically allocated buffer,
and simply re-point a function return address or function pointer to point to the attack
code.
• The attacker may not even need to inject attack code at all, if the right code fragment can
be found within the body of the program itself. Thus additional protection for critical data
structures such as function pointers and function return addresses, as described in Section
• It is one of the best known protection mechanisms. It is a GCC Compiler extension that
inserts additional function entry and exit code.
• The added function entry code writes a canary12 value below the old frame pointer
address, before the allocation of space for local variables. The added function exit code
checks that the canary value has not changed before continuing with the usual function
exit operations of restoring the old frame pointer and transferring control back to the
return address.
• Any attempt at a classic stack buffer overflow would have to alter this value in order to
change the old frame pointer and return addresses, and would thus be detected, resulting
in the program being aborted.
• For this defense to function successfully, it is critical that the canary value be
unpredictable and should be different on different systems.
• If this were not the case, the attacker would simply ensure the shellcode included the
correct canary value in the required location.
• Typically, a random value is chosen as the canary value on process creation and saved as
part of the processes state.
• The code added to the function entry and exit then use this value.
Limitation:
Using canaries
• A canary is a randomly generated value, and in the case of a buffer overflow, the canary
is overwritten; when, upon comparison with the known value, the compiler detects that
the stack was compromised it throws the stack smashing detected error.
Canary Types:
• Random canary:
– Random string chosen at program startup.
– Insert canary string into every stack frame.
– Verify canary before returning from function.
• Exit program if canary changed.
Turns potential exploit into DoS.
– To corrupt, attacker must learn current random string.
Random canaries are randomly generated, usually from an entropy-gathering daemon, in order
to prevent an attacker from knowing their value. Usually, it is not logically possible or plausible
to read the canary for exploiting; the canary is a secure value known only by those who need to
know it—the buffer overflow protection code in this case.
Normally, a random canary is generated at program initialization, and stored in a global variable.
Terminator canaries
• Most buffer overflow attacks are based on certain string operations which end at string
terminators. A terminator canary contains NULL(0x00), CR (0x0d), LF (0x0a), and EOF
(0xff), four characters that should terminate most string operations, rendering the
overflow attempt harmless.
• This prevents attacks using strcpy() and other methods that return upon copying a null
character while the undesirable result is that the canary is known.
• This type of protection can be bypassed by an attacker overwriting the canary with its
known values and the return address with specially-crafted value resulting in a code
execution.
• This can be when non-string functions are used to copy buffers and both the buffer
contents and the length of the buffer are attacker controlled.