RedHat's initscripts allows local users to execute arbitrary code as other users
28 Dec. 1999
Summary
The initscripts package contains, among other things, the default system shell initialization scripts. These scripts are executed upon login for users automatically. This advisory describes the script's insecure use of temporary files. L0pht describe the problem, offer a quick solution, and then provide a tool for demonstration of the attack.
Vulnerable systems:
initscripts-4.48-1 (Default version under RedHat 6.1)
The system-wide csh.login (/etc/csh.login) file tests for the existance of the /etc/profile.d directory. If the directory exists, it sources each file that exists in the directory that has a '.csh' suffix. Of these scripts, the lang.csh file tests for the existence of the /etc/sysconfig/i18n file and, if it exists, creates a shell script from the file after converting it to csh syntax. This file is created in the /tmp directory using the process ID as it's extension.
The offending lines of the code are:
sed 's|=C$|=en_US|g' /etc/sysconfig/i18n | sed "s|=| |g" \
| sed "s|^\([^#]\)|setenv \0|g" > /tmp/csh.$$
source /tmp/csh.$$
rm -f /tmp/csh.$$
As one can see, predicting the pid and pre-creating a link needs a few slight tweaks to work here. If the file linked to does not have the correct restrictive permissions, the redirection of the output from the sed(1) command will overwrite the file. If this happens the only chance for attack here is to replace the file between the end of the sed(1) line and before the next script command that sources the target file. This is an extremely small window to race.
If however, the temporary file is pre-created with a link pointing to a file with restrictive permissions such as 0444 then the destructive redirection of the output from the sed(1) command will fail. The next line will source the pre-created file and the line after that will attempt to remove it.
The only caveat to this is that the user logging in will see an error message on the attempt to redirect the output into the pre-created file. However, experience shows that the majority of users ignore such messages.
All of the requirements for this attack to work are met in the default US full install of RedHat 6.1.
Quick solution:
If temporary files must be created in public areas (that is not the only way to do it here), then proper care must be taken. One possible solution is to create a subdirectory in the public area and continue with the needed temporary files residing there. This solution works when care is taken to check the return value of the mkdir(1) command and use its atomic nature to ensure that race tricks are not played.
mkdir --mode=700 /tmp/csh_login.$$
if ($status != 0) then
echo "potential problem -- directory /tmp/csh_login.$$ already exists!"
exit
endif
sed 's|=C$|=en_US|g' /etc/sysconfig/i18n | sed "s|=| |g" | sed "s|^\([^#]\)|setenv \0|g" > /tmp/csh_login.$$/csh.$$
source /tmp/csh_login.$$/csh.$$
rm -f /tmp/csh_login.$$/csh.$$
rmdir /tmp/csh_login.$$
The diff is as follows:
--- /etc/profile.d/lang.csh Sun Sep 26 13:49:11 1999
+++ ./lang.csh.modified Sun Dec 26 20:59:25 1999
@@ -3,7 +3,14 @@
test -f /etc/sysconfig/i18n
if ($status == 0) then
- sed 's|=C$|=en_US|g' /etc/sysconfig/i18n | sed "s|=| |g" | sed "s|^\([^#]\)|setenv \0|g" > /tmp/csh.$$
- source /tmp/csh.$$
- rm -f /tmp/csh.$$
+ /bin/mkdir --mode=700 /tmp/csh_login.$$
+ if ($status != 0) then
+ echo "potential problem -- directory /tmp/csh_login.$$ already exists!"
+ exit
+ endif
+
+ sed 's|=C$|=en_US|g' /etc/sysconfig/i18n | sed "s|=| |g" | sed "s|^\([^#]\)|setenv \0|g" > /tmp/csh_login.$$/csh.$$
+ source /tmp/csh_login.$$/csh.$$
+ rm -f /tmp/csh_login.$$/csh.$$
+ /bin/rmdir /tmp/csh_login.$$
The script to force the user to execute is specified on the command line. If the script is not prepped with the correct permissions they are altered. It should be noted that the full path and filename should be specified here for the target script.
The program watches /etc/csh.login for the access time to change.
Upon seeing the a_time change the /proc directory is opened and walked looking for processes with the name of (tcsh).
For each entry it sees, a symbolic link is created to the target script suffixed with the tcsh process ID.
The targeted file is then watched for the a_time to change, which would signify execution. Upon seeing this the symbolic links that were created in the /tmp directory are removed.
A sample might be to create a file in /var/tmp such as demo.csh which would contain the following:
touch /tmp/`/usr/bin/whoami`.$$
And run the program as: ./init_race -f /var/tmp/demo.csh
The user logging in will see the error message
/tmp/csh.## : Permission denied.
Which signifies that we have won the race and a file will be created in the /tmp directory with the users name and the current pid. Of course, a malicious user could specify more nefarious scripts could be used in place of the above benign sample.