Niveau 1
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 :
leviathan1@leviathan:~$ ls -la
total 28
drwxr-xr-x 2 root root 4096 Aug 26 2019 .
drwxr-xr-x 10 root root 4096 Aug 26 2019 ..
-rw-r--r-- 1 root root 220 May 15 2017 .bash_logout
-rw-r--r-- 1 root root 3526 May 15 2017 .bashrc
-r-sr-x--- 1 leviathan2 leviathan1 7452 Aug 26 2019 check
-rw-r--r-- 1 root root 675 May 15 2017 .profile
Le fichier check
semble être un exécutable, créer par l'utilisateur leviathan2
et accessible par l'utilisateur leviathan1
. Utilisons la commande file
pour obtenir des détails :
leviathan1@leviathan:~$ file check
check: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c735f6f3a3a94adcad8407cc0fda40496fd765dd, not stripped
Puis exécutons le fichier check
:
leviathan1@leviathan:~$ ./check
password: aze
Wrong password, Good Bye ...
Le programme nous demande un mot de passe que nous n'avons pas.
La commande strings
nous donne guère davantage d'informations :
leviathan1@leviathan:~$ strings check
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
puts
setreuid
printf
getchar
system
geteuid
strcmp
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRhp
QVh;
secrf
love
UWVS
t$,U
[^_]
password:
/bin/sh
Wrong password, Good Bye ...
;*2$"
GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
crtstuff.c
__JCR_LIST__
deregister_tm_clones
__do_global_dtors_aux
completed.6587
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
check.c
__FRAME_END__
__JCR_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
strcmp@@GLIBC_2.0
__x86.get_pc_thunk.bx
printf@@GLIBC_2.0
getchar@@GLIBC_2.0
_edata
geteuid@@GLIBC_2.0
__data_start
puts@@GLIBC_2.0
system@@GLIBC_2.0
__gmon_start__
__dso_handle
_IO_stdin_used
setreuid@@GLIBC_2.0
__libc_start_main@@GLIBC_2.0
__libc_csu_init
_fp_hw
__bss_start
main
__TMC_END__
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got.plt
.data
.bss
.comment
Nous allons utiliser gdb
pour réussir à contourner la demande de mot de passe du programme. Tout d'abord ouvrons le fichier check
avec gdb :
leviathan1@leviathan:~$ gdb check
Puis regardons le contenu de la fonction main
du programme en demandant à gdb de déssassembler le code correspondant :
(gdb) disas main
Dump of assembler code for function main:
0x0804853b <+0>: lea 0x4(%esp),%ecx
0x0804853f <+4>: and $0xfffffff0,%esp
0x08048542 <+7>: pushl -0x4(%ecx)
0x08048545 <+10>: push %ebp
0x08048546 <+11>: mov %esp,%ebp
0x08048548 <+13>: push %ebx
0x08048549 <+14>: push %ecx
0x0804854a <+15>: sub $0x20,%esp
0x0804854d <+18>: movl $0x786573,-0x10(%ebp)
0x08048554 <+25>: movl $0x72636573,-0x17(%ebp)
0x0804855b <+32>: movw $0x7465,-0x13(%ebp)
0x08048561 <+38>: movb $0x0,-0x11(%ebp)
0x08048565 <+42>: movl $0x646f67,-0x1b(%ebp)
0x0804856c <+49>: movl $0x65766f6c,-0x20(%ebp)
0x08048573 <+56>: movb $0x0,-0x1c(%ebp)
0x08048577 <+60>: sub $0xc,%esp
0x0804857a <+63>: push $0x8048690
0x0804857f <+68>: call 0x80483c0 <printf@plt>
0x08048584 <+73>: add $0x10,%esp
0x08048587 <+76>: call 0x80483d0 <getchar@plt>
0x0804858c <+81>: mov %al,-0xc(%ebp)
0x0804858f <+84>: call 0x80483d0 <getchar@plt>
0x08048594 <+89>: mov %al,-0xb(%ebp)
0x08048597 <+92>: call 0x80483d0 <getchar@plt>
0x0804859c <+97>: mov %al,-0xa(%ebp)
0x0804859f <+100>: movb $0x0,-0x9(%ebp)
0x080485a3 <+104>: sub $0x8,%esp
0x080485a6 <+107>: lea -0x10(%ebp),%eax
0x080485a9 <+110>: push %eax
0x080485aa <+111>: lea -0xc(%ebp),%eax
0x080485ad <+114>: push %eax
0x080485ae <+115>: call 0x80483b0 <strcmp@plt>
0x080485b3 <+120>: add $0x10,%esp
0x080485b6 <+123>: test %eax,%eax
0x080485b8 <+125>: jne 0x80485e5 <main+170>
0x080485ba <+127>: call 0x80483e0 <geteuid@plt>
0x080485bf <+132>: mov %eax,%ebx
0x080485c1 <+134>: call 0x80483e0 <geteuid@plt>
0x080485c6 <+139>: sub $0x8,%esp
0x080485c9 <+142>: push %ebx
0x080485ca <+143>: push %eax
0x080485cb <+144>: call 0x8048410 <setreuid@plt>
0x080485d0 <+149>: add $0x10,%esp
0x080485d3 <+152>: sub $0xc,%esp
0x080485d6 <+155>: push $0x804869b
0x080485db <+160>: call 0x8048400 <system@plt>
0x080485e0 <+165>: add $0x10,%esp
0x080485e3 <+168>: jmp 0x80485f5 <main+186>
0x080485e5 <+170>: sub $0xc,%esp
0x080485e8 <+173>: push $0x80486a3
0x080485ed <+178>: call 0x80483f0 <puts@plt>
0x080485f2 <+183>: add $0x10,%esp
0x080485f5 <+186>: mov $0x0,%eax
0x080485fa <+191>: lea -0x8(%ebp),%esp
0x080485fd <+194>: pop %ecx
0x080485fe <+195>: pop %ebx
0x080485ff <+196>: pop %ebp
0x08048600 <+197>: lea -0x4(%ecx),%esp
0x08048603 <+200>: ret
Les informations retournées par gdb sont divisées en 4 colonnes :
- la première colonne qui correspond à l'adresse mémoire de l'instruction (ex:
0x080485b3
) - la deuxième colonne contient l'adresse relative au sein de la fonction main (on peut dire que
<+60>
correspond àmain+60
) - un OPCODE, qui indique un type d'instruction
- une opération à effectuer au sein d'un registre
Ici plusieurs lignes nous intéressent :
0x080485ae <+115>: call 0x80483b0 <strcmp@plt>
L'opération call
indique qu'une autre fonction va être appelée. Ici c'est strcmp@plt
qui va être appelée, ce qui indique une comparaison de deux chaines de caractères (le mot de passe indiqué par l'utilisateur avec celui stocké dans le programme).
0x080485b6 <+123>: test %eax,%eax
0x080485b8 <+125>: jne 0x80485e5 <main+170>
La première ligne contient une opération test
qui a pour but de s'assurer que la comparaison faites précédemment a bien indiqué que les deux chaînes étaient identiques.
Enfin l'opération jne
(jump if not equal
) indique que le programme va comparer deux valeurs lors que l'exécution arrivera à cette instruction et si elles ne sont pas égales, sautera directement à l'instruction main+170
.
Afin de pouvoir trouver la solution de ce niveau il va donc falloir s'arranger pour ignorer cette instruction jne
de manière à accéder au "bon message" affiché à l'utilisateur lorsque le mot de passe indiqué est le bon.
La première étape va être de rajouter un breakpoint (un point d'arrêt qui stoppera l'exécution du programme) sur l'adresse de call
qui est le moment où les chaines de caractères sont comparées :
(gdb) b* main+115
Breakpoint 1 at 0x80485ae
Si l'on lance ensuite le programme avec la commande run, celui-ci s'exécute et s'arrête après que l'on ait entré un mot de passe :
(gdb) run
Starting program: /home/leviathan1/check
password: abc
Breakpoint 1, 0x080485ae in main ()
(gdb)
Nous sommes à l'instruction main+115
et on peut voir (en regardant la fonction main décompilée au-dessus) qu'après cela le programme ajoute 10
en esp puis test en eax.
La solution que nous allons utiliser ici est de sauter directement après le jne
à main+127
:
(gdb) jump* main+127
Continuing at 0x80485ba.
$
Le progamme nous donne alors accès à un shell. Regardons le nom de l'utilisateur de ce shell :
$ whoami
leviathan1
Nous sommes toujours identifiés en tant que leviathan1
ce qui ne nous donne pas davantage de droit de lecture qu'avant l'exécution du programme. Cela est (probablement) dû au fait que le programme est exécuté par gdb.
Relançons le programme :
(gdb) run
Starting program: /home/leviathan1/check
password: abc
Breakpoint 1, 0x080485ae in main ()
(gdb)
À ce stade, regardons le contenu de ce qui se trouve dans l'esp :
(gdb) x/2x $esp
0xffffd670: 0xffffd69c 0xffffd698
On sait donc que le programme a enregistré des valeurs en 0xffffd69c
et 0xffffd698
. Regardons le contenu à ces adresses :
(gdb) x/s 0xffffd69c
0xffffd69c: "abc"
(gdb) x/s 0xffffd698
0xffffd698: "sex"
Après avoir noté le mot de passe et constaté que le développeur du programme était un beauf, on peut quitter gdb et lancer le programme en indiquant le bon mot de passe :
leviathan1@leviathan:~$ ./check
password: sex
$ whoami
leviathan2
On a donc les droits de l'utilisateur leviathan2
. Comme expliqué dans les consignes de départ du challenge, on sait que le mot de passe de l'utilisateur leviathan2
est stocké dans le répertoire /etc/leviathan_pass
. Listons le contenu de ce répertoire :
$ ls /etc/leviathan_pass
leviathan0 leviathan2 leviathan4 leviathan6
leviathan1 leviathan3 leviathan5 leviathan7
Puis ouvrons le fichier leviathan2
:
$ cat /etc/leviathan_pass/leviathan2
ougahZi8Ta