|Introduction Source Code vs Executable Code Narnia Level 0 – Source Code Narnia Level 0 – Exploitation Narnia Level 0 – Solution|
In the challenges that are provided, you are given an executable and the source code to a program. The goal is to figure out a way to exploit or PWN the executable. Exploitation in this context typically refers to overwriting system memory to achieve some unintended outcome. Lets first talk about the files that are give to you.
Source Code vs Executable Code
Source code is the original language that a program is written in. Source code is then compiled into a set of instructions that the computer processor can execute. This translation from source code to executable code must happen, because computer processors do not understand source code, but they do understand the machine instructions inside executable code. Lets take a look at the difference
Narnia Level 0 – Source Code
Lets get started…
First we must ssh into the game server using the following credentials:
Server: narnia.labs.overthewrite.org Username: narnia0 Password: narnia0
The scanf function is used for user input. The %24s means that the function will accept a 24 byte character string (1 char = 1 byte) and store that into the buf variable, but if you remember buf was only allocated 20 bytes of memory. This is how we’re going to exploit the program, more on this later.
|These two lines help you see what values were actually stored in buf and val after scanf()received user input.|
Narnia Level 0 – Exploitation
As I stated before, we will need to take advantage of
scanf() in order to exploit this program, but to understand how, we first need to understand how programs get mapped into system memory.
Every program gets mapped into memory and uses a data structure known as “the stack” to store information such as variables, arguments and what instruction to execute next. It make sense to store these variables on the stack so that they can be easily and quickly retrieved as the program runs. Here is a graphical representation of what the stack looks like. Notice the arrow pointing from high memory to low memory, this is because the stack grows towards the lower memory locations. That means that if a programs defines three variables in the following order… int x= 10 int y = 20 int z = 30 …then they will be stored on the stack as such.
In order to exploit narnia0, this is all the information that we need to know. Other details about the stack such as the return address and old EBP (base pointer) will be explained in detail as we progress through the other levels. Lets see how the the narnia0 program looks on the stack.
Since the stack grows from high memory to low memory,
val is stored at a higher memory address than buf, because val was declared first in the program. Notice that the main program does not take any arguments on the command line, so those memory locations on the stack have been grey out (in reality they don’t even exist), and since this challenge only require us to manipulate buf and val, I’ve also grayed out Old EBP and Return Address, again we’ll discuss the purpose of these during future levels. How are we going to change val on the stack, so that it reads 0xdeadbeef? Remember the scanf() function that reads in 24 bytes of data? For the visual learners, here’s how that looks in memory. Each square in the illustration above represents 1-byte. val is of type long and long is defined as being 8-bytes. Again, we see that scanf() is set to take in 24-bytes of input and store them in the memory location of buf. The scanf() function does not check or care how big the destination location is; therefore, by filling up the scanf() buffer, we can overwrite the adjacent memory location of val.
Narnia Level 0 – Solution
Armed with the knowledge above, you may be temped (as I was) to try and solve the puzzle. Attempt 1: Although this did not work, important information can be gleaned from our failure. The first thing to notice is that value 0x64616564 is no where close to 0xdeadbeef. The answer to why lies on the second line that says “Correct val’s value from 0x4141414141 to 0xdeadbeef”. The 0x portion means that it wants the value of val to be in hex, but instead we passed it ASCII. The second thing to notice is that 0x64616564 is the ASCII equivalent of daed (or dead backwards). The reason our input was displayed backwards is because most x86 architectures store data in little-endian format when it is pushed onto the stack. This means that the least significant byte (far right value) gets stored in the lowest memory location, for example, if we set val to Hello, it would be stored in memory like this… Using this information lets try again. Attempt 2:First we need to figure out how to get hex into our ASCII input. The BASH shell has the ability to represent hex using the \x escape sequence, but in order for echo to parse escape sequence we have to add the -e option. Since hex values outside the ASCII range contain non-printable characters that are not easily copied and pasted, we are going to pipe the output directly to the program. This has the affect of storing our custom string into a buffer and waiting for scanf() to read it. Success? Sort of. The program didn’t yell at us and the val has been overwritten to the correct value, but the program closes immediately without allowing us to use our newly acquired privileges. Attempt 3: SUCCESS! If you create a command group ( command 1 ; command 2; ) and pipe the result to your program, each command is provided as a separate input to the program. The first input is our custom string which gets fed to the scanf() function. After the program executes system(“/bin/sh”) we are given a command shell, by passing cat to the command shell as a the second input, it keeps the command shell open, we are free to run any commands under the new elevated permissions. (I have scoured the internet high and low to figure out how and why that last part works, but have yet to find a solid answer).
…Coming Soon Narnia – Level 1…