Bugtraq mailing list archives

Re: more majordomo brokeness


From: Vince.Skahan () PSS BOEING COM (Skahan, Vince)
Date: Tue, 30 May 2000 07:49:52 -0700


This came up in January. It's also well documented in the majordomo FAQ:
http://www.greatcircle.com/majordomo/majordomo-faq.html#wrapsec

It is easily possible to remove 'all' interactive access to all the pieces
of the majordomo software, even if you are using smrsh, without modifying
the majordomo software itself.

        *       set the group id in majordomo's makefile to group 'mail'
                (assuming you're the same as RedHat and mail is delivered
                as mail.mail on your o/s - check it with a script that runs 'id')
        *       remove world r-x on majordomo's home dir and its contents
        *       remove world r-x on the list dir and its contents
        *       still have the symbolic link to wrapper for smrsh to work if you
                have that installed with your sendmail

Tested with majordomo 1.94-5 on RH-6.1 (sendmail8.9.3+smrsh)

--
-------- Vince.Skahan () boeing com ------ http://bcstec.ca.boeing.com/~vds/ -------------
                 Boeing Shared Services Group - Technical Services
                    outside Boeing - http://www.halcyon.com/vince

----------
From:         Federico G. Schwindt[SMTP:core.lists.bugtraq () CORE-SDI COM]
Reply To:     Federico G. Schwindt
Sent:         Tuesday, May 23, 2000 2:48 PM
To:   BUGTRAQ () SECURITYFOCUS COM
Subject:      more majordomo brokeness

Hi,

  Majordomo is a perl script for managing mailing lists. The package
comes with several scripts and a program written in C (wrapper) that
runs setuid to ensure that majordomo performs all the work with proper
permissions (for further information you can check the FAQ that comes
with the package under Doc/ or in
http://www.visi.com/~barr/majordomo-faq.html).
  This wrapper is installed by default as root, mode 4755 and group as
the one used for majordomo. What this means? If you can fool majordomo
to run arbitrary commands, they'll be run with uid and gid equal to the
one used for majordomo.
  Almost all of these scripts accept an optional configuration from the
command line, which is loaded and evaluated via perl's require keyword.
  This file is nothing else than perl code, thus creating a special file
with our commands and pointing it as the configuration of any of the
affected scripts will result in the following (this applies to majordomo
1.94.5):

$ cat /tmp/myconf
system("/bin/sh");
$ id
uid=1000(fgsch) gid=1000(fgsch) groups=1000(fgsch), 0(wheel), 11(core)
$ ./wrapper bounce-remind -C /tmp/myconf
$ id
uid=41(majordom) gid=41(majordom) groups=1000(fgsch), 0(wheel), 11(core)

  This is not new. The same problem has been seen in the past in the
majordomo script shipped with the previous version, 1.94.4 (for more
details, http://www.securityfocus.com/bid/903).
  Interesting enough, this occurs on several scripts: archive2.pl,
bounce-remind, config-test, digest, majordomo, request-answer and
resend; medit under bin/, and archive_mh.pl, new-list, and sequencer
under Tools/ uses 'require' in the same way, but since the wrapper only
executes those scripts found in the majordomo installation directory,
they cannot be exploited.
  The obvious fix is to remove this option from all the involved
scripts, but since it can be useful on large sites with several mailing
lists, we've choosen instead to only allow configuration files from a
trusted directory, removing the problem without loosing functionality.
  Diffs:

--- majordomo-1.94.5/Makefile.orig    Tue Jan 18 11:01:17 2000
+++ majordomo-1.94.5/Makefile Tue May 23 07:05:24 2000
@@ -63,7 +63,8 @@
 # passed to processes run by "wrapper"
 W_SHELL = /bin/sh
 W_PATH = /bin:/usr/bin:/usr/ucb
-W_MAJORDOMO_CF = $(W_HOME)/majordomo.cf
+W_MAJORDOMO_CF = majordomo.cf
+W_MAJORDOMO_CFDIR = $(W_HOME)/config

 # A directory for temp files..
 TMPDIR = /usr/tmp
@@ -77,7 +78,8 @@

 WRAPPER_FLAGS = -DBIN=\"$(W_HOME)\" -DPATH=\"PATH=$(W_PATH)\" > \
      -DHOME=\"HOME=$(W_HOME)\" -DSHELL=\"SHELL=$(W_SHELL)\" \
-     -DMAJORDOMO_CF=\"MAJORDOMO_CF=$(W_MAJORDOMO_CF)\"      \
+     -DMAJORDOMO_CF=\"MAJORDOMO_CF=$(W_MAJORDOMO_CFDIR)/$(W_MAJORDOMO_CF)\"
\
+     -DMAJORDOMO_CFDIR=\"MAJORDOMO_CFDIR=$(W_MAJORDOMO_CFDIR)\"      \
      $(POSIX)

 INSTALL = ./install.sh
--- majordomo-1.94.5/archive2.pl.orig Fri Jan  7 08:00:49 2000
+++ majordomo-1.94.5/archive2.pl      Tue May 23 07:47:09 2000
@@ -50,7 +50,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/contrib/archive_mh.pl.orig       Mon Mar 10 12:40:41 1997
+++ majordomo-1.94.5/contrib/archive_mh.pl    Tue May 23 07:50:23 2000
@@ -17,9 +17,9 @@
 $ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";

 # Read and execute the .cf file
-$cf = $ENV{"MAJORDOMO_CF"} || "/tools/majordomo-1.56/majordomo.cf";
+$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/bounce-remind.orig       Mon Dec  9 13:49:46 1996
+++ majordomo-1.94.5/bounce-remind    Tue May 23 07:47:27 2000
@@ -20,7 +20,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]";
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/config-test.orig Wed Aug 27 12:17:13 1997
+++ majordomo-1.94.5/config-test      Tue May 23 16:10:05 2000
@@ -117,6 +117,8 @@
 print "\n\tNon obvious things that cause headaches:\n\n";
 &header('');

+$ARGV[0] = ($ARGV[0] && $ARGV[0] !~ /\//) ?
+    "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[0]" : '';
 $cf = $ARGV[0] || $ENV{'MAJORDOMO_CF'};

 if (eval "require '$cf'") {
--- majordomo-1.94.5/digest.orig      Fri Jan  7 08:04:34 2000
+++ majordomo-1.94.5/digest   Tue May 23 16:02:49 2000
@@ -322,6 +322,8 @@
              &abort("-C used without -l");
          } else {
              # Read and execute the .cf file
+             $opt_c = ($opt_c && $opt_c !~ /\//) ?
+                 "$ENV{'MAJORDOMO_CFDIR'}/$opt_c" : '';
              $cf = $opt_c || $ENV{"MAJORDOMO_CF"} ||
                  "/etc/majordomo.cf";
              require "$cf";
--- majordomo-1.94.5/majordomo.orig   Thu Jan 13 14:29:31 2000
+++ majordomo-1.94.5/majordomo        Tue May 23 07:48:42 2000
@@ -29,7 +29,7 @@

 while ($ARGV[0]) {   # parse for config file or default list
     if ($ARGV[0] =~ /^-C$/i) {       # sendmail v8 clobbers case
-        $cf = $ARGV[1];
+        $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~
/\//;
         shift(@ARGV);
         shift(@ARGV);
     } elsif ($ARGV[0] eq "-l") {
--- majordomo-1.94.5/medit.orig       Mon Apr 28 15:38:05 1997
+++ majordomo-1.94.5/medit    Tue May 23 07:48:55 2000
@@ -19,7 +19,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/contrib/new-list.orig    Mon Dec  9 13:50:45 1996
+++ majordomo-1.94.5/contrib/new-list Tue May 23 07:50:41 2000
@@ -15,7 +15,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/request-answer.orig      Fri Jan  7 08:10:18 2000
+++ majordomo-1.94.5/request-answer   Tue May 23 07:49:10 2000
@@ -16,7 +16,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";>
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/resend.orig      Fri Jan  7 12:32:39 2000
+++ majordomo-1.94.5/resend   Tue May 23 16:02:37 2000
@@ -79,6 +79,9 @@
 }

 # Read and execute the .cf file
+$cfdir = $ENV{"MAJORDOMO_CFDIR"};
+$opt_C = ($opt_C && $opt_C !~ /\//) ? "$cfdir/$opt_C" : '';
+$opt_c = ($opt_c && $opt_c !~ /\//) ? "$cfdir/$opt_c" : '';
 $cf = $opt_C || $opt_c || $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";

 # Despite not having a place to send the remains of the body,
--- majordomo-1.94.5/contrib/sequencer.orig   Mon Dec  9 13:50:48 1996
+++ majordomo-1.94.5/contrib/sequencer        Tue May 23 07:50:58 2000
@@ -48,7 +48,7 @@
 # Read and execute the .cf file
 $cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
 if ($ARGV[0] eq "-C") {
-    $cf = $ARGV[1];
+    $cf = "$ENV{'MAJORDOMO_CFDIR'}/$ARGV[1]" unless $ARGV[1] =~ /\//;
     shift(@ARGV);
     shift(@ARGV);
 }
--- majordomo-1.94.5/wrapper.c.orig   Wed Aug 27 12:01:12 1997
+++ majordomo-1.94.5/wrapper.c        Tue May 23 07:06:23 2000
@@ -42,20 +42,27 @@
 #  define SHELL "SHELL=/bin/sh"
 #endif

+#ifndef MAJORDOMO_CF
+#  error "MAJORDOMO_CF not defined; edit Makefile"
+#endif
+
+#ifndef MAJORDOMO_CFDIR
+#  error "MAJORDOMO_CFDIR not defined; edit Makefile"
+#endif
+
 char * new_env[] = {
     HOME,            /* 0 */
     PATH,            /* 1 */
     SHELL,           /* 2 */
-#ifdef MAJORDOMO_CF
     MAJORDOMO_CF,    /* 3 */
-#endif
+    MAJORDOMO_CFDIR, /* 4 */
     0,               /* possibly for USER or LOGNAME */
     0,               /* possible for LOGNAME */
     0,          /* possibly for timezone */
     0
 };

-int new_env_size = 7;                                /* to prevent overflow problems */
+int new_env_size = 8;                                /* to prevent overflow problems */

 main(argc, argv, env)
     int argc;
@@ -89,11 +96,7 @@
      *  if they exist.
      */

-#ifdef MAJORDOMO_CF
-    e = 4; /* the first unused slot in new_env[] */
-#else
-    e = 3; /* the first unused slot in new_env[] */
-#endif
+    e = 5; /* the first unused slot in new_env[] */

     for (i = 0 ; env[i] != NULL && e <= new_env_size; i++) {
      if ((strncmp(env[i], "USER=", 5) == 0) ||
@@ -153,5 +156,6 @@
     fprintf(stderr, "    PATH is %s,\n", PATH);
     fprintf(stderr, "    SHELL is %s,\n", SHELL);
     fprintf(stderr, "    MAJORDOMO_CF is %s\n", MAJORDOMO_CF);
+    fprintf(stderr, "    MAJORDOMO_CFDIR is %s\n", MAJORDOMO_CFDIR);
     exit(EX_OSERR);
 }

  MAJORDOMO_CFDIR points to the trusted directory. You should store all
the configuration files there. Be sure that is pointing to the correct
place or majordomo won't work.
  We've also modified wrapper.c to barf if neither MAJORDOMO_CF nor
MAJORDOMO_CFDIR are defined, since there is no point in using it
otherwise, plus a few other minor paranoia changes... ;)
  Salute,

  f.-

--
Federico Schwindt - Developer                         fgsch () core-sdi com
Core SDI S.A.                                         http://www.core-sdi.com

--- For a personal reply use fgsch () core-sdi com




Current thread: