Narnia · Pwnable.kr

Pwnable.kr Toddler’s Bottle writeup

fd

Username : fd
Password : guest
SSH : pwnable.kr:2222

Solution

To solve this level, we first ssh into the pwnable server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-09-09 13-34-53.png

9-9-2017 1-36-11 PM.png

As we can see above, the executable expects a number to be passed to it. It then uses the number passed to calculate a file descriptor, fd which is then used to open a file. If the content of the file pointed by the fd pointer contains ‘LETMEWIN’ then the executable prints our flag.

To start off, let’s have a look at the Wikipedia page of file descriptor and understand what it is and why it’s needed. As we can see, the main purpose of the file descriptor is to provide us a channel to perform operations on a file. Each file descriptor performs a specific task (read/write) on a file.

As the executable compares the file content of the file pointed by fd with ‘LETMEWIN’, if we can create a file containing ‘LETMEWIN’ and know its file descriptor number, we can pass it to the executable to capture our flag. We can also see in the Wikipedia page that the value 0 for a file descriptor is a pipe to standard input. therefore, if we can change fd’s value to 0, we will be able to enter ‘LETMEWIN’ using standard input and capture the flag. To set the value of fd to 0, we need to pass 4660 (0x1234) to the executable as it is subtracted by that amount in the executable.

Screenshot from 2017-09-09 13-50-34.png

Flag : mommy! I think I know what a file descriptor is!!

Continue reading “Pwnable.kr Toddler’s Bottle writeup”

Narnia · OverTheWire

Narnia Level 7 → Level 8

Level 7

Username : narnia7
Password : ahkiaziphu
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-08-30 15-42-48.png

8-30-2017 2-45-52 PM.pngAs we can see above, the executable contains four functions main(), vuln(), hackedfunction(), and goodfunction().

The executable expects an argument from the user and passes it to vuln() function. The vuln() function as the name suggests is a vulnerable function. It uses a pointer to call goodfunction() which prints a statement and exits. The function of interest is hackedfunction() as we can see that function contains a system call to execute shell.

From a high level, this level seems very similar to Level 5 as we need to exploit it using string format vulnerability. If we can replace the value of pointer ‘ptrf’ to the address of hackedfunction() we can gain access to the shell. Let’s look at the inner working of the executable.

On starting the program, I set a breakpoint to right before the vuln() function is called to view the stack contents.

Screenshot from 2017-08-30 23-10-10.png

Screenshot from 2017-08-30 23-18-21.png

As we can see the executable pushes the address of the location which contains the content of the argument passed. The contents of this address are then copied to the buffer created in the vuln() function.

Another breakpoint has been set right after the snprintf() function is called within vuln().

Screenshot from 2017-08-30 23-16-16.png

As we can see above, the address and the copied content of the address are 6 words away from each other. Therefore, If we exploit the program using string format vulnerability, we can replace the 6th word with the address where we want our values written.

As this is a variation of string format vulnerability that I had to learn, I solved this problem in two different ways:

  1. Writing 2 bytes at a time
  2. Writing the entire word at a time

As we learned earlier, we can use the %u specifier to increase the width of the string, thus writing an arbitrary number of bytes in a location by using the %n specifier. Let’s use this technique to replace contents of the pointer ptrf to point to the location of hackedfunction() instead of goodfunction(). The executable prints the location of the pointer function and as we can see, the address that it points to is the address of goodfunction(). Therefore, if we modify the 6th word in the argument to point to the address of ptrf pointer and use %u and %n format specifier, we would be able to change the value to the address of hackedfunction().

Screenshot from 2017-08-31 17-56-48.png

As we can see above, by exploiting the string format vulnerability, we are able to right a random value at a location of our choice. In the case above, by writing 104 bytes (4 bytes of address and 100 bytes of %x), we are able to replace the value at the location “0xffffd67c” with 0x68 (104 in decimal). Let’s use this technique to replace the value with 0x8048706 which equates to 134514438 in decimal.

Screenshot from 2017-08-31 18-08-12.png

As we can see above, the executable prints the password to the next round as the value at the ptrf address is changed to the address of hackedfunction(). Note: 134514434 value is provided to the %u parameter as the address is 4 bytes long.

The method described above is easier and convenient, however, I also wanted to demonstrate another method of exploiting this by using short writes (2 bytes long each). It is very similar to the above method, however, instead of writing an entire word, it breaks the number to be overwritten into 2 different parts. The address to be written is 0x8048706. 0x804 (Higher bytes) is 2052 in decimals and 0x8706 (Lower bytes) is 34566 in decimals. Therefore, if we write the first 2 bytes in the higher address space and the last two bytes in the lower address space, we can achieve the same output as writing one single word.

Screenshot from 2017-08-31 18-17-35.png

As we can see above, by doing 2 different writes, one at the lower address (0xffffd65c) and one at the higher address (0xffffd65e) we were able to replace the value to the address of function hackedfunction().

Level 8

Username : narnia8
Password : mohthuphog
SSH : narnia.labs.overthewire.org:2226
Narnia · OverTheWire

Narnia Level 6 → Level 7

Level 6

Username : narnia6
Password : neezocaeng
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-08-12 16-27-23.png

8-12-2017 4-30-33 PM.png

As we can see above, the executable removes all the environment variables and arguments greater than 3 (argument 1 is the the executable call and arguments 2 and 3 are the two arguments passed to the executable). I was a little confused by the following line:

int (*fp)(char *)=(int(*)(char *))&puts

After refreshing my knowledge on pointers, I understood that the code is a function pointer initialized to point to puts(). Therefore whatever is passed to fp is simply printed on the console. As we know the strcpy is a vulnerable function to buffer overflow, let’s see if we can exploit it.

Screenshot from 2017-08-12 16-53-53.png

As we can see above, we can overflow the buffer and overwrite the return pointer. As we cannot utilize arguments and environment variable, we need to find a different way of gaining access to a shell. At this point, I decided to try and put a shellcode in the second argument in the hopes of being able to call that address by overflowing the argumnt 1 variable. However, since the length of the buffer is only 8 bytes, I ended up overflowing space allocated for argument 1 and replaced the return address with a word in the shellcode.

Screenshot from 2017-08-12 17-11-52.png

So now that we know that we cannot provide/store the shellcode in the executable, we need to think of a different way of exploiting it. Let’s look at the following code:

8-12-2017 5-34-43 PM.pngScreenshot from 2017-08-12 17-36-05.png

The code calls the system() function to execute ‘ls -l‘. Let’s now have a look at the internal workings of it in GDB.

Screenshot from 2017-08-12 16-23-17.png

As we can see above, right before the call to the system module is made, the command is pushed on the stack. Therefore, if we can call the system() function and pass ‘/bin/sh‘ to it, we might be able to access a shell.

Screenshot from 2017-08-12 19-27-48.png

As we can see above, we first find the address of the system() function and then pass our string ‘/bin/sh’ to it.

Screenshot from 2017-08-12 19-31-21.png

Level 7

Username : narnia7
Password : ahkiaziphu
SSH : narnia.labs.overthewire.org:2226
Narnia · OverTheWire

Narnia Level 5 → Level 6

Level 5

Username : narnia5
Password : faimahchiy
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-08-08 00-03-06.png

8-8-2017 12-04-26 AM.png

As we can see above, the executable sets the value of a variable i to 1. There is a clause within the code that lets us access the shell if the value for i has been changed to 500. The exdcutable copies the value from the argument to the variable buffer by using the sprintf function with size bounds. Therefore, we cannot overflow it to change the value of i to 500. We need to find another way.

After spending a considerable amount of time working on this, I learned that some functions are vulnerable to Format String Vulnerability and sprintf function is one of them. I followed the following documents and I hope they help you too. Link 1, Link 2.

Let’s see what’s on the stack and learn more about this vulnerability.

Screenshot from 2017-08-08 00-19-59.png

As we can see above, the executable is vulnerable to Format String Vulnerability and we can see the stack contents. Let’s verify this in gdb to gain a better understanding.

Screenshot from 2017-08-08 00-27-32.png

As we can see, the executable is indeed printing the stack contents. Let’s follow the documents above and try to insert our value in the address of variable i.

Screenshot from 2017-08-08 00-35-39.png

As we can see, the executable prints our argument ‘ABCD’ on the fifth iteration of %08x. Instead of using the %08x format specifier the fifth time, I decided to use the %n format specifier and pass the address of variable i to it. By using the %n format specifier, we can see that the value at the address that we have passed changes to 40. A %n specifier is used as a reference to the number of bytes written so far. Let’s dissect why the application printed 40 in this case. As we can see, we have 4 bytes of the address in little-endian form, bytes of %x specifier printed times consuming 32 bytes and 1 byte of . symbol printed times totaling 4 bytes. 32+4+4=40 and that is the reason why the number was overwritten to 40 at variable i. Let’s now use the %u specifier to increase the width of the output thus tricking the %n specifier. The number we are writing — the count of characters written by the format function — is dependent on the format string. Since we control the format string, we can at least take influence on this counter, by writing more or less bytes. By using a dummy parameter ‘%nu’ we are able to control the counter written by ‘%n’, at least a bit. As we already have 40 bytes using our previous shellcode. Let’s increase it to change the value of i to 500.

Screenshot from 2017-08-08 11-18-47.png

As we can see above, after changing the width of the shellcode, the value of i is changed to 500.

Level 6

Username : narnia6
Password : neezocaeng
SSH : narnia.labs.overthewire.org:2226
Narnia · OverTheWire

Narnia Level 4 → Level 5

Level 4

Username : narnia4
Password : thaenohtai
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

 

Screenshot from 2017-08-01 21-32-46.png

8-1-2017 9-33-27 PM.png

As we can see above, the executable doesn’t respond to any data provided as an argument and merely just exits after it’s done executing the commands. On looking at the code, we can see that the executable changes the data of environment variable to a Null character, thereby removing any shellcode that might be sitting in an environment variable.

The last few lines of the code are used to copy an argument provided to the executable into a buffer. My first impression was to use an environment variable similar to the previous two levels and somehow exploit the strlen function to think that my shellcode size is smaller than it is and preserve the shellcode in the environment variable.

Screenshot from 2017-08-01 21-45-31.png

As we can see above, the executable removes the content of an environment variable. After messing with it for a few times, I decided to take a different approach and look into the buffer variable. The executable simply copies the content of the argument to the buffer variable without checking for limit bounds. Therefore, if we can exceed the bounds, we can potentially create a buffer overflow and re-write the return pointer to the address of our shellcode which would be provided in the argument to the executable. Let’s try to find out how many bytes are needed to overflow the buffer.

Screenshot from 2017-08-01 21-51-20.png

As we know the size of the buffer variable is 256 characters, I decided to start with 260 characters and proceed upwards until I find my first Segmentation Fault. As we can see above, after inputting 272 characters, the executable returned an ‘Illegal Instruction’. From what I’ve seen in my past experiences, when the base pointer of the previous function is overwritten and not the return pointer, the executable responds with this error message. Therefore, 4 more bytes over this will re-write the return pointer. At this point I decided to run the program in gdb and figure out the address of my buffer. We can see that the executable uses strcpy to copy data from the argument to the buffer. Therefore, I set a breakpoint after strcpy function to see where the data was copied.

Screenshot from 2017-08-01 21-58-34.png

As the executable loads the effective address of ‘$esp+0x1c’, I decided to jump to that location and see if that’s the address of the buffer variable. The argument value that I provided was there in the buffer. Therefore, my next step was to create a slide of NOP’s and put my shellcode in between.

Screenshot from 2017-08-01 22-23-30.png

As we can see above, by using the shellcode used in the previous levels, we were able to re-write the return pointer to our shellcode address.

Level 5

Username : narnia5
Password : faimahchiy
SSH : narnia.labs.overthewire.org:2226
Narnia · OverTheWire

Narnia Level 3 → Level 4

Level 3

Username : narnia3
Password : nairiepecu
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-07-31 19-07-20.png

7-31-2017 7-08-58 PM.png

As we can see above, the executable reads a file that user provides and copies its content to ‘/tmp/null‘. ‘/tmp/null‘ is a special file that discards all data written to it but reports that the write operation succeeded. For more information on it, read this wikipedia page.

On a first pass at the C code, we can see that it utilizes the vulnerable strcpy function with no check on size limits. The allocation for an input file name is 32 bytes and the output file is 16 bytes. Let’s look at the code in a debugger.

Screenshot from 2017-07-31 19-17-01.png

We can see above that the executable copies the string name stored at 0x58(%esp) first and then the string name stored at 0x38(%esp). Both these locations probably store the file names to be opened. Therefore, we can conclude that if we overflow the buffer for input file name, we can modify the name for output file as well and possibly change it to something other than the null device.

Let’s confirm this theory by providing a filename more than 32 characters and breaking the flow in gdb before the files are opened.

Screenshot from 2017-07-31 19-26-27.png

As we can see, there are two breakpoints set and a long filename passed to the executable. At the first breakpoint which is right before the output file is opened, the value is set to “7890” and we can see in the next few statements that the file tried to be opened is “7890” which is 32 characters after our input file name. Therefore, we are successfully able to change the output file name. Let’s create a file “7890” and see how the input file looks like at the second breakpoint.

Screenshot from 2017-07-31 19-28-13.png

As we can see, the input filename is the one we provided to the executable. Therefore, now we control the input file and the output file. Let’s provide the executable an input file which contains or references the password and an output file which we control.

To solve this, I created a folder within /tmp called Narnia0003 and a folder within it called SecurityTimes003. The total length of the following string is 32 bytes.

/tmp/Narnia0003/SecurityTimes003

Therefore, anything that follows the above path will overwrite the output file. To solve that, I created an output file within /tmp named output. I also created an input file named output within a folder named tmp  which nests under /tmp/Narnia0003/SecurityTimes003. If we symbolically link this file to the password file, we can use it as the input file and the output file will be re-written to /tmp/output which is a file we can view.Screenshot from 2017-07-31 19-38-18.png

As we can see above, the executable updates the output file to our file and prints the password for the next level in it.

 

Level 4

Username : narnia4
Password : thaenohtai
SSH : narnia.labs.overthewire.org:2226
Narnia · OverTheWire

Narnia Level 2 → Level 3

Level 2

Username : narnia2
Password : nairiepecu
SSH : narnia.labs.overthewire.org:2226

Solution

To solve this level, we first ssh into the narnia server using the credentials provided above. Let’s have a look at the executable for this level and its source code.

Screenshot from 2017-07-27 12-54-49.png

7-27-2017 12-53-45 PM.png

As we can see, the executable copies the argument into a buffer and then prints it. The buffer size allocated is 128 characters. Therefore, if we can overflow the buffer by inserting more bytes than the executable expects, we can re-write the instruction pointer (EIP) to execute our shellcode. This level is very similar to the last level, however, this time around, the executable does not run our shellcode. We need to place our shellcode at a location whose address we are aware of and the executable can jump to it. In this scenario, I can think of two easy ways to solve this:

  1. Put the shellcode in the buffer and then jump to it after finding it’s address.
  2. Put the shellcode in an environment variable and jump to that address.

Since this level is very similar to the previous level, I decided to use environment variable to execute the shellcode. In the previous level, the executable executed our shellcode within the variable, however, this time around, we will need to replace the return pointer to jump to our shellcode address.

Let’s first determine after how many bytes does the executable overflows the return pointer.

Screenshot from 2017-07-28 15-43-35.png

As we can see above, the return pointer is overwritten after 140 characters. Therefore, we need to input our shellcode address after 140 characters.

Screenshot from 2017-07-28 15-40-09.png

Using the above programs, we will now create a simple python script to overflow the return pointer with the address returned by findeggaddr executable.

Screenshot from 2017-07-28 15-51-12.png

As we can see above, despite having an address for the shellcode, the executable throws a Segmentation Fault error with no core dump. At this point, to evaluate the core, I decided to make a copy of narnia2 executable in my temp directory and understand what’s happening behind the scene.

Screenshot from 2017-07-28 15-55-06.png

As we can see, the executable does return to our address, however, it still segment faults. Let’s see if our environment address is correct or not.

Screenshot from 2017-07-28 15-57-50.png

As we can see above, our address for EGG was incorrect and we can find the correct address by reading the environment variables inside gdb. After getting the correct value for shellcode address, we can execute narnia2 to get the password for the next level.

Level 3

Username : narnia3
Password : vaequeezee
SSH : narnia.labs.overthewire.org:2226