Content
This commit is contained in:
parent
541a979646
commit
020a4542fb
BIN
references/2014_heartbleed.pdf
Normal file
BIN
references/2014_heartbleed.pdf
Normal file
Binary file not shown.
BIN
references/2019_checksec.pdf
Normal file
BIN
references/2019_checksec.pdf
Normal file
Binary file not shown.
BIN
work/01paper.pdf
BIN
work/01paper.pdf
Binary file not shown.
524
work/01paper.tex
524
work/01paper.tex
@ -27,6 +27,7 @@
|
|||||||
%\usepackage[ngerman]{babel}
|
%\usepackage[ngerman]{babel}
|
||||||
\usepackage[utf8]{inputenc}
|
\usepackage[utf8]{inputenc}
|
||||||
\usepackage{hyperref}
|
\usepackage{hyperref}
|
||||||
|
\usepackage{cleveref}
|
||||||
\usepackage{url}
|
\usepackage{url}
|
||||||
%%fuer abkuerzungen begin
|
%%fuer abkuerzungen begin
|
||||||
\usepackage[acronym,hyperfirst = false]{glossaries}
|
\usepackage[acronym,hyperfirst = false]{glossaries}
|
||||||
@ -60,7 +61,12 @@ MatrNr. 3220018}
|
|||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
\begin{abstract}
|
\begin{abstract}
|
||||||
TODO
|
|
||||||
|
This paper tries to explain the details behind buffer overflows, explore the
|
||||||
|
problems stemming from those kinds of software vulnerabilities and discus
|
||||||
|
possible countermeasures with focus on their effectiveness, performance impact
|
||||||
|
and ease of use.
|
||||||
|
|
||||||
\end{abstract}
|
\end{abstract}
|
||||||
|
|
||||||
\begin{IEEEkeywords}
|
\begin{IEEEkeywords}
|
||||||
@ -74,20 +80,24 @@ Buffer Overflow, Software Security
|
|||||||
When the first programming languages were designed, memory had to be managed
|
When the first programming languages were designed, memory had to be managed
|
||||||
manually to make the best use of slow hardware. This opened the door for many
|
manually to make the best use of slow hardware. This opened the door for many
|
||||||
kinds of programming errors. Memory can be deallocated more than once
|
kinds of programming errors. Memory can be deallocated more than once
|
||||||
(double-free), the programm could read or write out of bounds of a buffer
|
(double-free), invalid pointers can be dereferenced (\mintinline{C}{NULL}
|
||||||
(information leaks, \acp{bof}). Languages that are affected by this are e.g. C,
|
pointer dereference; this is still a problem in many modern languages), the
|
||||||
C++ and Fortran. These languages are still used in critical parts of the worlds
|
program could read or write out of bounds of a buffer (information leaks,
|
||||||
|
\acp{bof}). Languages that are affected by this are e.g.\ C, C++ and Fortran.
|
||||||
|
While most if not all of these problems are solved in modern programming
|
||||||
|
languages, these languages are still used in critical parts of the worlds
|
||||||
infrastructure, either because they allow to implement really performant
|
infrastructure, either because they allow to implement really performant
|
||||||
programms, because they power legacy systems or for portability reasons.
|
programs, offer deterministic runtime behaviour (e.g.\ no pauses due to garbage
|
||||||
|
collection), because they power legacy systems or for portability reasons.
|
||||||
Scientists and software engineers have proposed lots of solutions to this
|
Scientists and software engineers have proposed lots of solutions to this
|
||||||
problem over the years and this paper aims to compare and give an overview about
|
problem over the years and this paper aims to compare and give an overview about
|
||||||
those.
|
those.
|
||||||
|
|
||||||
Reading out of bounds can result in an information leak and is less critical
|
Reading out of bounds can result in an information leak and is less critical
|
||||||
than \acp{bof} in most cases, but there are exceptions, e.g.\ the Heartbleed bug
|
than \acp{bof} in most cases, but there are exceptions, e.g.\ the Heartbleed
|
||||||
in OpenSSL which allowed dumping secret keys from memory. Out of bounds writes
|
bug~\cite{Heardbleed2014} in OpenSSL which allowed dumping secret keys from
|
||||||
are almost always critical and result in code execution vulnerabilities or at
|
memory. Out of bounds writes are almost always critical and result in code
|
||||||
least application crashes.
|
execution vulnerabilities or at least application crashes.
|
||||||
|
|
||||||
In 2018, 14\% (2368 out of 16556)~\cite{Cve2018} of all software vulnerabilities
|
In 2018, 14\% (2368 out of 16556)~\cite{Cve2018} of all software vulnerabilities
|
||||||
that have a CVE assigned, were overflow related. This shows that, even if this
|
that have a CVE assigned, were overflow related. This shows that, even if this
|
||||||
@ -95,241 +105,439 @@ type of bug is very old and well known, it's still relevant today.
|
|||||||
|
|
||||||
\section{Background}\label{ref:background}
|
\section{Background}\label{ref:background}
|
||||||
|
|
||||||
% TODO: many references
|
|
||||||
|
|
||||||
\subsection{Technical Details}
|
\subsection{Technical Details}
|
||||||
|
|
||||||
Exploitation of \ac{bof} vulnerabilities almost always works by overriding the
|
Code execution via \ac{bof} vulnerabilities almost always works by overwriting
|
||||||
return address in the current stack frame, so when the \mintinline{ASM}{RET}
|
the return address in the current stack frame (known as \enquote{stack
|
||||||
instruction is executed, an attacker controlled address is moved into the
|
smashing})~\cite{Smashing2004}, so when the \mintinline{ASM}{RET} instruction is
|
||||||
instruction pointer register and the code pointed to by this address is
|
executed, an attacker controlled address is moved into the instruction pointer
|
||||||
executed. Other ways include overriding addresses in the \ac{plt} of a binary so
|
register and the code pointed to by this address is
|
||||||
that, if a linked function is called, an attacker controlled function is called
|
executed~\cite{Detection2018}. Other ways include overwriting addresses in the
|
||||||
instead, or (in C++) overriding the vtable where the pointers to an object's
|
\ac{plt} (the \ac{plt} contains addresses of dynamically linked library
|
||||||
methods are stored.
|
functions) of a binary so that, if a linked function is called, an attacker
|
||||||
|
controlled function is called instead, or (in C++) overwriting the vtable where
|
||||||
|
the pointers to an object's methods are stored.
|
||||||
|
|
||||||
A simple vulnerable programm might look like this:
|
A simple vulnerable C program might look like this:
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
\begin{minted}{c}
|
\begin{minted}{c}
|
||||||
int main(int argc, char **argv) {
|
void vuln(char *input) {
|
||||||
char buf[50];
|
char buf[50];
|
||||||
for (size_t i = 0; i < strlen(argv[1]); i++) {
|
size_t len = strlen(input);
|
||||||
buf[i] = argv[1][i];
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
buf[i] = input[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
vuln(argv[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
\end{minted}
|
\end{minted}
|
||||||
|
\caption{Vulnerable C program}\label{lst:vuln}
|
||||||
A successful exploit would place the payload in the memory by supplying it as an
|
|
||||||
argument to the programm and eventually overwrite the return address by
|
|
||||||
providing an input $> 50$ and therefore writing out of bounds. When the
|
|
||||||
\mintinline{C}{return} instruction is executed, and jumps into the payload, the
|
|
||||||
attacker's code is executed. This works due to the way, how function calls on
|
|
||||||
CPUs work. The stack frame of the current function lies between the two pointers
|
|
||||||
\ac{bp} and \ac{sp} as shown in~\ref{fig:before}. When a function is called, the
|
|
||||||
value of the \ac{bp}, \ac{sp} and \ac{ip} is pushed to the stack
|
|
||||||
(Fig.~\ref{fig:call}) and the \ac{ip} is set to the address of the called
|
|
||||||
function. When the function returns, the old \ac{ip} is restored from the stack
|
|
||||||
and the execution continues from where the function was called. If an overflow
|
|
||||||
overwrites the old \ac{ip} (Fig.~\ref{fig:exploit}), the execution continues in
|
|
||||||
attacker controlled code.
|
|
||||||
|
|
||||||
\begin{figure}[h!]
|
|
||||||
\includegraphics[width=.3\textwidth]{./dot/before.pdf}
|
|
||||||
\caption{Stack layout before function call}\label{fig:before}
|
|
||||||
\end{figure}%
|
|
||||||
|
|
||||||
\begin{figure}[h!]
|
|
||||||
\includegraphics[width=.3\textwidth]{./dot/call.pdf}
|
|
||||||
\caption{Stack layout after function call}\label{fig:call}
|
|
||||||
\end{figure}%
|
|
||||||
|
|
||||||
\begin{figure}[h!]
|
|
||||||
\includegraphics[width=.3\textwidth]{./dot/exploit.pdf}
|
|
||||||
\caption{Stack layout after overflow}\label{fig:exploit}
|
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
This is only one of several types and exploitation techniques but the general
|
A successful stack \ac{bof} exploit would place the payload in the memory by
|
||||||
idea stays the same: ovewrite the return address or some kind of function
|
supplying it as an argument to the program (or by placing it in an environment
|
||||||
pointer (e.g.\ in vtables or the \ac{plt}) and once that function is called, the
|
variable, writing it to a file that the program reads, via network packet, ...)
|
||||||
execution flow is hijacked and the attacker can execute arbitiary code.
|
and eventually overwrite the return address by providing an input with $> 50$
|
||||||
|
bytes and therefore writing out of bounds. When executing the
|
||||||
|
\mintinline{C}{return} instruction, and the jumps into the payload, the
|
||||||
|
attacker's code is executed. This works due to the way, how function calls on
|
||||||
|
CPUs work: The stack frame of the current function lies between the \ac{bp} and
|
||||||
|
\ac{sp} as shown in~\cref{fig:before}. When a function is called, the value
|
||||||
|
of the \ac{bp} and \ac{ip} is pushed to the stack (\cref{fig:call}) and the
|
||||||
|
\ac{ip} is set to the address of the called function. When the function returns,
|
||||||
|
the old \ac{ip} is restored from the stack and the execution continues from
|
||||||
|
where the function was called. If an overflow overwrites the old \ac{ip}
|
||||||
|
(\cref{fig:exploit}), the attacker controls where execution continues.
|
||||||
|
|
||||||
The most trivial kinds of exploits is known as a \mintinline{ASM}{NOP} sled.
|
\begin{figure}[h!]
|
||||||
|
\begin{subfigure}[b]{.3\textwidth}
|
||||||
|
\includegraphics[width=\textwidth]{./dot/before.pdf}
|
||||||
|
\caption{Stack layout before function call}\label{fig:before}
|
||||||
|
\end{subfigure}\\
|
||||||
|
|
||||||
|
\begin{subfigure}[b]{.3\textwidth}
|
||||||
|
\includegraphics[width=\textwidth]{./dot/call.pdf}
|
||||||
|
\caption{Stack layout after function call}\label{fig:call}
|
||||||
|
\end{subfigure}\\
|
||||||
|
|
||||||
|
\begin{subfigure}[b]{.3\textwidth}
|
||||||
|
\includegraphics[width=\textwidth]{./dot/exploit.pdf}
|
||||||
|
\caption{Stack layout after overflow}\label{fig:exploit}
|
||||||
|
\end{subfigure}
|
||||||
|
\caption{Stack layouts during an \ac{bof} exploit}
|
||||||
|
\end{figure}%
|
||||||
|
|
||||||
|
This is only one of several types and exploitation techniques. Others include
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
|
||||||
|
\item Heap-based \ac{bof}: In this case there is no way of overwriting the
|
||||||
|
return address but objects on the heap might contain function pointers
|
||||||
|
(e.g.\ for dynamic dispatch) which can be overwritten to execute the
|
||||||
|
attackers code, when executed~\cite{Detection2018}.
|
||||||
|
|
||||||
|
\item Integer overflow: Some calculation on fixed sized integers is used to
|
||||||
|
allocate memory. The calculation leads to an integer overflow and only a
|
||||||
|
small buffer is allocated~\cite{Detection2018}. Later a big integer into the
|
||||||
|
buffer is used and reads or writes outside the buffer. This kind of
|
||||||
|
vulnerability can also lead to other problems because at least in C, signed
|
||||||
|
integer overflow is undefined behaviour.
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
This paper won't explore other kinds of \ac{bof} in detail because the concept
|
||||||
|
is always the same: Unchecked indexing into memory allows the attacker to
|
||||||
|
overwrite some kind of return or call address, which allows hijacking of the
|
||||||
|
execution flow.
|
||||||
|
|
||||||
|
The most trivial kinds of payloads is known as a \mintinline{ASM}{NOP} sled.
|
||||||
Here the attacker appends as many \mintinline{ASM}{NOP} instructions before any
|
Here the attacker appends as many \mintinline{ASM}{NOP} instructions before any
|
||||||
shellcode (e.g.\ to invoke \mintinline{shell}{/bin/sh}) and points the
|
shell-code (e.g.\ to invoke \mintinline{shell}{/bin/sh}) and points the
|
||||||
overwritten \ac{ip} somewhere inside the \mintinline{ASM}{NOP}s. The execution
|
overwritten \ac{ip} or function pointer somewhere inside the
|
||||||
\enquote{slides} through the \mintinline{ASM}{NOP}s until it reaches the
|
\mintinline{ASM}{NOP}s. The execution \enquote{slides} (hence the name) through
|
||||||
shellcode. Most of the migration techniques described in this paper protect
|
the \mintinline{ASM}{NOP}s until it reaches the shell-code. Most of the
|
||||||
against this kind of exploit but there are different and more complex ways of
|
mitigation techniques described in this paper protect against this kind of
|
||||||
exploiting \acp{bof} that are not that easily migrated.
|
exploit but there are different and more complex ways of exploiting \acp{bof}
|
||||||
|
that are not that easily mitigated.
|
||||||
\subsection{Implications}
|
|
||||||
|
|
||||||
\section{Concept and Methods}\label{ref:concept}
|
\section{Concept and Methods}\label{ref:concept}
|
||||||
|
|
||||||
\subsection{Methods}
|
\subsection{Research Methods}
|
||||||
|
|
||||||
This paper describes several techniques that have been proposed to fix the
|
This paper describes several techniques that have been proposed to mitigate the
|
||||||
problems introduced by \acp{bof}. The performance impact, effectiveness (e.g.\
|
problems introduced by \acp{bof} and tries to answer the following questions:
|
||||||
did the technique actually prevent exploitation of \acp{bof}?) and how realistic
|
|
||||||
it is for developers to use the technique in real-world code (e.g.\ is
|
|
||||||
incremental introduction into an existing codebase possible). In the end, there
|
|
||||||
is a discussion about the current state.
|
|
||||||
|
|
||||||
\subsection{Runtime Bounds Checks}
|
\begin{itemize}
|
||||||
|
|
||||||
|
\item What is the performance impact?
|
||||||
|
|
||||||
|
\item How effective is the technique? Did it actually prevent exploitation of
|
||||||
|
\acp{bof}?
|
||||||
|
|
||||||
|
\item How realistic is it for developers to use the technique in real-world
|
||||||
|
code? Can it be introduced incrementally?
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
The paper focuses on solutions for the C language, since it is still the second
|
||||||
|
most used language as of December 2019~\cite{Tiobe2019}. Some of the described
|
||||||
|
techniques are language agnostic but this is not a focus of this paper. In the
|
||||||
|
end, there is a discussion about the current state.
|
||||||
|
|
||||||
|
For the literature research, the paper~\citetitle{Detection2018} served as a
|
||||||
|
base. From there a snowball system search with combinations of the keywords
|
||||||
|
\enquote{buffer}, \enquote{overflow}, \enquote{detection}, \enquote{prevention}
|
||||||
|
and \enquote{dependent typing} was performed using
|
||||||
|
\url{https://scholar.google.com/}.
|
||||||
|
|
||||||
|
Results are evaluated and prioritized using the following criteria:
|
||||||
|
|
||||||
|
\begin{itemize}
|
||||||
|
|
||||||
|
\item Type of publication in the following order:
|
||||||
|
|
||||||
|
\begin{enumerate}
|
||||||
|
\item conference paper
|
||||||
|
\item unreleased paper
|
||||||
|
\item books
|
||||||
|
\item online sources
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\item Number of citations
|
||||||
|
|
||||||
|
\item Publisher
|
||||||
|
|
||||||
|
\item Author's reputation and institute
|
||||||
|
|
||||||
|
\item Overall quality (first by checking structure and abstract, then by
|
||||||
|
the actual content)
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{\Ac{rbc}}
|
||||||
|
|
||||||
The easiest and maybe single most effective method to prevent \acp{bof} is to
|
The easiest and maybe single most effective method to prevent \acp{bof} is to
|
||||||
check, if a write or read operation is out of bounds. This requires storing the
|
check, if a write or read operation is out of bounds. This requires storing the
|
||||||
size of a buffer together with the pointer to the buffer and check for each read
|
size of a buffer together with the pointer to the buffer (so called fat
|
||||||
or write in the buffer, if it is in bounds at runtime. Still almost any language
|
pointers) and check for each read or write in the buffer, if it is in bounds at
|
||||||
that comes with a runtime, uses runtime checking. For this technique to be
|
runtime. Still almost any language that comes with a runtime, uses runtime
|
||||||
effective effective in general, writes to a raw pointer must be disallowed.
|
checking. For this technique to be effective effective in general, writes to a
|
||||||
Otherwise the security checks can be circumvented.
|
raw pointer must be disallowed. Otherwise the security checks can be
|
||||||
|
circumvented. \Ac{rbc} introduces a runtime overhead for every indexed read or
|
||||||
|
write operation. This is a problem if a program runs on limited hardware or
|
||||||
|
might impact real-time properties.
|
||||||
|
|
||||||
\subsection{Prevent/Detect Overriding Return Address}
|
Introducing \ac{rbc} into an existing codebase is not easy. Using fat pointers
|
||||||
|
in a few functions does not prevent other parts of the code to use raw pointers
|
||||||
|
into the same buffer. So for this to be effective, the whole codebase needs to
|
||||||
|
be changed to disallow raw pointers, which, depending on the size, might not be
|
||||||
|
feasible. Still, if done correctly and consequently, it is simply impossible to
|
||||||
|
exploit \acp{bof} for code execution. \Ac{dos} is still possible because the
|
||||||
|
program terminates gracefully when a out of bounds index is used.
|
||||||
|
|
||||||
Since most traditional \ac{bof} exploits work by overriding the return address
|
\subsection{Prevent/Detect Overwriting Return Address}
|
||||||
|
|
||||||
|
Since most traditional \ac{bof} exploits work by overwriting the return address
|
||||||
in the current stack frame, preventing or at least detecting this, can be quite
|
in the current stack frame, preventing or at least detecting this, can be quite
|
||||||
effective without much overhead at runtime. \citeauthor{Rad2001} describe a
|
effective without much overhead at runtime. \citeauthor{Rad2001} describe a
|
||||||
technique that stores a redudnant copy of the return address in a secure memory
|
technique that stores a redundant copy of the return address in a secure memory
|
||||||
area that is guarded by read-only memory, so it cannot be overwritten by
|
area that is guarded by read-only memory, so it cannot be overwritten by
|
||||||
overflows. When returning, the copy of the return address is compared to the one
|
overflows. When returning, the copy of the return address is compared to the one
|
||||||
in the current stack frame and only, if it matches, the \mintinline{ASM}{RET}
|
in the current stack frame and only, if it matches, the \mintinline{ASM}{RET}
|
||||||
instruction is actually executed~\cite{Rad2001}. While this is effective against
|
instruction is actually executed~\cite{Rad2001}. While this is effective against
|
||||||
\ac{rop} based exploits, it does not protect against vtable overrides.
|
stack based \acp{bof}, in the described form, it does not protect against vtable
|
||||||
|
overwrites. An extension could be made to also protect the \ac{plt} and vtables
|
||||||
|
but custom constructs using function pointers would still be vulnerable. Since
|
||||||
|
this technique is a compiler extension, no modification of the codebase is
|
||||||
|
required to enable it, and while it does not prevent all kinds of \ac{bof},
|
||||||
|
mitigates all stack based \acp{bof} with only minimal overhead when calling and
|
||||||
|
returning from a function.
|
||||||
|
|
||||||
An older technique from 1998 proposes to put a canary word between the data of a
|
An older technique from 1998 proposes to put a canary word (named after the
|
||||||
stack frame and the return address~\cite{Stackguard1998}. When returning, the
|
canaries that were used in mines to detect low oxygen levels) between the data
|
||||||
canary is checked, if it is still intact and if not, a \ac{bof} occurred. This
|
of a stack frame and the return address~\cite{Stackguard1998}\cite{AtkDef2016}.
|
||||||
technique is used in major operating systems %TODO
|
When returning, the canary is checked, if it is still intact and if not, a
|
||||||
but can be defeted, if there
|
\ac{bof} occurred. This technique is implemented by major
|
||||||
is an information leak that leaks the cannary to the attacker. The attacker is
|
compilers~\cite{Gcc2003} but can be defeated, if there is an information leak
|
||||||
then able to construct a payload, that keeps the canary intact.
|
that leaks the canary to the attacker. The attacker is then able to construct a
|
||||||
|
payload, that keeps the canary intact. This mitigation has a minimal
|
||||||
|
performance impact~\cite{Gcc2003} and offers a good level of protection. It is a
|
||||||
|
compiler extension so no modification of the code base is needed.
|
||||||
|
|
||||||
\subsection{Restricting Language Features to a Secure Subset}
|
% \subsection{Restricting Language Features to a Secure Subset}
|
||||||
\subsection{Static Analysis}
|
% \subsection{Static Analysis}
|
||||||
\subsection{Type System Solutions}
|
\subsection{Type System Solutions}
|
||||||
|
|
||||||
\citeauthor{Dep2007} propose an extension to the C type system that extends it
|
\citeauthor{Dep2007} propose an extension to the C type system that extends it
|
||||||
with dependent types. These types have an associated value, e.g.\ a pointer type
|
with dependent types. These types have an associated value, e.g.\ a pointer type
|
||||||
can have the buffer size associated to it. This prevents indexing into a buffer
|
can have the buffer size associated to it~\cite{Dep2007}. This prevents indexing
|
||||||
with out-of-bounds values. This extension is a superset of C so any valid C code
|
into a buffer with out-of-bounds values. This extension is a superset of C so
|
||||||
can be compiled using the extension and the codebase is improved incrementally.
|
any valid C code can be compiled using the extension and the codebase is
|
||||||
If the type extension is advanced enough, the additional information might form
|
improved incrementally. If the type extension is advanced enough, the
|
||||||
the base for a formal verification.
|
additional information might form the base for a formal verification. In some
|
||||||
|
cases, the type extensions can even be inferred~\cite{Dep2007}.
|
||||||
|
|
||||||
|
This technique prevents all kinds of overflows, if used, but requires changes to
|
||||||
|
the codebase and is only effective where these changes are applied. Since it is
|
||||||
|
a compile-time solution, it does affect the compile-time but has no negative
|
||||||
|
effect on the runtime.
|
||||||
|
|
||||||
\subsection{Address Space Layout Randomization}
|
\subsection{Address Space Layout Randomization}
|
||||||
|
|
||||||
\Ac{aslr} aims to prevent exploitatoin of \acp{bof} by placing code at random
|
\Ac{aslr} aims to prevent exploitation of \acp{bof} by placing code at random
|
||||||
locations in memory. That way, it is not trivial to set the return address to
|
locations in memory~\cite{AtkDef2016}. That way, it is not trivial to set the
|
||||||
point to the payload in memory. This is effective against generic exploits but
|
return address to point to the payload in memory. This is effective against
|
||||||
it is still posible to exploit \ac{bof} vulnerabilities in combination with
|
every kind of \ac{bof} vulnerability but it is still possible to exploit
|
||||||
information leaks or other techniques like heap spraying. Also on 32 bit
|
\ac{bof} vulnerabilities in combination with information leaks or other
|
||||||
systems, the address space is small enough to try a brute-force attempt until
|
techniques like heap spraying. Also on 32 bit systems, the address space is
|
||||||
the payload in memory is hit.
|
small enough to try a brute-force attempt until the payload in memory is
|
||||||
|
hit~\cite{Effectiveness2014}.
|
||||||
|
|
||||||
|
This is another technique that works without modification of the code base. Also
|
||||||
|
there is no runtime overhead because nothing changed except the location of the
|
||||||
|
program.
|
||||||
|
|
||||||
\subsection{w\^{}x Memory}
|
\subsection{w\^{}x Memory}
|
||||||
|
|
||||||
w\^{}x (also known as \ac{nx}) makes memory either writable or executable. That
|
w\^{}x (also known as \ac{nx} or \ac{dep}) makes memory either writable or
|
||||||
way, an attacker cannot place arbitiary payloads in memory. There are still
|
executable~\cite{AtkDef2016}. That way, an attacker cannot place arbitrary
|
||||||
techniques to exploit this by reusing existing executable code. The ret-to-libc
|
payloads in memory. There are still techniques to exploit this by reusing
|
||||||
exploiting technique uses existing calls to the libc with attacker controlled
|
existing executable code. The ret-to-libc exploiting technique uses existing
|
||||||
parameters, e.g.\ if the programm uses the \mintinline{shell}{system} command,
|
calls to the libc with attacker controlled parameters, e.g.\ if the program uses
|
||||||
the attacker can plant \mintinline{shell}{/bin/sh} as parameter on the stack,
|
the \mintinline{shell}{system} command, the attacker can plant
|
||||||
followed by the address of \mintinline{shell}{system} and get a shell on the
|
\mintinline{shell}{/bin/sh} as parameter on the stack, followed by the address
|
||||||
system. \ac{rop} (a superset of ret-to-libc exploits) uses so called \ac{rop}
|
of \mintinline{shell}{system} and get a shell on the system. \ac{rop} (a
|
||||||
gadgets, combinations of memory modifying instructions followed by the
|
superset of ret-to-libc exploits) uses so called \ac{rop} gadgets, combinations
|
||||||
\mintinline{ASM}{RET} instruction to build instruction chains, that execute the
|
of memory modifying instructions followed by the \mintinline{ASM}{RET}
|
||||||
desired shellcode. This is done by placing the desired return addresses in the
|
instruction to build instruction chains, that execute the desired shell-code.
|
||||||
right order on the stack and reuses the existing code to circumvent the w\^{}x
|
This is done by placing the desired return addresses in the right order on the
|
||||||
protection. These combinations of memory modification followed by
|
stack and reuses the existing code to circumvent the w\^{}x protection. These
|
||||||
\mintinline{ASM}{RET} instructions are called \ac{rop} chains and are turing
|
combinations of memory modification followed by \mintinline{ASM}{RET}
|
||||||
complete~\cite{Rop2007}, so in theory it is possible to implement any imaginable
|
instructions are called \ac{rop} chains and are Turing complete~\cite{Rop2007},
|
||||||
payload, as long as the exploited program contains enough gadgets and the
|
so in theory it is possible to implement any imaginable payload, as long as the
|
||||||
overflowing buffer has enough space.
|
exploited program contains enough gadgets and the overflowing buffer has enough
|
||||||
|
space.
|
||||||
|
|
||||||
|
|
||||||
\section{Discussion}\label{ref:discussion}
|
\section{Discussion}\label{ref:discussion}
|
||||||
|
|
||||||
\subsection{Ineffective or Inefficient}
|
\subsection{Effectiveness}
|
||||||
|
|
||||||
\subsubsection{\ac{aslr}}
|
\subsubsection{\ac{aslr}}
|
||||||
|
|
||||||
\Ac{aslr} has been really effective and wildly used in production. It is
|
\Ac{aslr} has been proven effective and is wildly used in production. It is
|
||||||
included in most major operating systems~\cite{FBSDaslr}. Some even use kernel
|
included in most major operating systems~\cite{FBSDaslr}. Some even use kernel
|
||||||
\ac{aslr}~\cite{Linuxaslr}. Since this mechanism is active at runtime, it does
|
\ac{aslr}~\cite{Linuxaslr}. Since this mechanism is active at runtime, it does
|
||||||
not require any changes in the code itself, the programm only has to be compiled
|
not require any changes in the code itself, the program only has to be compiled
|
||||||
as a \ac{pie}. On 32-bit CPUs, only 16-bit of the address are randomized. These
|
as a \ac{pie}. On 32-bit CPUs, only 16-bit of the address are randomized. These
|
||||||
16-bit can be brute forced in a few minutes or seconds~\cite{AslrEffective2004}.
|
16-bit can be brute forced in a few minutes or seconds~\cite{AslrEffective2004}.
|
||||||
|
|
||||||
|
There is no runtime overhead since the only change is the position of the
|
||||||
|
program in memory. Since there is no additional work except maybe recompilation,
|
||||||
|
this technique can and should be used on modern systems.
|
||||||
|
|
||||||
\subsubsection{w\^{}x}
|
\subsubsection{w\^{}x}
|
||||||
|
|
||||||
With the rise of \ac{rop} techniques, w\^{}x protection has been shown to be
|
With the rise of \ac{rop} techniques, w\^{}x protection has been shown to be
|
||||||
ineffective. It makes vulnerabilities harder to exploit but does not prevent
|
ineffective. It makes vulnerabilities harder to exploit by preventing the most
|
||||||
anything.
|
naive types of payloads but it doesn't actually prevent exploits from happening.
|
||||||
|
|
||||||
|
\Ac{nx} does not prevent any exploits but makes it harder for an attacker that
|
||||||
|
does not know the system, the program is running on (e.g.\ a network service).
|
||||||
|
It has no runtime overhead and is a compile-time option so it does not hurt to
|
||||||
|
enable \ac{nx}.
|
||||||
|
|
||||||
\subsubsection{Runtime Bounds Checks}
|
\subsubsection{Runtime Bounds Checks}
|
||||||
|
|
||||||
Checking for overflows at runtime is very effective but can have a huge
|
Checking for overflows at runtime is very effective but can have a huge
|
||||||
performance impact so it is not feasible in every case. It also comes with other
|
performance impact so it is not feasible in every case. It also comes with other
|
||||||
footguns. There might be integer overflows when calculating the bounts which
|
footguns. There might be integer overflows when calculating the bounds which
|
||||||
might introduce other problems.
|
might introduce other problems.
|
||||||
|
|
||||||
Methods that have been shown to be ineffective (e.g.\ can be circumvented
|
|
||||||
easily) or inefficient (to much runtime overhead)\ldots
|
|
||||||
|
|
||||||
\subsection{State of the Art}
|
\subsection{State of the Art}
|
||||||
|
|
||||||
What techniques are currently used?
|
Operating systems started to compile C code to \ac{pie} by
|
||||||
|
default~\cite{ArchPie2017} and \ac{aslr} is enabled, too. Same goes for \ac{nx}
|
||||||
|
and stack canaries~\cite{ArchPie2017}. The combination of these mitigations
|
||||||
|
makes it hard to write general exploits for modern operating systems.
|
||||||
|
|
||||||
\subsection{Outlook}
|
To check the current state, the latest release of the \ac{gcc} (9.2) and the
|
||||||
|
latest commit of the LLVM-project (\mintinline[breaklines]{shell}{181ab91efc9})
|
||||||
|
are compiled using the default configuration. The experiments are performed on a
|
||||||
|
64-bit Debian 9.11 system running on version 4.19.0 of the Linux kernel. The
|
||||||
|
following commands are used for compilation:
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\begin{subfigure}[b]{.3\textwidth}
|
||||||
|
\begin{minted}{shell}
|
||||||
|
mkdir objdir \
|
||||||
|
&& cd objdir \
|
||||||
|
&& ../configure \
|
||||||
|
--build=x86_64-linux-gnu \
|
||||||
|
--host=x86_64-linux-gnu \
|
||||||
|
--target=x86_64-linux-gnu \
|
||||||
|
--disable-multilib \
|
||||||
|
&& make -j8
|
||||||
|
\end{minted}
|
||||||
|
\caption{\ac{gcc} compilation script}\label{lst:gcc}
|
||||||
|
\end{subfigure}
|
||||||
|
\\
|
||||||
|
\begin{subfigure}[b]{.3\textwidth}
|
||||||
|
\begin{minted}{shell}
|
||||||
|
mkdir build \
|
||||||
|
&& cd build \
|
||||||
|
&& cmake -DLLVM_ENABLE_PROJECTS=clang \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-G "Unix Makefiles" ../llvm
|
||||||
|
&& make -j8
|
||||||
|
\end{minted}
|
||||||
|
\caption{clang compilation script}
|
||||||
|
\end{subfigure}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
The \mintinline{shell}{build}, \mintinline{shell}{host} and
|
||||||
|
\mintinline{shell}{target} parameters in~\ref{lst:gcc} only describe the target
|
||||||
|
platform for the compiler and \mintinline{shell}{disable-multilib} disables
|
||||||
|
32-bit support. The \mintinline{sh}{-j8} flag only tells make to use all 8
|
||||||
|
available cores for compilation.
|
||||||
|
|
||||||
|
The fresh builds of \ac{gcc} and clang compile the code from~\cref{lst:vuln} to
|
||||||
|
check which mitigations are enabled by default. Using
|
||||||
|
\mintinline[breaklines]{shell}{gcc -o vuln.gcc vuln.c} and
|
||||||
|
\mintinline[breaklines]{shell}{clang -o vuln.clang vuln.c} to compile the source
|
||||||
|
code, the \mintinline{shell}{checksec.sh} tool~\cite{Checksec2019} shows which
|
||||||
|
mitigations are active in the new binary:
|
||||||
|
|
||||||
|
\begin{table}[h!]
|
||||||
|
\begin{center}
|
||||||
|
\begin{tabular}{lll}
|
||||||
|
\toprule
|
||||||
|
Mitigation & Active in \ac{gcc}? & Active in clang? \\
|
||||||
|
\toprule
|
||||||
|
Stack Canary & No & No \\
|
||||||
|
\midrule
|
||||||
|
\ac{nx} & Yes & Yes \\
|
||||||
|
\midrule
|
||||||
|
\ac{pie} & No & No \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Enabled mitigations in a default \ac{gcc} and clang
|
||||||
|
build}\label{tab:mitigations}
|
||||||
|
\end{center}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
Surprisingly enough, two of the most popular C compilers enable only one of the
|
||||||
|
described compile-time mitigations by default. Maintainer of operating system
|
||||||
|
packages of the compiler might choose a more secure configuration for the
|
||||||
|
compiler as shown in~\cite{ArchPie2017} but still, compiler vendors might want
|
||||||
|
to choose better defaults, too.
|
||||||
|
|
||||||
|
So far, all described mitigations don't change anything about the existence of
|
||||||
|
\acp{bof} but just try to prevent the exploitation for code execution. The
|
||||||
|
vulnerable programs will still terminate if the stack canary is overwritten, a
|
||||||
|
call into \ac{nx} memory occurs or execution continues inside garbage data due
|
||||||
|
to \ac{aslr}. The underlying problem persists, only the worst results are
|
||||||
|
mitigated. \Ac{dos} is still a problem in safety critical systems (e.g.\ cars,
|
||||||
|
planes, medical devices) or in any area with real-time requirements.
|
||||||
|
|
||||||
|
Language extensions to fix the problem of \acp{bof} as described
|
||||||
|
in~\cite{Dep2007} require lots of discipline to use them everywhere. They are
|
||||||
|
only useful if the whole codebase uses the new features. Introducing them in an
|
||||||
|
existing codebase is quite unrealistic since it requires lots of modifications.
|
||||||
|
On the other hand, this actually prevents \acp{bof} from happening and not just
|
||||||
|
from being exploited, so it looks like an interesting concept for safety
|
||||||
|
critical software.
|
||||||
|
|
||||||
\section{Conclusion}\label{ref:conclusion}
|
\section{Conclusion}\label{ref:conclusion}
|
||||||
|
|
||||||
While there are many techniques, that protect against different types of
|
While there are many techniques, that protect against different types of
|
||||||
\acp{bof}, none of them is effctive in every situation. Maybe we've come to a
|
\acp{bof}, none of them is effective in every situation but in combination they
|
||||||
|
offer good protection against code execution attacks. Maybe we've come to a
|
||||||
point where we have to stop using memory unsafe languages where it is not
|
point where we have to stop using memory unsafe languages where it is not
|
||||||
inevitable. There are many modern programming languages, that aim for the same
|
inevitable. There are many modern programming languages, that aim for the same
|
||||||
problem space as C, C++ or Fortran but without the issues comming/stemming %TODO
|
problem space as C, C++ or Fortran but without the issues coming from these
|
||||||
from these languages. If it is feasible to use a garbage collector, Go might
|
languages. If it is feasible to use a garbage collector, languages like Go, Java
|
||||||
work just fine. If real-time properties are required, Rust could be the way to
|
or even scripting languages like Python might work just fine. If real-time
|
||||||
go, without any language runtime and with deterministic memory management. For
|
properties are required, Rust could be the way to go, without any language
|
||||||
any other problem, almost any other memory safe language is better than using
|
runtime and with deterministic memory management. For any other problem, almost
|
||||||
unsafe C.
|
any other memory safe language is better than using unsafe C.
|
||||||
|
|
||||||
\section{Sources (Dummy Section for Deadline)}
|
% \section{Sources (Dummy Section for Deadline)}
|
||||||
|
|
||||||
\begin{itemize}
|
% \begin{itemize}
|
||||||
|
|
||||||
\item RAD:\ A Compile-Time Solution to Buffer Overflow Attacks~\cite{Rad2001}
|
% \item RAD:\ A Compile-Time Solution to Buffer Overflow Attacks~\cite{Rad2001}
|
||||||
(might not protect against e.g.\ vtable overrides, \ac{plt} address changes,
|
% (might not protect against e.g.\ vtable overwrites, \ac{plt} address
|
||||||
\dots)
|
% changes, \dots)
|
||||||
|
|
||||||
\item Dependent types for low-level programming~\cite{Dep2007}
|
% \item Dependent types for low-level programming~\cite{Dep2007}
|
||||||
|
|
||||||
\item StackGuard: Automatic Adaptive Detection and Prevention of
|
% \item StackGuard: Automatic Adaptive Detection and Prevention of
|
||||||
Buffer-Overflow Attachs~\cite{Stackguard1998} (ineffective in combination
|
% Buffer-Overflow Attachs~\cite{Stackguard1998} (ineffective in combination
|
||||||
with information leaks)
|
% with information leaks)
|
||||||
|
|
||||||
\item Type-Assisted Dynamic Buffer Overflow Detection~\cite{TypeAssisted2002}
|
% \item Type-Assisted Dynamic Buffer Overflow Detection~\cite{TypeAssisted2002}
|
||||||
|
|
||||||
\item On the Effectiveness of NX, SSP, RenewSSP, and \ac{aslr} against Stack
|
% \item On the Effectiveness of NX, SSP, RenewSSP, and \ac{aslr} against Stack
|
||||||
Buffer Overflows~\cite{Effectiveness2014}
|
% Buffer Overflows~\cite{Effectiveness2014}
|
||||||
|
|
||||||
\item What Do We Know About Buffer Overflow Detection?: A Survey on Techniques
|
% \item What Do We Know About Buffer Overflow Detection?: A Survey on Techniques
|
||||||
to Detect A Persistent Vulnerability~\cite{Detection2018}
|
% to Detect A Persistent Vulnerability~\cite{Detection2018}
|
||||||
|
|
||||||
\item Survey of Attacks and Defenses on Stack-based Buffer Overflow
|
% \item Survey of Attacks and Defenses on Stack-based Buffer Overflow
|
||||||
Vulnerability~\cite{AtkDef2016}
|
% Vulnerability~\cite{AtkDef2016}
|
||||||
|
|
||||||
\item Beyond stack smashing: recent advances in exploiting buffer
|
% \item Beyond stack smashing: recent advances in exploiting buffer
|
||||||
overruns~\cite{Smashing2004}
|
% overruns~\cite{Smashing2004}
|
||||||
|
|
||||||
\item Runtime countermeasures for code injection attacks against C and C++
|
% \item Runtime countermeasures for code injection attacks against C and C++
|
||||||
programs~\cite{Counter2012}
|
% programs~\cite{Counter2012}
|
||||||
|
|
||||||
\end{itemize}
|
% \end{itemize}
|
||||||
|
|
||||||
|
|
||||||
\printbibliography{}
|
\printbibliography{}
|
||||||
|
@ -52,3 +52,13 @@
|
|||||||
short = DOS,
|
short = DOS,
|
||||||
long = denial of service
|
long = denial of service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
\DeclareAcronym{gcc}{
|
||||||
|
short = GCC,
|
||||||
|
long = GNU compiler collection
|
||||||
|
}
|
||||||
|
|
||||||
|
\DeclareAcronym{dep}{
|
||||||
|
short = DEP,
|
||||||
|
long = data execution prevention
|
||||||
|
}
|
||||||
|
@ -73,7 +73,7 @@ year = {2001}
|
|||||||
|
|
||||||
@ARTICLE{Smashing2004,
|
@ARTICLE{Smashing2004,
|
||||||
author={{Pincus}, J. and {Baker}, B.},
|
author={{Pincus}, J. and {Baker}, B.},
|
||||||
journal={{IEEE Security \& Privacy}},
|
journal={{IEEE Security and Privacy (SP)}},
|
||||||
title={{Beyond stack smashing: recent advances in exploiting buffer
|
title={{Beyond stack smashing: recent advances in exploiting buffer
|
||||||
overruns}},
|
overruns}},
|
||||||
year={2004},
|
year={2004},
|
||||||
@ -126,6 +126,22 @@ year={2007}
|
|||||||
title = {{7.1.1-4: enable SSP and PIE by default}}
|
title = {{7.1.1-4: enable SSP and PIE by default}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@online{Heardbleed2014,
|
||||||
|
url = {http://heartbleed.com/},
|
||||||
|
urlDate = {2019-12-15},
|
||||||
|
year = {2014},
|
||||||
|
title = {{The Heartbleed Bug}},
|
||||||
|
author = {{Codenomicon}},
|
||||||
|
}
|
||||||
|
|
||||||
|
@online{Checksec2019,
|
||||||
|
url = {https://github.com/slimm609/checksec.sh},
|
||||||
|
urlDate = {2019-12-16},
|
||||||
|
year = {2019},
|
||||||
|
title = {{Checksec.sh}},
|
||||||
|
author = {{Klein}, Tobias}
|
||||||
|
}
|
||||||
|
|
||||||
@online{Tiobe2019,
|
@online{Tiobe2019,
|
||||||
author = {{TIOBE}},
|
author = {{TIOBE}},
|
||||||
title = {{TIOBE Index for December 2019}},
|
title = {{TIOBE Index for December 2019}},
|
||||||
|
Loading…
Reference in New Issue
Block a user