Bugtraq mailing list archives

Patch to prevent setuid bash shells


From: aleph1 () NATIONWIDE NET (aleph1 () NATIONWIDE NET)
Date: Sat, 30 May 1998 13:04:26 -0400


This patches bash 1.4.15 to prevent setuid root shells.  Of course, this
does not totally secure a system.  A buffer overflow could run /bin/csh
instead of /bin/sh, or any other command.

Not only does this patch prevent setuid root shells from spawning, but it
keeps a log file of all attempts, kills the user, and prevents them from
logging in again.  The administrator can monitor the log file and decide if
the person should be allowed back.

This blocks logins using the ~/.nologin file, I'm not sure if this works on
all systems, but it does work on mine.

All instances of the user logged in while the buffer overflow happens are
killed.  This keeps the intruder from attempting any other attacks.

This is my first attempt at a patch, so if I did it wrong don't mock me too
much =)

My theory is, if you can catch an intruder attempting a known attack, they
won't get a chance to exploit any unknown attacks.

------------------ CUT HERE --------------------
--- shell.c     Thu Apr  6 16:45:00 1995
+++ newshell.c  Sat May 30 12:31:44 1998
@@ -29,6 +29,8 @@
   Birthdate:
   Sunday, January 10th, 1988.
   Initial author: Brian Fox
+  Modified by: Ryan Veety [ryan () ryanspc com]
+     - now doesn't allow setuid shells, kills anyone that attempts them.
 */
 #define INSTALL_DEBUG_MODE

@@ -41,6 +43,7 @@
 #include <pwd.h>
 #include "posixstat.h"
 #include "bashansi.h"
+#include <utmp.h>

 #if defined (HAVE_VARARGS_H)
 #include <varargs.h>
@@ -247,6 +250,10 @@
   int arg_index, locally_skip_execution;
   int top_level_arg_index, read_from_stdin;
   FILE *default_input;
+  FILE *rootshell;
+  FILE *nologin_file;
+  char* nologin;
+  struct utmp* cutmp;

   /* There is a bug in the NeXT 2.1 rlogind that causes opens
      of /dev/tty to fail. */
@@ -275,8 +282,47 @@
   current_user.egid = getegid ();

   /* See whether or not we are running setuid or setgid. */
-  privileged_mode = (current_user.uid != current_user.euid) ||
-                   (current_user.gid != current_user.egid);
+  if(privileged_mode = (current_user.uid != current_user.euid) ||
+                   (current_user.gid != current_user.egid) != 0)
+  {
+
+    if(current_user.euid == 0)
+    {
+  /* Use the passwd file to get the users's login from the uid */
+      struct passwd *entry = getpwuid (current_user.uid);
+
+  /* Give a nice warning to the user */
+      printf("******************************************************\n");
+      printf("*                Root Shell detected!                *\n");
+      printf("*   This has been logged, and your account may be    *\n");
+      printf("*               terminated as a result.              *\n");
+      printf("******************************************************\n");
+
+  /* Well, we are running as root...so we can write to this file =) */
+  /* You can change this to any kind of administrator warning       */
+      rootshell=fopen("/usr/local/secure/rootshell", "a");
+      if(rootshell != NULL)
+      {
+         fprintf(rootshell, "SUID ROOT DETECTED from UID %d [%s].\n", current_user.uid, entry->pw_name);
+         fclose(rootshell);
+      }
+  /* Now its time to get rid of this guy!  */
+      nologin = (char*)malloc(strlen(entry->pw_dir) + strlen("/.nologin") +1);
+      sprintf(nologin, "%s/.nologin", entry->pw_dir);
+      nologin_file = fopen(nologin, "w");
+      if(nologin_file) fclose(nologin_file);
+      while((cutmp=getutent()) != NULL)
+         if(strncmp(cutmp->ut_user, entry->pw_name, 8) == 0)
+            kill(cutmp->ut_pid, SIGKILL);
+      return 1;
+    }
+    else
+    {
+  /* In case it is a setuid shell of bin, mail, ...   */
+      printf("Sorry, I don't allow setuid shells.\n");
+      return 1;
+    }
+  }

   posixly_correct = (getenv ("POSIXLY_CORRECT") != (char *)NULL) ||
                    (getenv ("POSIX_PEDANTIC") != (char *)NULL);

-------------------- CUT HERE -----------------------



Current thread: