Skip to main content

ARM buffer overflow: chapter 4 ಠ-ಠ (day 66)


Welcome back to another ARM buffer overflow challenge so in this post we are going to talk about how we can utilize multiple gadgets into the ROP chain to achieve our goal.

small recap:

As you guys know from the previous challenge we are able to take control of program by taking advantage of buffer overflow and using single gadget that contains instruction "pop {r0,pc}" by using this instruction we get the two top stack that we set to contain the address of "/bin/sh" and "system()" function, assign it to r0 (1st param) and pc (instruction pointer) to pop a shell

but using only a single gadget will not become effective in real-life scenario instead it will be mostly comprised of a huge and complex gadget.

to get the concept of this exploitation process, let's try to chain a two gadget together that able to overwrite a global variable

our target will be this following vulnerable code:

#import <stdio.h>
#import <unistd.h>

int changed_me = 0;

void gadget1(){

        __asm__("pop {r0,r1,pc}");
}

void gadget2(){

        __asm__("str r0,[r1]; pop {r4,pc}");
}


void validated(){
     char input[8];
     printf("You have to crash me ! \n");
     gets(input);
     if(changed_me != 0){
        system("/bin/sh");
     }else{
        printf("who the hell are you \n");
    }
}

int main(){

    printf("Welcome to ROPLevel3 version 2 \n\n");
    validated();   
    return 0;
}

~# gcc roplevel3.c -o roplevel3 --no-pie -fno-stack-protector

you can turn on the ASLR on

the following source code was inspired from roplevel3 Billie ellis exploit challenge link: https://github.com/Billy-Ellis/Exploit-Challenges/

finding the crash:








open the binary into gdb and let's input a long string to crash the application and from the figure, we can see that the offset is needed to be 13 but pay attention to the PC register at crash you can see that the character is kinda altered so you need to subtract the result of the pattern.py with one so it will be 12.

test it again with the following python script and we got the offset right





so we know how many offsets, we need to take control of the execution. It's time to construct the ROPGadget

our current objective is to overwrite the global variable changed_me by some random value (the point is we just need to insert some value onto the variable) if we able to do that we are able to grant access to execute a shell

there are two gadgets inside the source code:

void gadget1(){

        __asm__("pop {r0,r1,pc}");
}

void gadget2(){

        __asm__("str r0,[r1]; pop {r4,pc}");
}

the first gadget is set up the value of register r0,r1 and pc from the 3 top value in the stack and the second gadget will be used to store the value of r0 into the memory address that is stored in the r1 register and redirect the flow execution by popping the next two value of the stack

so here's how we construct the gadget :

first phase payload => padding + gadget1() address + 0x10101010 + <changed_me global variable address> + gadget2() address

the first phase we overwrite the PC register by pointing it into gadget1() function address now the gadget going to pop the 3 top value from the stack which is the value 0x10101010 m changed_me address and gadget2() address each of this value will be assigned to r0,r1,pc respectively after the first phase our current register will be like this

r0 = 0x10101010
r1 = <changed_me global variable address>
pc = gadget2() address

after this phase, the execution will continue to the gadget2() address

this will store r0 value that contains 0x010101010 to register r1 that right point to the memory address of changed_me global variable with this we are able to overwrite a value to a global variable

now all that's left is to redirect the execution again to the main function so we can get the shell

we need to update the previous payload to be like this: padding + gadget1() address + 0x10101010 + <changed_me global variable address> + gadget2() address + "AAAA" + main function

we append two value at the end of the payload since after storing the value to the global variable the gadget will assign the current stack value to register r4 and pc we need to provide two value to satisfy this execution, we don't care about the r4 value since we will not use it what we want is to assign the pc register with main function address so we can go back to that main function

Let's step through the payload manually so you get the sense of how the ROP works:



first, put a breakpoint at the end of the validated function and once we run it we are going to supply 12 characters so we know where we can edit the stack properly





this is how the stack looks like when we insert 12 characters notice that after the 12th character lies the return address.

we are going to overwrite this value with the payload that we have just construct previously

execute: ni so we can go to the next instruction

 



we need to gather this value in order to construct our payload





you can alter the stack value by using this command

0x00010484 => gadget1
0x01010101 => random value to get inserted into changed_me global variable
0x00020734 => location of changed_me global variable
0x0001049c => gadget2

of course, we need to supply additional value so we can get back to the main function.



let's step through the execution of our ROP chain one by one

the first is to execute the pop {r0,r1,pc}






once you arrive at the first gadget and type "ni" again now the register is set like the above figure





continue to the next instruction it will go to the second gadget that will store the value 0x01010101 to address global variable



if you proceed to the next instruction which is pop{r4,pc} it will update the register like the above figure. Continue the process we will end up with a shell

 

cool :) so we got a shell, now all it's left is to construct a python script with the following information we just got



 

COOL! WE GOT A SHELL!

So that's all folks hope you enjoy this post and see you again at the next arm buffer overflow series

Some note in this blog post in case you wondering why I am not using the original challenge

why don't you just use that challenge instead of creating your own?

yes I agree and I can do that but in the process of finishing the challenge, I encounter some unpleasant technical problems that make me nuts over 3 days but I'm grateful due to this struggle I get a chance to refine my understanding or buffer overflow.

1st technical problem, address, and bad character

as you guys know I compile the source code from the GitHub in azeria labs raspberry pi virtual machine but after I finish compiling the source code, the address of the global variable is using a bad character




in the original roplevel3 source code the user input is processed by scanf() function and scanf() will stop read your input if there are whitespace (0xb) and blank character (0x20) from the figure above we can see that the global variable stored in the address that contains blank character that will render our exploit useless. Well we can use ROP gadget to alter that condition but that will be a long and tedious process but I don't want to exhaust myself so I just changed the scanf to gets that are not sensitive to bad characters

2nd technical problem missing instruction

when I try to analyze the second gadget I noticed that after the second gadget "str r0, [r1]" there is no pop pc instruction that let us back to take control the execution flow so I altered the second gadget to have pop{r4,pc} :p


Comments

Popular posts from this blog

Having fun analyzing nginx log to find malicious attacker in the net (ง'̀-'́)ง (day 37)

  What makes you sleepless at night? is it because of a ghost or scary stories? is it because you have an important meeting tomorrow? or is it because you have an exam? For me, what keeps me up all night is that I keep thinking about what happens to a website that I just created, is it safe from an attacker (certainly not) or did I missing some security adjustments that lead to vulnerability? well I'm not the best secure programmer in the world, I'm still learning and there is a big possibility that I can make a mistake but for me, a mistake can be a valuable investment to myself or yourself to be better so from this idea, I want to know more about what attackers casually do when attacking a website. Here in this post, I'm going to show you how I analyzed attack to the website that I have permission to design and also some interesting findings that I could get from the analysis Background: All of this analysis comes from the traffic that is targeted to th...

Utilize Pwntools for crafting ROP chain :') (day 69)

who doesn't like pwntools? it is a very versatile tool and can be customized according to our need using the python script but did you need to know that pwntools itself can help us to automatically craft a rop chain for us? so in this post, I will show you how to make rop chain less painful and make pwntools do all the heavy lifting. To demonstrate this I will use the binary challenge callme 64 bit from ropemporium link: https://ropemporium.com/challenge/callme.html Crashing the app: Like any other exploitation process, we need to crash the program by generating a long string pattern to determine the offset. based on the information from the above figure we can see that we required to provide 40 bytes of offset Fun stuff: now this where the fun stuff began write the following python script: as in the guideline of the challenged said we need to chain the function call by first to call the callme_one function, callme_two function and then callme_three funct...

Bypassing stack canaries protection :') (day 51)

In my previous blogs, I show you guys how to bypass some common protection usually used in Linux binary such as NX and ASLR but this time we are going to take it to the next level we are going to talk about protection employ in the modern Linux OS which is "The Canaries" and how to bypass it. note: this post was not originally mined it was inspired by the following resources https://ctf-wiki.github.io/ctf-wiki/pwn/linux/mitigation/canary/ (Credit goes to the author) we are going to start this post about what is stack canaries and types of different implementation of it then move to the implementation about how to bypass this protection. We are going to focus on "leak canaries" technique What is stack canary: In layman terms, canaries are just another protection mechanism to prevent stack overflow implemented by appending 4/8 bytes value (depend on the architecture) into the stack when a function is entered. When the function is at the end of its exec...