213 lines
8.5 KiB
TeX
213 lines
8.5 KiB
TeX
\documentclass[conference]{IEEEtran}
|
|
\IEEEoverridecommandlockouts{}
|
|
% The preceding line is only needed to identify funding in the first footnote. If that is unneeded, please comment it out.
|
|
\usepackage{csquotes}
|
|
\usepackage[style=ieee,backend=biber]{biblatex}
|
|
|
|
\addbibresource{./bibliography.bib}
|
|
|
|
\usepackage{amsmath,amssymb,amsfonts}
|
|
\usepackage{algorithmic}
|
|
\usepackage{booktabs}
|
|
\usepackage{graphicx}
|
|
\usepackage{textcomp}
|
|
\usepackage{xcolor}
|
|
|
|
%additional packages
|
|
%\usepackage[ngerman]{babel}
|
|
\usepackage[utf8]{inputenc}
|
|
\usepackage{hyperref}
|
|
\usepackage{url}
|
|
%%fuer abkuerzungen begin
|
|
\usepackage[acronym,hyperfirst = false]{glossaries}
|
|
\glsdisablehyper{}
|
|
%\usepackage[acronym,acronymlists={main, abbreviationlist},shortcuts,toc,description,footnote]{glossaries}
|
|
\newglossary[clg]{abbreviationlist}{cyi}{cyg}{List of Abbreviations}
|
|
\newglossary[slg]{symbolslist}{syi}{syg}{Symbols}
|
|
\renewcommand{\firstacronymfont}[1]{\emph{#1}}
|
|
\renewcommand*{\glspostdescription}{} % Punkt am Ende jeder Beschreibung entfernen
|
|
\renewcommand*{\acrnameformat}[2]{#2 (\acronymfont{#1})} % Langform der Akronyme
|
|
\makeglossaries{}
|
|
\date{\today}
|
|
\input{glossary}
|
|
%%fuer abkuerzungen end
|
|
|
|
\begin{document}
|
|
|
|
\title{Overview Over Attack Vectors and Countermeasures for Buffer Overflows}
|
|
|
|
\author{\IEEEauthorblockN{Valentin Brandl}
|
|
\IEEEauthorblockA{\textit{Faculity of Computer Science and Mathematics} \\
|
|
\textit{OTH Regensburg}\\
|
|
Regensburg, Germany \\
|
|
valentin.brandl@st.oth-regensburg.de\\
|
|
MatrNr. 3220018}
|
|
}
|
|
|
|
\maketitle
|
|
|
|
\begin{abstract}
|
|
TODO
|
|
\end{abstract}
|
|
|
|
\begin{IEEEkeywords}
|
|
Buffer Overflow, Software Security
|
|
\end{IEEEkeywords}
|
|
|
|
|
|
|
|
\section{Motivation}\label{ref:motivation}
|
|
|
|
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
|
|
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
|
|
(information leaks, buffer overflows). Languages that are affected by this are
|
|
e.g. C, C++ and Fortran. These languages are still used in critical parts of
|
|
the worlds infrastructure, either because they allow to implement really
|
|
performant programms, because they power legacy systems or for portability
|
|
reasons. 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 those.
|
|
|
|
Reading out of bounds can result in an information leak and is less critical
|
|
than buffer overflows in most cases, but there are exceptions, e.g.\ the
|
|
Heartbleed bug in OpenSSL which allowed dumping secret keys from memory. Out of
|
|
bounds writes are almost always critical and result in code execution
|
|
vulnerabilities or at least application crashes.
|
|
|
|
|
|
\section{Main Part, TODO}\label{ref:main} %TODO!!!!
|
|
|
|
\subsection{Background}\label{ref:background}
|
|
|
|
% TODO: many references
|
|
|
|
\subsubsection{Technical Details}
|
|
|
|
Exploitation of buffer overflow vulnerabilities almost always works by
|
|
overriding the return address in the current stack frame, so when the `ret`
|
|
instruction is executed, an attacker controlled address is moved into the
|
|
instruction pointer register and the code pointed to by this address is
|
|
executed. Other ways include overriding addresses in the PLT of a binary so
|
|
that, if a linked function is called, an attacker controlled function is called
|
|
instead, or (in C++) overriding the vtable where the pointers to an object's
|
|
methods are stored.
|
|
|
|
\subsubsection{Implications}
|
|
|
|
\subsection{Concept and Methods}\label{ref:concept}
|
|
|
|
\subsubsection{Runtime Bounds Checks}
|
|
|
|
The easiest and maybe single most effective method to prevent buffer overflows
|
|
is to 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 or write in the buffer, if it is in bounds at runtime.
|
|
|
|
\subsubsection{Prevent/Detect Overriding Return Address}
|
|
|
|
Since most traditional buffer overflow exploits work by overriding the return
|
|
address in the current stack frame, preventing or at least detecting this, can
|
|
be quite effective without much overhead at runtime. \citeauthor{Rad2001}
|
|
describe a technique that stores a redudnant copy of the return address in a
|
|
secure memory 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 in the current stack frame and only, if it matches, the ret
|
|
instruction is actually executed\cite{Rad2001}. While this is effective against
|
|
return oriented programming based exploits, it does not protect against vtable
|
|
overrides.
|
|
|
|
An older technique from 1998 proposes to put a canary word between the data of a
|
|
stack frame and the return address\cite{Stackguard1998}. When returning, the
|
|
canary is checked, if it is still intact and if not, a buffer overflow occurred.
|
|
This technique is used in major operating systems %TODO
|
|
but can be defeted, if there is an information leak that leaks the cannary to
|
|
the attacker. The attacker is then able to construct a payload, that keeps the
|
|
canary intact.
|
|
|
|
\subsubsection{Restricting Language Features to a Secure Subset}
|
|
\subsubsection{Static Analysis}
|
|
\subsubsection{Type System Solutions}
|
|
|
|
\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
|
|
can have the buffer size associated to it. This prevents indexing into a buffer
|
|
with out of bounds values.
|
|
|
|
\subsubsection{ASLR}
|
|
|
|
ASLR aims to prevent exploitatoin of buffer overflows by placing code at random
|
|
locations in memory. That way, it is not trivial to set the return address to
|
|
point to the payload in memory. This is effective against generic exploits but
|
|
can still be exploited in combination with information leaks or other techniques
|
|
like heap spraying. Also on 32 bit systems, the address space is small enough to
|
|
try a brute-force attempt until the payload in memory is hit.
|
|
|
|
\subsubsection{w\^{}x Memory}
|
|
|
|
This mitigation makes memory either writable or executable. That way, an
|
|
attacker cannot place arbitiary payloads in memory. There are still techniques
|
|
to exploit this by reusing existing executable code. The ret-to-libc exploiting
|
|
technique uses existing calls to the libc with attacker controlled parameters,
|
|
e.g.\ if the programm uses the "system" command, the attacker can plant
|
|
"/bin/sh" as parameter on the stack, followed by the address of "system" and get
|
|
a shell on the system. Return oriented programming (a superset of ret-to-libc
|
|
exploits) uses so called ROP gadgets, combinations of memory modifying
|
|
instructions followed by the ret instruction to build instruction chains, that
|
|
execute the desired shellcode. This is done by placing the desired return
|
|
addresses in the right order on the stack and reuses the existing code to
|
|
circumvent the w\^{}x protection.
|
|
|
|
|
|
\subsection{Discussion}\label{ref:discussion}
|
|
|
|
\subsubsection{Ineffective or Inefficient}
|
|
|
|
Methods that have been shown to be ineffective (e.g. can be circumvented easily)
|
|
or inefficient (to much runtime overhead)...
|
|
|
|
\subsubsection{State of the Art}
|
|
|
|
What techniques are currently used?
|
|
|
|
|
|
\section{Conclusion and Outlook}\label{ref:conclusion}
|
|
|
|
While there are many techniques, that protect against different types of buffer
|
|
overflows, none of them is effctive in every situation. Maybe we've come to a
|
|
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
|
|
problem space as C, C++ or Fortran but without the issues comming/stemming %TODO
|
|
from these languages. If it is feasible to use a garbage collector, Go might
|
|
work just fine. If real-time properties are required, Rust could be the way to
|
|
go, without any language runtime and with deterministic memory management. For
|
|
any other problem, almost any other memory safe language is better than using
|
|
unsafe C.
|
|
|
|
\section{Sources}
|
|
|
|
\begin{itemize}
|
|
|
|
\item RAD:\ A Compile-Time Solution to Buffer Overflow Attacks\cite{Rad2001}
|
|
(might not protect against e.g.\ vtable overrides, PLT address changes,
|
|
\dots)
|
|
|
|
\item Dependent types for low-level programming\cite{Dep2007}
|
|
|
|
\item StackGuard: Automatic Adaptive Detection and Prevention of
|
|
Buffer-Overflow Attachs\cite{Stackguard1998} (ineffective in combination
|
|
with information leaks)
|
|
|
|
\item Type-Assisted Dynamic Buffer Overflow Detection\cite{TypeAssisted2002}
|
|
|
|
\end{itemize}
|
|
|
|
|
|
\printbibliography
|
|
% \bibliographystyle{IEEEtran}
|
|
% \bibliography{bibliography}
|
|
|
|
\end{document}
|
|
% vim: set filetype=tex ts=2 sw=2 tw=80 et spell :
|