all repos — site @ 6b66f5122d3818bdd3047a52520fbb6345e06de1

source for my site, found at icyphox.sh

pages/blog/rop-on-arm.md (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
---
template: text.html
title: Return Oriented Programming on ARM (32-bit)
subtitle: Making stack-based exploitation great again!
date: 05 June, 2019
---

# Return Oriented Programming on ARM (32-bit)
## Making stack-based exploitation great again!

Before we start _anything_, you’re expected to know the basics of ARM
assembly to follow along. I highly recommend
[Azeria’s](https://twitter.com/fox0x01) series on [ARM Assembly
Basics](https://azeria-labs.com/writing-arm-assembly-part-1/). Once you’re
comfortable with it, proceed with the next bit — environment setup.

### Setup

Since we’re working with the ARM architecture, there are two options to go
forth with: 

1. Emulate — head over to [qemu.org/download](https://www.qemu.org/download/) and install QEMU. 
And then download and extract the ARMv6 Debian Stretch image from one of the links [here](https://blahcat.github.io/qemu/).
The scripts found inside should be self-explanatory.
2. Use actual ARM hardware, like an RPi.

For debugging and disassembling, we’ll be using plain old `gdb`, but you
may use `radare2`, IDA or anything else, really. All of which can be
trivially installed.

Finally, the binary we’ll be using in this exercise is [Billy Ellis’](https://twitter.com/bellis1000)
[roplevel2](/static/files/roplevel2.c). 

Compile it:
```sh
$ gcc roplevel2.c -o rop2
```

With that out of the way, here’s a quick run down of what ROP actually is.

### A primer on ROP

ROP or Return Oriented Programming is a modern exploitation technique that’s
used to bypass protections like the **NX bit** (no-execute bit) and **code sigining**.
In essence, no code in the binary is actually modified and the entire exploit
is crafted out of pre-existing artifacts within the binary, known as **gadgets**.

A gadget is essentially a small sequence of code (instructions), ending with
a `ret`, or a return instruction. In our case, since we’re dealing with ARM
code, there is no `ret` instruction but rather a `pop {pc}` or a `bx lr`.
These gadgets are _chained_ together by jumping (returning) from one onto the other
to form what’s called as a **ropchain**. At the end of a ropchain,
there’s generally a call to `system()`, to acheive code execution.

In practice, the process of executing a ropchain is something like this:

- confirm the existence of a stack-based buffer overflow
- identify the offset at which the instruction pointer gets overwritten
- locate the addresses of the gadgets you wish to use
- craft your input keeping in mind the stack’s layout, and chain the addresses
of your gadgets

[LiveOverflow](https://twitter.com/LiveOverflow) has a [beautiful video](https://www.youtube.com/watch?v=zaQVNM3or7k&list=PLhixgUqwRTjxglIswKp9mpkfPNfHkzyeN&index=46&t=0s) where he explains ROP using “weird machines”. 
Check it out, it might be just what you needed for that “aha!” moment :)

Still don’t get it? Don’t fret, we’ll look at _actual_ exploit code in a bit and hopefully
that should put things into perspective.

### Exploring our binary

Start by running it, and entering any arbitrary string. On entering a fairly
large string, say, “AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”, we
see a segmentation fault occur.

![string and segfault](/static/img/string_segfault.png)

Now, open it up in `gdb` and look at the functions inside it.

![gdb functions](/static/img/gdb_functions.png)

There are three functions that are of importance here, `main`, `winner` and 
`gadget`. Disassembling the `main` function:

![gdb main disassembly](/static/img/gdb_main_disas.png)

We see a buffer of 16 bytes being created (`sub	sp, sp, #16`), and some calls
to `puts()`/`printf()` and `scanf()`. Looks like `winner` and `gadget` are 
never actually called.

Disassembling the `gadget` function:

![gdb gadget disassembly](/static/img/gdb_gadget_disas.png)

This is fairly simple, the stack is being initialized by `push`ing `{r11}`,
which is also the frame pointer (`fp`). What’s interesting is the `pop {r0, pc}`
instruction in the middle. This is a **gadget**.

We can use this to control what goes into `r0` and `pc`. Unlike in x86 where
arguments to functions are passed on the stack, in ARM the registers `r0` to `r3`
are used for this. So this gadget effectively allows us to pass arguments to
functions using `r0`, and subsequently jumping to them by passing its address
in `pc`. Neat.

Moving on to the disassembly of the `winner` function:

![gdb winner disassembly](/static/img/gdb_disas_winner.png)