\documentclass{article}\usepackage{../style}\usepackage{../langs}\begin{document}\section*{Handout 3 (Buffer Overflow Attacks)}By far the most popular attack method on computers are bufferoverflow attacks or simple variations thereof. The popularity isunfortunate because we nowadays have technology in place to prevent themeffectively. But these kind of attacks are still very relevanteven today since there are many legacy systems out there andalso many modern embedded systems do not take any precautionsto prevent such attacks.To understand how buffer overflow attacks work, we have to havea look at how computers work ``under the hood'' (on themachine level) and also understand some aspects of the C/C++programming language. This might not be everyday fare forcomputer science students, but who said that criminal hackersrestrict themselves to everyday fare? Not to mention thefree-riding script-kiddies who use this technology withouteven knowing what the underlying ideas are. If you want to bea good security engineer who needs to defend such attacks, then better you know the details.For buffer overflow attacks to work, a number of innocentdesign decisions, which are really benign on their own, needto conspire against you. All these decisions were pretty muchtaken at a time when there was no Internet: C was introducedaround 1973; the Internet TCP/IP protocol was standardised in1982 by which time there were maybe 500 servers connected (andall users were well-behaved, mostly academics); Intel's first8086 CPUs arrived around 1977. So nobody of the``forefathers'' can really be blamed, but as mentioned abovewe should already be way beyond the point that buffer overflowattacks are worth a thought. Unfortunately, this is far fromthe truth. I let you ponder why?One such ``benign'' design decision is how the memory is laidout into different regions for each process. \begin{center} \begin{tikzpicture}[scale=0.7] %\draw[step=1cm] (-3,-3) grid (3,3); \draw[line width=1mm] (-2, -3) rectangle (2,3); \draw[line width=1mm] (-2,1) -- (2,1); \draw[line width=1mm] (-2,-1) -- (2,-1); \draw (0,2) node {\large\tt text}; \draw (0,0) node {\large\tt heap}; \draw (0,-2) node {\large\tt stack}; \draw (-2.7,3) node[anchor=north east] {\tt\begin{tabular}{@{}l@{}}lower\\ address\end{tabular}}; \draw (-2.7,-3) node[anchor=south east] {\tt\begin{tabular}{@{}l@{}}higher\\ address\end{tabular}}; \draw[->, line width=1mm] (-2.5,3) -- (-2.5,-3); \draw (2.7,-2) node[anchor=west] {\tt grows}; \draw (2.7,-3) node[anchor=south west] {\tt\footnotesize older}; \draw (2.7,-1) node[anchor=north west] {\tt\footnotesize newer}; \draw[|->, line width=1mm] (2.5,-3) -- (2.5,-1); \end{tikzpicture}\end{center}\noindent The text region contains the program code (usuallythis region is read-only). The heap stores all data theprogrammer explicitly allocates. For us the most interestingregion is the stack, which contains data mostly associatedwith the control flow of the program. Notice that the stackgrows from a higher addresses to lower addresses. That meansthat older items on the stack will be stored behind, or after,newer items. Let's look a bit closer what happens with thestack when a program is running. Consider the following simpleC program.\lstinputlisting[language=C]{../progs/example1.c} \noindent The \code{main} function calls \code{foo} with threearguments. \code{Foo} contains two (local) buffers. Theinteresting point for us will be what will the stack lokelike after Line 3 has been executed? The answer is as follows:\begin{center} \begin{tikzpicture}[scale=0.65] \draw[gray!20,fill=gray!20] (-5, 0) rectangle (-3,-1); \draw[line width=1mm] (-5,-1.2) -- (-5,0.2); \draw[line width=1mm] (-3,-1.2) -- (-3,0.2); \draw (-4,-1) node[anchor=south] {\tt main}; \draw[line width=1mm] (-5,0) -- (-3,0); \draw[gray!20,fill=gray!20] (3, 0) rectangle (5,-1); \draw[line width=1mm] (3,-1.2) -- (3,0.2); \draw[line width=1mm] (5,-1.2) -- (5,0.2); \draw (4,-1) node[anchor=south] {\tt main}; \draw[line width=1mm] (3,0) -- (5,0); %\draw[step=1cm] (-3,-1) grid (3,8); \draw[gray!20,fill=gray!20] (-1, 0) rectangle (1,-1); \draw[line width=1mm] (-1,-1.2) -- (-1,7.4); \draw[line width=1mm] ( 1,-1.2) -- ( 1,7.4); \draw (0,-1) node[anchor=south] {\tt main}; \draw[line width=1mm] (-1,0) -- (1,0); \draw (0,0) node[anchor=south] {\tt arg$_3$=3}; \draw[line width=1mm] (-1,1) -- (1,1); \draw (0,1) node[anchor=south] {\tt arg$_2$=2}; \draw[line width=1mm] (-1,2) -- (1,2); \draw (0,2) node[anchor=south] {\tt arg$_1$=1}; \draw[line width=1mm] (-1,3) -- (1,3); \draw (0,3.1) node[anchor=south] {\tt ret}; \draw[line width=1mm] (-1,4) -- (1,4); \draw (0,4) node[anchor=south] {\small\tt last sp}; \draw[line width=1mm] (-1,5) -- (1,5); \draw (0,5) node[anchor=south] {\tt buf$_1$}; \draw[line width=1mm] (-1,6) -- (1,6); \draw (0,6) node[anchor=south] {\tt buf$_2$}; \draw[line width=1mm] (-1,7) -- (1,7); \draw[->,line width=0.5mm] (1,4.5) -- (1.8,4.5) -- (1.8, 0) -- (1.1,0); \draw[->,line width=0.5mm] (1,3.5) -- (2.5,3.5); \draw (2.6,3.1) node[anchor=south west] {\tt back to main()};\end{tikzpicture}\end{center} \noindent On the left is the stack before \code{foo} iscalled; on the right is the stack after \code{foo} finishes.The function call to \code{foo} in Line 7 pushes the argumentsonto the stack in reverse order---shown in the middle.Therefore first 3 then 2 and finally 1. Then it pushes thereturn address to the stack where execution should resume once\code{foo} has finished. The last stack pointer (\code{sp}) isneeded in order to clean up the stack to the last level---infact there is no cleaning involved, but just the top of thestack will be set back. The two buffers are also on the stack,because they are local data within \code{foo}. So in themiddle is a snapshot of the stack after Line 3 has been executed. In case you are familiar with assembly instructionsyou can also read off this behaviour from the machinecode that the \code{gcc} compiler generates for the programabove:\footnote{You can make \pcode{gcc} generate assembly instructions if you call it with the \pcode{-S} option, for example \pcode{gcc -S out in.c}\;. Or you can lookat this code by using the debugger. This will be explainedlater.}.\begin{center}\small\begin{tabular}[t]{@{}c@{\hspace{8mm}}c@{}}{\lstinputlisting[language={[x86masm]Assembler}, morekeywords={movl},xleftmargin=5mm] {../progs/example1a.s}} &{\lstinputlisting[language={[x86masm]Assembler}, morekeywords={movl,movw},xleftmargin=5mm] {../progs/example1b.s}} \end{tabular}\end{center}\noindent On the left you can see how the function\pcode{main} prepares in Lines 2 to 7 the stack, beforecalling the function \pcode{foo}. You can see that thenumbers 3, 2, 1 are stored on the stack (the register\code{$esp} refers to the top of the stack). On the rightyou can see how the function \pcode{foo} stores the two localbuffers onto the stack and initialises them with the givendata (Lines 2 to 9). Since there is no real computationgoing on inside \pcode{foo} the function then just restoresthe stack to its old state and crucially sets the returnaddress where the computation should resume (Line 9 in thecode on the left hand side). The instruction \code{ret} thentransfers control back to the function \pcode{main} to theteh instruction just after the call, namely Line 9.Another part of the ``conspiracy'' is that library functionsin C look typically as follows:\begin{center}\lstinputlisting[language=C,numbers=none]{../progs/app5.c}\end{center} \noindent This function copies data from a source \pcode{src}to a destination \pcode{dst}. The important point is that itcopies the data until it reaches a zero-byte (\code{"\\0"}). The central idea of the buffer overflow attack is to overwritethe return address on the stack which states where the controlflow of the program should resume once the function at handhas finished its computation. So if we have somewhere in a function a local a buffer, say\begin{center}\code{char buf[8];}\end{center}\noindentthen the corresponding stack will look as follows\begin{center} \begin{tikzpicture}[scale=0.65] %\draw[step=1cm] (-3,-1) grid (3,8); \draw[gray!20,fill=gray!20] (-1, 0) rectangle (1,-1); \draw[line width=1mm] (-1,-1.2) -- (-1,6.4); \draw[line width=1mm] ( 1,-1.2) -- ( 1,6.4); \draw (0,-1) node[anchor=south] {\tt main}; \draw[line width=1mm] (-1,0) -- (1,0); \draw (0,0) node[anchor=south] {\tt arg$_3$=3}; \draw[line width=1mm] (-1,1) -- (1,1); \draw (0,1) node[anchor=south] {\tt arg$_2$=2}; \draw[line width=1mm] (-1,2) -- (1,2); \draw (0,2) node[anchor=south] {\tt arg$_1$=1}; \draw[line width=1mm] (-1,3) -- (1,3); \draw (0,3.1) node[anchor=south] {\tt ret}; \draw[line width=1mm] (-1,4) -- (1,4); \draw (0,4) node[anchor=south] {\small\tt last sp}; \draw[line width=1mm] (-1,5) -- (1,5); \draw (0,5) node[anchor=south] {\tt buf}; \draw[line width=1mm] (-1,6) -- (1,6); \draw (2,5.1) node[anchor=south] {\code{$esp}}; \draw[<-,line width=0.5mm] (1.1,6) -- (2.5,6); \draw[->,line width=0.5mm] (1,4.5) -- (2.5,4.5); \draw (2.6,4.1) node[anchor=south west] {\code{??}}; \draw[->,line width=0.5mm] (1,3.5) -- (2.5,3.5); \draw (2.6,3.1) node[anchor=south west] {\tt jump to \code{\\x080483f4}};\end{tikzpicture}\end{center}\noindent We need to fill this over its limit of8 characters so that it overwrites the stack pointerand then overwrites the return address. If, for example, we want to jump to a specific address in memory, say,\pcode{\\x080483f4} then we need to fill the buffer for example as follows\begin{center}\code{char buf[8] = "AAAAAAAABBBB\\xf4\\x83\\x04\\x08";}\end{center}\noindent The first 8 \pcode{A}s fill the buffer to the rim;the next four \pcode{B}s overwrite the stack pointer (withwhat data we overwrite this part is usually not important);then comes the address we want to jump to. Notice that we haveto give the address in the reverse order. All addresses onIntel CPUs need to be given in this way. Since the string isenclosed in double quotes, the C convention is that the stringinternally will automatically be terminated by a zero-byte. Ifthe programmer uses functions like \pcode{strcpy} for fillingthe buffer \pcode{buf}, then we can be sure it will overwritethe stack in this manner---since it will copy everything upto the zero-byte.What the outcome of such an attack is can be illustrated withthe code shown in Figure~\ref{C2}. Under ``normal operation''this program ask for a login-name and a password (both arerepresented as strings). Both of which are stored in buffersof length 8. The function \pcode{match} tests whether two such strings are equal. If yes, then the function lets you in(by printing \pcode{Welcome}). If not, it denies access(by printing \pcode{Wrong identity}). The vulnerable functionis \code{get_line} in Lines 11 to 19. This function does nottake any precautions about the buffer of 8 characters beingfilled beyond this 8-character-limit. The buffer overflowcan be triggered by inputing something, like \pcode{foo}, for the login name and then the specially crafted string as password:\begin{center}\code{AAAAAAAABBBB\\x2c\\x85\\x04\\x08\\n}\end{center}\noindent The address happens to be the one for the function\pcode{welcome()}. This means even with this input (where thelogin name and password clearly do not match) the program willstill print out \pcode{Welcome}. The only information we needfor this attack is to know where the function\pcode{welcome()} starts in memory. This information can beeasily obtained by starting the program inside the debuggerand disassembling this function. \begin{lstlisting}[numbers=none,language={[x86masm]Assembler}, morekeywords={movl,movw}]$ gdb C2GNU gdb (GDB) 7.2-ubuntu(gdb) disassemble welcome\end{lstlisting}\noindent The output will be something like this\begin{lstlisting}[numbers=none,language={[x86masm]Assembler}, morekeywords={movl,movw}]0x0804852c <+0>: push %ebp0x0804852d <+1>: mov %esp,%ebp0x0804852f <+3>: sub $0x4,%esp0x08048532 <+6>: movl $0x8048690,(%esp)0x08048539 <+13>: call 0x80483a4 <puts@plt>0x0804853e <+18>: movl $0x0,(%esp)0x08048545 <+25>: call 0x80483b4 <exit@plt>\end{lstlisting}\noindent indicating that the function \pcode{welcome()}starts at address \pcode{0x0804852c}.\begin{figure}[p]\lstinputlisting[language=C]{../progs/C2.c}\caption{A suspicious login implementation.\label{C2}}\end{figure}This kind of attack was very popular with commercial programsthat needed a key to be unlocked. Historically, hackers first broke the rather weak encryption of these locking mechanisms.After the encryption had been made stronger, hackers usedbuffer overflow attacks as shown above to jump directly tothe part of the program that was intended to be only availableafter the correct key was typed in by the user. \subsection*{Paylods}Unfortunately, much more harm can be caused by buffer overflowattacks. This is achieved by injecting code that will be runonce the return address is appropriately modified. Typicallythe code that will be injected is for running a shell. Inorder to be send as part of the string that is overflowing thebuffer, we need the code to be encoded as a sequence of characters\lstinputlisting[language=C,numbers=none]{../progs/o1.c}\noindent These characters represent the machine codefor opening a shell. It seems obtaining such a stringrequires higher-education in the architecture of thetarget system. But it is actually relatively simple: Firstthere are many ready-made strings available---just a quickGoogle query away. Second, tools like the debugger can help us again. We can just write the code we want in C, for example this would be the program to start a shell\lstinputlisting[language=C,numbers=none]{../progs/shell.c} \noindent Once compiled, we can use the debugger to obtain the machine code, or even the ready made encoding as charactersequence. While easy, obtaining this string is not entirely trivial.Remember the functions in C that copy or fill buffers worksuch that they copy everything until the zero byte is reached.Unfortunately the ``vanilla'' output from the debugger for theshell-program will contain such zero bytes. So apost-processing phase is needed to rewrite the machine codesuch that it does not contain any zero bytes. This is likesome works of literature that have been rewritten so that theletter 'i', for example, is avoided. For rewriting the machinecode you might need to use clever tricks like\begin{lstlisting}[numbers=none,language={[x86masm]Assembler}]xor %eax, %eax\end{lstlisting}\noindent This instruction does not contain any zero byte whenencoded, but produces a zero byte on the stack. Having removed the zero bytes we can craft the string that will be send to our target computer. It is typically of the form\begin{center} \begin{tikzpicture}[scale=0.7] \draw[line width=1mm] (-2, -1) rectangle (2,3); \draw[line width=1mm] (-2,1.9) -- (2,1.9); \draw (0,2.5) node {\large\tt shell code}; \draw[line width=1mm,fill=black] (0.3, -1) rectangle (2,-0.7); \draw[->,line width=0.3mm] (1.05, -1) -- (1.05,-1.7) -- (-3,-1.7) -- (-3, 3.7) -- (-1.9, 3.7) -- (-1.9, 3.1); \draw (-2, 3) node[anchor=north east] {\LARGE\tt "}; \draw ( 2,-0.9) node[anchor=west] {\LARGE\tt "}; \end{tikzpicture}\end{center}\bigskip\bigskip\subsubsection*{A Crash-Course for GDB}\begin{itemize}\item \texttt{(l)ist n} -- listing the source file from line \texttt{n}\item \texttt{disassemble fun-name}\item \texttt{run args} -- starts the program, potential arguments can be given\item \texttt{(b)reak line-number} -- set break point\item \texttt{(c)ontinue} -- continue execution until next breakpoint in a line number\item \texttt{x/nxw addr} -- print out \texttt{n} words starting from address \pcode{addr}, the address could be \code{$esp} for looking at the content of the stack\item \texttt{x/nxb addr} -- print out \texttt{n} bytes \end{itemize}\bigskip\bigskip \noindent If you want to know more aboutbuffer overflow attacks, the original Phrack article``Smashing The Stack For Fun And Profit'' by Elias Levy (alsoknown as Aleph One) is an engaging read:\begin{center}\url{http://phrack.org/issues/49/14.html}\end{center} \noindent This is an article from 1996 and some parts arenot up-to-date anymore. The article called``Smashing the Stack in 2010''\begin{center}\url{http://www.mgraziano.info/docs/stsi2010.pdf}\end{center}\noindent updates, as the name says, most information to 2010.\end{document}%%% Local Variables: %%% mode: latex%%% TeX-master: t%%% End: