rnd: add rust stack manipulation attempt
This commit is contained in:
parent
5ec6c7245e
commit
542c46a702
3 changed files with 116 additions and 23 deletions
|
@ -55,11 +55,21 @@ static void modifier(void) {
|
||||||
*(&p + 2) = (uint64_t *)simple_printer;
|
*(&p + 2) = (uint64_t *)simple_printer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void modifier_indexed(uint64_t *p) {
|
||||||
|
// without frame-pointer
|
||||||
|
(&p)[1] = (uint64_t *)simple_printer;
|
||||||
|
|
||||||
|
// with frame-pointer
|
||||||
|
(&p)[2] = (uint64_t *)simple_printer;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// caller();
|
// caller();
|
||||||
// many_args(0xfffffffffffffff0, 0xfffffffffffffff1, 0xfffffffffffffff3,
|
// many_args(0xfffffffffffffff0, 0xfffffffffffffff1, 0xfffffffffffffff3,
|
||||||
// 0xfffffffffffffff4, 0xfffffffffffffff5, 0xfffffffffffffff6,
|
// 0xfffffffffffffff4, 0xfffffffffffffff5, 0xfffffffffffffff6,
|
||||||
// 0xfffffffffffffff7);
|
// 0xfffffffffffffff7);
|
||||||
|
// modifier_indexed(NULL);
|
||||||
modifier();
|
modifier();
|
||||||
|
fprintf(stderr, "main exiting");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -84,9 +84,31 @@ fn caller() {
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn printer(a: &isize, b: &isize) {
|
fn printer(a: &isize, b: &isize) {
|
||||||
println!("2*{}={}", a, b);
|
println!("2*{}={}", a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn modifier() {
|
||||||
|
let mut sp: usize = 0xdeadbeef;
|
||||||
|
let addr = &mut sp as *mut usize;
|
||||||
|
// println!("{:p} {}", sp, addr as usize + 0x38);
|
||||||
|
// unsafe {
|
||||||
|
// std::ptr::write(sp.offset(4).as_mut().unwrap(), simple_printer);
|
||||||
|
// }
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write((addr as usize + 0x40) as *mut usize,
|
||||||
|
simple_printer as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn simple_printer() {
|
||||||
|
println!("I wonder who called me")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
caller();
|
modifier();
|
||||||
|
println!("main exiting")
|
||||||
}
|
}
|
|
@ -91,32 +91,57 @@ The goal of this chapter is to learn about \gls{Rust}'s stack protection mechani
|
||||||
|
|
||||||
\subsection{Return Address Manipulation Experiments}
|
\subsection{Return Address Manipulation Experiments}
|
||||||
\label{rnd::weakness-mitig-eval::stack-protection::ret-addr-experiments}
|
\label{rnd::weakness-mitig-eval::stack-protection::ret-addr-experiments}
|
||||||
The following manifestations are minimal constructions, supposedly to easy to understand.
|
Return address manipulation is a dangerous stack manipulation as it changes control flow of the program without explicit function calls.
|
||||||
They should allow to get a grasp of what vulnerabilities might look like, and at the same time display weaknesses of the \gls{C} language.
|
First a \gls{C} example demonstrates the issue, then a \gls{Rust} port is attempted.
|
||||||
|
|
||||||
\Cref{code::context::examples::sf-modification-simple} is a little example program in \gls{C}, which manipulates the return function address stored on the \gls{stack}.
|
\begin{figure}[ht!]
|
||||||
This is done by simple and legal pointer arithmetic.
|
\begin{minted}[linenos,breaklines]{c}
|
||||||
|
static void simple_printer(void) { fprintf(stderr, "I wonder who called me?"); }
|
||||||
|
void modifier(void) {
|
||||||
|
uint64_t *p;
|
||||||
|
*(&p + 1) = (uint64_t *)simple_printer;
|
||||||
|
*(&p + 2) = (uint64_t *)simple_printer;
|
||||||
|
}
|
||||||
|
int main(void) {
|
||||||
|
modifier();
|
||||||
|
fprintf(stderr, "main exiting");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
\end{minted}
|
||||||
|
\caption{Stack-Frame Modification in C}
|
||||||
|
\label{code::context::examples::sf-modification-simple-c}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\Cref{code::context::examples::sf-modification-simple-c} is a little example program in \gls{C}, which manipulates the return function address stored on the \gls{stack}.
|
||||||
|
This is done by simple and legal in \gls{C} pointer arithmetic.
|
||||||
It abuses the address of the first local variable to create references into the \gls{sf} below on the \gls{stack}.
|
It abuses the address of the first local variable to create references into the \gls{sf} below on the \gls{stack}.
|
||||||
Since the first variable is in the beginning of the \gls{sf} of the called function, it can be used to guess the position of the return address on the \gls{stack}.
|
Since the first variable is in the beginning of the \gls{sf} of the called function, it can be used to guess the position of the return address on the \gls{stack}.
|
||||||
Depending on the \gls{compiler} settings, the return address is stored either one or two stack entries in front of the first local variable for a function with no arguments.
|
Depending on the \gls{compiler} settings, the return address is stored either one or two stack entries in front of the first local variable for a function with no arguments.
|
||||||
In a brute-force manner the program simply overwrites both entries with the address of \code{simple_printer}.
|
In a brute-force manner the program simply overwrites both entries with the address of \code{simple_printer}.
|
||||||
By writing a different function address at these entries, the \code{ret} instruction will jump there, since the original return address has been overwritten.
|
By writing a different function address at these entries, the \code{ret} instruction will jump there, since the original return address has been overwritten.
|
||||||
|
|
||||||
|
The result of running this program will be \textit{I wonder who called me?Segmentation fault}.
|
||||||
|
|
||||||
|
\Cref{code::context::examples::sf-modification-simple-c-asm} shows the Assembly code of the \code{modifier} function from two different compilation runs.
|
||||||
|
One version makes use of the RBP register as the \gls{sf} Base-Pointer, and the other relies solely on the Stack-Pointer (RSP) for referencing \gls{sf} variables.
|
||||||
|
The RBP register is push onto the \gls{stack} in the function-prologue and restored in the function-epilogue, which takes up one \gls{stack} entry.
|
||||||
|
|
||||||
\begin{figure}[ht!]
|
\begin{figure}[ht!]
|
||||||
\begin{subfigure}[T]{0.60\textwidth}
|
\begin{subfigure}[T]{0.49\textwidth}
|
||||||
\centering
|
\centering
|
||||||
\begin{minted}[linenos,breaklines]{c}
|
\begin{minted}[linenos,breaklines]{objdump}
|
||||||
void modifier(void) {
|
push rbp
|
||||||
uint64_t *p;
|
mov rbp,rsp
|
||||||
*(&p + 1) =
|
movabs rax,0x400690
|
||||||
(uint64_t *)simple_printer;
|
mov QWORD PTR [rbp+0x0],rax
|
||||||
*(&p + 2) =
|
mov QWORD PTR [rbp+0x8],rax
|
||||||
(uint64_t *)simple_printer;
|
pop rbp
|
||||||
}
|
ret
|
||||||
|
nop DWORD PTR [rax+rax*1+0x0]
|
||||||
\end{minted}
|
\end{minted}
|
||||||
\subcaption{C code}
|
\caption{Compiled with \code{-fno-omit-frame-pointer}}
|
||||||
\end{subfigure}
|
\end{subfigure}
|
||||||
\begin{subfigure}[T]{0.39\textwidth}
|
\begin{subfigure}[T]{0.49\textwidth}
|
||||||
\centering
|
\centering
|
||||||
\begin{minted}[linenos,breaklines]{objdump}
|
\begin{minted}[linenos,breaklines]{objdump}
|
||||||
movabs rax,0x400690
|
movabs rax,0x400690
|
||||||
|
@ -124,10 +149,10 @@ mov QWORD PTR [rsp],rax
|
||||||
mov QWORD PTR [rsp+0x8],rax
|
mov QWORD PTR [rsp+0x8],rax
|
||||||
ret
|
ret
|
||||||
\end{minted}
|
\end{minted}
|
||||||
\subcaption{ASM code}
|
\subcaption{Compiled with \code{-fomit-frame-pointer}}
|
||||||
\end{subfigure}
|
\end{subfigure}
|
||||||
\caption{Stack-Frame Modification in C}
|
\caption{Stack-Frame Modification in C: Assembly}
|
||||||
\label{code::context::examples::sf-modification-simple}
|
\label{code::context::examples::sf-modification-simple-c-asm}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
\Cref{TODO-callstack-manipulation} is an attempt to visualize what happens in memory and with the \gls{stack} and the \gls{cpu}'s RIP {64-Bit Instruction Pointer} register.
|
\Cref{TODO-callstack-manipulation} is an attempt to visualize what happens in memory and with the \gls{stack} and the \gls{cpu}'s RIP {64-Bit Instruction Pointer} register.
|
||||||
|
@ -139,6 +164,36 @@ ret
|
||||||
\end{figure}
|
\end{figure}
|
||||||
\FloatBarrier
|
\FloatBarrier
|
||||||
|
|
||||||
|
\paragraph{Porting the above to Rust}
|
||||||
|
|
||||||
|
\begin{figure}[ht!]
|
||||||
|
\begin{minted}[linenos,breaklines]{rust}
|
||||||
|
...
|
||||||
|
#[inline(never)]
|
||||||
|
fn modifier() {
|
||||||
|
let mut sp: usize = 0xdeadbeef;
|
||||||
|
let addr = &mut sp as *mut usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write((addr as usize + 0x30) as *mut usize,
|
||||||
|
simple_printer as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
...
|
||||||
|
\end{minted}
|
||||||
|
\caption{Stack-Frame Modification \emph{attempt} in Rust}
|
||||||
|
\label{code::examples::sf-modification-simple-rust}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\cref{code::examples::sf-modification-simple-rust} shows the return instruction modification attempt in Rust.
|
||||||
|
Note that the hard-coded offset is \code{0x30}, which was individually calculated from the Assembly output.
|
||||||
|
Things to note:
|
||||||
|
\begin{itemize}
|
||||||
|
\item The above source code compiles
|
||||||
|
\item \code{unsafe} is required for writing to any raw pointers
|
||||||
|
\item For some reason the manipulation did not succeed.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
\subsection{Rust and the Stack Clash}
|
\subsection{Rust and the Stack Clash}
|
||||||
\label{rnd::weakness-mitig-eval::stack-protection::rust-stack-clash}
|
\label{rnd::weakness-mitig-eval::stack-protection::rust-stack-clash}
|
||||||
This subsection determines if \gls{Rust} can solve the issue described in \cpnameref{context::weaknesses-mem-safety::manifestations::stack-clash} from userspace and \gls{os} perspectives.
|
This subsection determines if \gls{Rust} can solve the issue described in \cpnameref{context::weaknesses-mem-safety::manifestations::stack-clash} from userspace and \gls{os} perspectives.
|
||||||
|
@ -159,12 +214,18 @@ This chapter presents the attempt to use \gls{Rust} for a simple buffer that is
|
||||||
\subsection{Libfringe}
|
\subsection{Libfringe}
|
||||||
% TODO: https://github.com/edef1c/libfringe
|
% TODO: https://github.com/edef1c/libfringe
|
||||||
|
|
||||||
|
|
||||||
\section{Systems}
|
\section{Systems}
|
||||||
\subsection{intermezzOS}
|
\subsection{intermezzOS}
|
||||||
\subsection{Blog OS}
|
\subsection{Blog OS}
|
||||||
\subsection{Redox}
|
\subsection{Redox OS}
|
||||||
\subsection{Tock}
|
\subsection{Tock OS}
|
||||||
%TODO: mention paper's by tockos team
|
Tock OS is "an embedded operating system designed for running multiple concurrent, mutually distrustful applications on low-memory and low-power microcontrollers."\footnote{\url{https://www.tockos.org/}}
|
||||||
|
|
||||||
|
In retrospection about their paper \citetitle{Levy2015a}\cite{Levy2015a} which reported on challenges they ran into early on building Tock in Rust, they state today:
|
||||||
|
"After feedback from the Rust developers and the community, we were able to overcome those challanges without modifications to the language. We also learned that we understated how disruptive some of the changes we proposed would be to the language and do not believe they are worthwhile. This has been discussed extensively now in the Rust community. You should read this paper critically, not as conclusive scientific findings, but as the perspectives of the authors during a particular point in the development of Tock."\footnote{\url{https://www.tockos.org/papers/}}
|
||||||
|
|
||||||
|
- TODO: shortly describe their initial issues with Rust
|
||||||
|
|
||||||
\chapter{\glsentrytext{imezzos}: Adding Preemptive \glsentrytext{os}-Level Multitasking}
|
\chapter{\glsentrytext{imezzos}: Adding Preemptive \glsentrytext{os}-Level Multitasking}
|
||||||
\label{rnd::imezzos-preemptive-multitasking}
|
\label{rnd::imezzos-preemptive-multitasking}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue