2

I am learning Buffer Overflow, so the question might seem silly but here it is. I started with this very simple buggy program

int main(int argc, char *argv[])
{
  char buf[128];
  printf("You entered value %s\n", argv[1]);
  strcpy(buf,argv[1]);
  printf("%s\n", buf);
  printf("Program is exitting normally!!\n\n\n");
  return 0;
}

Now when I turn gdb on and run it with a simple set of input HElooooooooooooooooooooooooo, it works normally with eip set to very next instruction after strcpy function.

0x565555ce <+81>:   call   0x56555400 <strcpy@plt>
0x565555d3 <+86>:   add    $0x10,%esp
0x565555d6 <+89>:   sub    $0xc,%esp
0x565555d9 <+92>:   lea    -0x98(%ebp),%eax

$eip contains 0x565555d3 and I can see Little Endian version of my input smoothly. Things work fine.

(gdb) x/40x $esp
0xffffd260: 0xffffd270  0xffffd566  0xf7ffdaf8  0x56555598
0xffffd270: 0x6f6c4548  0x6f6f6f6f  0x6f6f6f6f  0x6f6f6f6f
0xffffd280: 0x6f6f6f6f  0x6f6f6f6f  0x6f6f6f6f  0x00000000
0xffffd290: 0x00000000  0x00000001  0xf7ffd940  0x000000c2

But when I provide it with 1000 A's. I expect to see corrupted area around $esp and an expected corrupted value of $eip something like 0x41414141 but neither of it happens.

After corruption, area around $esp looks pretty normal

(gdb) x/40x $esp
0xffffd27c: 0x565555d3  0xffffd290  0x00000000  0xf7ffdaf8
0xffffd28c: 0x56555598  0x00000000  0xf7fdff8b  0x5655523c
0xffffd29c: 0xffffd2fc  0xf7ffda9c  0x00000001  0xf7fcf410
0xffffd2ac: 0x00000001  0x00000000  0x00000001  0xf7ffd940
0xffffd2bc: 0x000000c2  0x00000000  0x00ca0000  0x00000000
0xffffd2cc: 0xf7ffd000  0x00000000  0x00000000  0x00000000
0xffffd2dc: 0xa7a40500  0x00000009  0xffffd56c  0xf7e03fa9
0xffffd2ec: 0xf7fac748  0xf7fa9000  0xf7fa9000  0x00000000

and $eip becomes 0xf7e62238 which obviously is not the right value of the next instruction after strcpy so it means something has changed it.

Now I am unable to find two things.

  1. Where are all A's?

  2. How $eip has changed like that?

I am using following command to disable protection plus I have changed /proc/sys/kernel/randomize_va_space to 0. gcc version is 7.3.0.

gcc -fno-stack-protector -zexecstack -m32 -o overflow overflow.c

Is there something preventing overflow which I have missed or something else?

perror
  • 813
  • 2
  • 10
  • 26
aneela
  • 201
  • 3
  • 10

2 Answers2

1

Try using the Switch "-g" , when you compile your c File with gcc.

Or there is something with the Security Features, that prevent your Code.

Did you try to break your Code ?

E.g.

"break main" and "break 5" and "break 8"

on "break 8" you might try to examine the buffer "x/s buf" or "x/40x buf" ?

Before ending the Program you should see a message that it can't access Address 0x41414141. After continuing you should see an error message.

Tech-IO
  • 259
  • 2
  • 11
  • Yeah I have inserted breakpoints but when I try to see the value of buf, it says `No symbol table is loaded. Use the "file" command.` I use again this command `file ./overflow` but it says `Reading symbols from ./overflow...(no debugging symbols found)...done.` I am not adding any breakpoints before starting gdb, i guess it says this for that reason. But I am unable to look at value of buf – aneela May 31 '18 at 06:10
  • Also I have searched and these are all the protections I have found so I dont know am I missing anything else – aneela May 31 '18 at 06:11
  • Try to compile your c code like "gcc -g -o overflow overflow.c" , with the -g switch it will load then the Symbols in gdb. – Tech-IO May 31 '18 at 07:52
  • Yeah i did and now debugging is fine – aneela May 31 '18 at 09:13
1

First, you better try to overflow the saved eip of a regular function, not main(). It is not really different, but the main() function is a bit specific and might give you a distorted view of reality.

Let's try with this code:

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

void foo(char *msg)
{
  char buf[64];
  printf ("You entered value %s\n", msg);
  strcpy (buf, msg);
  printf ("%s\n", buf);
}

int main (int argc, char *argv[])
{
  if (argc > 1)
    foo(argv[1]);

  printf ("Program is exiting normally!\n");
  return 0;
}

First, lets compile it:

$> gcc -Wall -Wextra -std=c11 -m32 -g -o vulnerable vulnerable.c

Then, lets start it with gdb:

$> gdb -q ./vulnerable
Reading symbols from ./vulnerable...done.
(gdb) b foo
Breakpoint 1 at 0x11db: file vulnerable.c, line 7.
(gdb) r $(python -c 'print("A" * 64)')
Starting program: /tmp/vulnerable $(python -c 'print("A" * 64)')

Breakpoint 1, foo (msg=0xffffd53a 'A' <repeats 64 times>) at vulnerable.c:7
7     printf ("You entered value %s\n", msg);
(gdb) 

Now, we are just at the point where we can overflow the buffer and overwrite the saved eip which is stored on the stack. But, we entered only 64 'A' (the size of the buffer), and we need to know how many 'A' we need to insert to reach the saved eip on the stack.

What we will try to do is:

  • Get the address of the buffer;
  • Get the address of the saved eip on the stack;
  • Get the difference between these two addresses which should give us the exact size of the padding we need to insert to reach the saved eip.

Lets go:

(gdb) p &buf
$1 = (char (*)[64]) 0xffffd280

(gdb) info frame
Stack level 0, frame at 0xffffd2d0:
 eip = 0x565561db in foo (vulnerable.c:7); saved eip = 0x56556249
 called by frame at 0xffffd300
 source language c.
 Arglist at 0xffffd2c8, args: msg=0xffffd53a 'A' <repeats 64 times>
 Locals at 0xffffd2c8, Previous frame's sp is 0xffffd2d0
 Saved registers:
  ebx at 0xffffd2c4, ebp at 0xffffd2c8, eip at 0xffffd2cc

(gdb) p 0xffffd2cc-0xffffd280
$3 = 76

Now, we know that if we feed the program with 76 characters of padding, we will overwrite the saved eip with the next 4 characters (you are in 32-bit here).

Lets try:

(gdb) r $(python -c 'print("A" * 76 + "\xde\xad\xbe\xef"[::-1])')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/vulnerable $(python -c 'print("A" * 76 + "\xde\xad\xbe\xef"[::-1])')

Breakpoint 1, foo (
    msg=0xffffd52a 'A' <repeats 76 times>, <incomplete sequence \336>)
    at vulnerable.c:7
7     printf ("You entered value %s\n", msg);
(gdb) n
You entered value AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAᆳ�
8     strcpy (buf, msg);
(gdb) info frame
Stack level 0, frame at 0xffffd2c0:
 eip = 0x565561f0 in foo (vulnerable.c:8); saved eip = 0x56556249
 called by frame at 0xffffd2f0
 source language c.
 Arglist at 0xffffd2b8, args: 
    msg=0xffffd52a 'A' <repeats 76 times>, <incomplete sequence \336>
 Locals at 0xffffd2b8, Previous frame's sp is 0xffffd2c0
 Saved registers:
  ebx at 0xffffd2b4, ebp at 0xffffd2b8, eip at 0xffffd2bc
(gdb) n
9     printf ("%s\n", buf);
(gdb) info frame
Stack level 0, frame at 0xffffd2c0:
 eip = 0x56556202 in foo (vulnerable.c:9); saved eip = 0xdeadbeef
 called by frame at 0xffffd2c4
 source language c.
 Arglist at 0xffffd2b8, args: 
    msg=0xffffd500 "S\340\347Q\217\363\004x(\355\ri686"
 Locals at 0xffffd2b8, Previous frame's sp is 0xffffd2c0
 Saved registers:
  ebx at 0xffffd2b4, ebp at 0xffffd2b8, eip at 0xffffd2bc

Now, we have the complete control of the saved eip as we just wrote 0xdeadbeef on it. Thus, we can control the execution once we exit from this foo() function.

If you want to look at what you just wrote on the stack, now you can do:

(gdb) x /32x $esp
0xffffd270: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd280: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd290: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd2a0: 0x41414141  0x41414141  0x41414141  0x41414141
0xffffd2b0: 0x41414141  0x41414141  0x41414141  0xdeadbeef
0xffffd2c0: 0xffffd500  0xffffd384  0xffffd390  0x5655622b
0xffffd2d0: 0xffffd2f0  0x00000000  0x00000000  0xf7de79a1
0xffffd2e0: 0xf7fa4000  0xf7fa4000  0x00000000  0xf7de79a1

As you can see, you find all the 76 'A' followed by the 0xdeadbeef. In fact, this is your buffer buf, followed by the saved ebp and the saved eip that you just rewrote.

A final note about the ASLR and the non-executable stack. These two protections are not playing any role here. They have to be disabled only if you want to execute a shellcode you inject through this overflow. The ASLR render more difficult to write a meaningful address in place of 0xdeadbeef because the memory context will change all the time. And, the non-executable stack, will just ruin your attempts to execute code on the stack.

If you just want to control the saved eip, you only need to disable the stack canaries (stack-protector option). The rest will be meaningful only afterward when you will try to use this control to redirect it to some code you own.

perror
  • 813
  • 2
  • 10
  • 26