Niveau 1

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 :

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