When I was scrolling through my twitter feed 2 weeks ago I noticed that azeria just release new material on her website and it's about ROP in ARM. As you know we talk a lot about ROP in several posts on ARM buffer overflow thus I think this could be a good opportunity for me to learn the basic again about ROP again and without a second thought, I took my favorite notebook, click the link and start learning(check it out in link).
The author also put some challenges about how to construct ROP exploitation in an ARM architecture to test our skills and in this post, I will show you how I approach these challenges.
When you boot up the qemu emulator you can find the two binary in the challenges directory
Note: Before you continue this post make sure you turn off ASLR mode in the QEMU emulator
Challenge1: 1st approach(Without ROP)
At the first challenge, we got 32 bit ARM binary, not stripped and the PIE protection is on. Basically, PIE enables the program to randomly load its source code in different places. Try to run the program several times so we get the general idea of the workflow.
From the looks of it, the program will take the first argument as the input and if we try to load the program in GDB and provided really long character as its input, it will crash. Typical buffer overflow vulnerability
if we try to see the code in the program the culprit is in the func1 function since it's using strcpy() which consider as an unsafe function.
Let's try to find how many bytes we need to overwrite the PC register, to do this I'm using exploit-pattern tools. Next, all you have to do is put the pattern into the program and as you can see from the figure above the string "e4A" is overwrite the register. Put this result in the tool and we found that the offset is 133 bytes but notice something strange?
every time we crash the program the last character of the PC always ends up in "@" to get the actual offset you need to subtract it by one => 132
Let's try to test it again by crafting a simple python script and run it again in the program.
this time as you can see we accurately overwrite the PC register. Next, we need to find where we want to put our shellcode in the SP so we can jump to this location and take control of the program, we get the information inside the GDB like the below figure.
cool! we have a pretty roomful of space to put our shellcode, I will use 0xbefffab8 to place our shellcode. From this information, we can create our exploit like this:
This script will generate a payload that will redirect the instruction pointer to the desired location which is 0xbefffab8(where our shellcode is waiting to be executed). Run it in GDB and we can see that we got a shell
But unfortunately, when we run it outside the GDB this will eventually crash because of the different environment.
to get the actual location where we can put our shellcode outside the GDB environment we can utilize the core dump file. You can enable this feature by putting this command:
run the program one more time and it will create a core file, this file contains the last state of our program at the time of crash including information of register and stack content
load the core file by using this command:
~# gdb -c core ./challenge1
then dump the SP register and try to find where is your input, you can do this by adjusting the location by this command:
(gef) x/100wx $sp-100
from this result above we can see that our shellcode it actually located in 0xbec8baf8
update the script once again with this new location
................
shell_address = struct.pack("<I",0xbec8baf8)
................
Run it again and we can see from the below figure we got a shell :) cool!
Challenge1: 2nd approach(with ROP)
The advantage of using this approach is we don't have to worry about the location where we want to put our shellcode and all we need to do is to find a gadget that simply jumps to the top of the stack where our shellcode will be located.We can search for the gadget inside the libc.so.6 library by using "ropper" tools
from the above result, there are two gadgets: blx and bx it's up to you which one that you choose basically this two gadget will eventually jump into the stack pointer
next is to find the base address of the libc of the program. The address that we have just found in ropper is just a relative address and you need to add it with the base address of the libc when it's loaded in the program to get the actual location of the gadget. You can find this information in the following way:
get the first row of the start address and update our previous python script into this:
now all you have to do is run this script along with the program and we got a shell again :)
Finish Challenge2 with ROP
the second challenge is the same as the first one but the only difference its that the program is equipped with NX and PIE protection.Certainly, we cannot use the last two approaches because we cannot execute a shellcode inside the stack. So we need to find a proper that let us to execute Ret2libc attack
In the fundamental level ARM use R0-R3 as its 1st-4th argument when calling a function so we need to a find a proper gadget that let us load "/bin/sh" string to R0 as the first argument and jump to the system() function to execute shell
we can find the right gadget by using Ropper again just like the below figure:
we can use the pop{r0,pc} gadget and we need to find where is the location system() function in library, you can get this information in the following way:
remember! this location is a relative address we need to add with the base address of libc library. Fortunately, the location will be the same as the previous challenge because we turn off the ASLR.
The last thing we need to found is the location of the "/bin/sh" string, we can find the location by typing this command, in GDB:
(gef) find &system,+999999,"/bin/sh" (sorry i forgot to screenshot the result)
from all of the information we have gathered it's time to construct an exploit script:
run the script with the program and we got a shell :) cool!
Conclusion:
From this challenge, we got a chance to see several cases that show ROP help us to bypass the protection of NX and make our life easier.It is important to always find and solve this particular type of challenge to strengthen the basic over and over again
Lastly, I think from this exercise I could tell that ROP is one of the essential technique for all of the security enthusiast who wants to develop exploit in ARM environment and the author did a great job creating this exercise(*Two thumbs up).
So that's all for today post I hope to see you again in ARM exploitation challenge
Comments
Post a Comment