> > The 4.0.3 patch was, as far as I know, never released, and it certainly wasn't
> > rolled into 4.1.1. The above was the last I heard about the bug until I
> > complained again after we installed 4.1.1.

>   Hmm.  I looked up the bug, and found some proposed fixes by dan
> trinkle of purdue, but I'm not sure that they really do anything but
> slow the attackers down.  Again, I'll look at this and get back to you.

There's a bug in Dan's patch which allows a cracker to get the maps iff the last
legitimate request to ypserv was to the same map as the map the cracker is
requesting. I understand from a dark hint in one of Brad Powell's messages that
this problem was discovered by Sun Engineering.

Apart from that, Dan's patch should block any attacks apart from
host spoofing ones. Of course, if the attacker is clever enough to spoof hosts,
you will have to `take up arms against a sea of troubles'.

>   Indeed.  It's unbelievable that you can write to the things so easily
> and make the machine forget it's identity or something equally obnoxious.
> It's interesting to me that the system crackers seem to be getting
> more sophisticated; I'm wondering what, if anything, computer manufacturers
> will be doing with this?  I suppose that there will always be hosts that
> are poorly set up regardless of what you do.  I'd like to see something
> like the self-cleaning oven paridigm -- the more you use your system,
> the more secure it gets :-)

The getty hack was demonstrated to us by a student here (a German). I don't
know how well-know the problem is in German {h,cr}acker circles. As far as
self-cleaning goes, I think systems are more like colour CRT's than
self-cleaning ovens. They positively *attract* dirt and grime.

A small bunch of patches for pcops are attached.

The things changed are:
	1) '_' added to the allowed characters in login names & group names
	2) The pattern for allowed login and group names made the same
	3) Search for rexd rather than rexecd in /etc/inetd.conf. Perhaps
	   rexecd is also a security hole, but rexd(8)/on(1) is a gaping
	   cavernous one.
	4) Assorted hacking to get suid checking to work sort-of portably.
	   The test for NFS fs's is:
		       ($dev < 0 || $dev >= 16384)
	   Ultrix and AIX use large, rather than -'ve major devs for NFS mounts.
	   Apart from the added test and the argument parsing, the code in
	   suidfind.pl was generated by find2perl.
	   Using the -xdev test, and a list of the local mounts in /etc/fstab
	   is probably a better strategy than the above hack. Ultrix find
	   doesn't have -xdev, either, so I think find2perl is the way to go
	   on this.

regards,

peter

*** group.chk.orig	Sun Jun 23 15:35:27 1991
--- group.chk	Fri Dec  6 13:42:55 1991
***************
*** 92,98 ****
  	$groups{$group}++;   # keep track of dups
  	print "$W line $., does not have 4 fields:\n\t$_" if (@_ != 4);
  	print "$W line $., nonalphanumeric group name:\n\t$_"
! 	    if $group !~ /^[A-Za-z0-9-]+$/;
  	if ($pass && $pass ne '*') {
  	    if ( ! $C2 || $yp ) {
  		print "$W line $., group has password:\n\t$_"
--- 92,98 ----
  	$groups{$group}++;   # keep track of dups
  	print "$W line $., does not have 4 fields:\n\t$_" if (@_ != 4);
  	print "$W line $., nonalphanumeric group name:\n\t$_"
! 	    if $group !~ /^[_A-Za-z0-9-]+$/;
  	if ($pass && $pass ne '*') {
  	    if ( ! $C2 || $yp ) {
  		print "$W line $., group has password:\n\t$_"
*** passwd.chk.orig	Sun Jun 23 15:35:45 1991
--- passwd.chk	Fri Dec  6 13:42:53 1991
***************
*** 93,99 ****
  	$users{$user}++;    # keep track of dups
  	print "$W line $., does not have 7 fields:\n\t$_" if (@_ != 7);
  	print "$W line $., nonalphanumeric username:\n\t$_"
! 	    if $user !~ /^[A-Za-z0-9]+$/;
  	print "$W line $., numeric username:\n\t$_"
  	    if $user =~ /^\d+$/;
  	print "$W line $., login name > 8 characters:\n\t$_"
--- 93,99 ----
  	$users{$user}++;    # keep track of dups
  	print "$W line $., does not have 7 fields:\n\t$_" if (@_ != 7);
  	print "$W line $., nonalphanumeric username:\n\t$_"
! 	    if $user !~ /^[_A-Za-z0-9-]+$/;
  	print "$W line $., numeric username:\n\t$_"
  	    if $user =~ /^\d+$/;
  	print "$W line $., login name > 8 characters:\n\t$_"
*** misc.chk.orig	Sun Jun 23 15:35:35 1991
--- misc.chk	Tue Dec  3 14:09:43 1991
***************
*** 58,64 ****
  		 ( -f '/etc/servers' && '/etc/servers') ||
  		 'BOGUS';
  	}
! $rexd="rexecd";
  
  # tmp and target file (for tftp test)
  $target="/etc/motd";
--- 58,64 ----
  		 ( -f '/etc/servers' && '/etc/servers') ||
  		 'BOGUS';
  	}
! $rexd="rexd";
  
  # tmp and target file (for tftp test)
  $target="/etc/motd";
*** suid.chk.orig	Fri Aug 30 17:17:49 1991
--- suid.chk	Tue Dec  3 16:51:41 1991
***************
*** 43,55 ****
  $usage = "Usage: $0 [-n] [-s secure_dir] [starting_directory]\n";
  require 'getopts.pl';
  # Process the command args; Either specify verbose or an alternate config file:
! die $usage unless &`Getopts('ns:');
  
  $suid_dir = $'SECURE || '.';
! if (defined($opt_s)) { $suid_dir = $opt_s; }
  
  # Do NFS stuff?  Yes unless opt:
! if (defined($opt_n)) { $skip_nfs = $opt_n; }
  else { $skip_nfs = 0; }
  
  $STOP="$suid_dir/suid.stop";
--- 43,55 ----
  $usage = "Usage: $0 [-n] [-s secure_dir] [starting_directory]\n";
  require 'getopts.pl';
  # Process the command args; Either specify verbose or an alternate config file:
! die $usage unless &'Getopts('ns:');
  
  $suid_dir = $'SECURE || '.';
! if (defined($'opt_s)) { $suid_dir = $'opt_s; }
  
  # Do NFS stuff?  Yes unless opt:
! if (defined($'opt_n)) { $skip_nfs = $'opt_n; }
  else { $skip_nfs = 0; }
  
  $STOP="$suid_dir/suid.stop";
***************
*** 64,83 ****
  
  # these may be terribly rash assumptions....
  $start_dir="/" unless defined $start_dir;
- $find_can_ls = 1 unless defined $find_can_ls;
  
- $NONFS = '-type d \( -fstype nfs -prune \) -o' if $skip_nfs;  
- $find_ls = $find_can_ls ? '-ls' : "-exec $'LS -gilds {} \\;";
- 
  die "Error -- Security directory $suid_dir doesn't exist\n"
      unless -d $suid_dir;
  unless (-d $suid_dir) {
      mkdir($suid_dir, 0700) || die "can't mkdir $suid_dir: $!";
! } 
  chdir $suid_dir || die "can't chdir $suid_dir: $!\n";
  
  # find the setuid programs and sort
! &run("$'FIND $start_dir $NONFS -type f \\( -perm -4000 -o -perm -2000
\\) $find_ls | $'SORT > $TEMPCUR");
  
  # compare with the sorted stop list
  # create stop file if needed
--- 64,82 ----
  
  # these may be terribly rash assumptions....
  $start_dir="/" unless defined $start_dir;
  
  die "Error -- Security directory $suid_dir doesn't exist\n"
      unless -d $suid_dir;
  unless (-d $suid_dir) {
      mkdir($suid_dir, 0700) || die "can't mkdir $suid_dir: $!";
! }
! 
  chdir $suid_dir || die "can't chdir $suid_dir: $!\n";
  
  # find the setuid programs and sort
! 
! &run("$suid_dir/suidfind.pl".($skip_nfs ? " -n " : " ").$start_dir
! 	. "| $'SORT > $TEMPCUR");
  
  # compare with the sorted stop list
  # create stop file if needed
*** /dev/null	Mon Dec 23 11:46:59 1991
--- suidfind.pl	Tue Dec  3 10:39:42 1991
***************
*** 0 ****
--- 1,123 ----
+ #!/bin/sh -- need to mention perl here to avoid recursion
+ 'true' || eval 'exec perl -S $0 $argv:q';
+ eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec /usr/local/bin/perl -S $0 $argv:q'
+         if 0;
+ 
+ #
+ #  Usage: suidfind.pl [-n] [-s secure_dir] [search_starting_directory]
+ #
+ 
+ require "getopts.pl";
+ 
+ die $usage unless &Getopts('n');
+ 
+ # Do NFS stuff?  Yes unless opt:
+ if (defined($opt_n)) { $skip_nfs = $opt_n; }
+ else { $skip_nfs = 0; }
+ 
+ if (@ARGV > 1) { die $usage; }
+ elsif (@ARGV == 1) { $start_dir = shift; }
+ 
+ # these may be terribly rash assumptions....
+ $start_dir="/" unless defined $start_dir;
+ 
+ @rwx = ('---','--x','-w-','-wx','r--','r-x','rw-','rwx');
+ @moname = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);
+ 
+ while (($name, $pw, $uid) = getpwent) {
+     $user{$uid} = $name unless $user{$uid};
+ }
+ 
+ while (($name, $pw, $gid) = getgrent) {
+     $group{$gid} = $name unless $group{$gid};
+ }
+ 
+ require "find.pl";
+ 
+ # Traverse desired filesystems
+ 
+ &find($start_dir);
+ 
+ exit;
+ 
+ sub wanted {
+     (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
+     -d _ &&
+     (	$skip_nfs &&
+ 	($dev < 0 || $dev >= 16384) &&
+ 	($prune = 1)
+     )
+     ||
+     -f _ &&
+     (
+ 	($mode & 04000) == 04000
+ 	||
+ 	($mode & 02000) == 02000
+     ) &&
+     &ls;
+ }
+ 
+ sub ls {
+     ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$sizemm,
+       $atime,$mtime,$ctime,$blksize,$blocks) = lstat(_);
+ 
+     $pname = $name;
+ 
+     if (defined $blocks) {
+ 	$blocks = int(($blocks + 1) / 2);
+     }
+     else {
+ 	$blocks = int(($size + 1023) / 1024);
+     }
+ 
+     if    (-f _) { $perms = '-'; }
+     elsif (-d _) { $perms = 'd'; }
+     elsif (-c _) { $perms = 'c'; $sizemm = &sizemm; }
+     elsif (-b _) { $perms = 'b'; $sizemm = &sizemm; }
+     elsif (-p _) { $perms = 'p'; }
+     elsif (-S _) { $perms = 's'; }
+     else         { $perms = 'l'; $pname .= ' -> ' . readlink($_); }
+ 
+     $tmpmode = $mode;
+     $tmp = $rwx[$tmpmode & 7];
+     $tmpmode >>= 3;
+     $tmp = $rwx[$tmpmode & 7] . $tmp;
+     $tmpmode >>= 3;
+     $tmp = $rwx[$tmpmode & 7] . $tmp;
+     substr($tmp,2,1) =~ tr/-x/Ss/ if -u _;
+     substr($tmp,5,1) =~ tr/-x/Ss/ if -g _;
+     substr($tmp,8,1) =~ tr/-x/Tt/ if -k _;
+     $perms .= $tmp;
+ 
+     $user = $user{$uid} || $uid;
+     $group = $group{$gid} || $gid;
+ 
+     ($sec,$min,$hour,$mday,$mon,$year) = localtime($mtime);
+     $moname = $moname[$mon];
+     if (-M _ > 365.25 / 2) {
+ 	$timeyear = '19' . $year;
+     }
+     else {
+ 	$timeyear = sprintf("%02d:%02d", $hour, $min);
+     }
+ 
+     printf "%5lu %4ld %-10s %2d %-8s %-8s %8s %s %2d %5s %s\n",
+ 	    $ino,
+ 		 $blocks,
+ 		      $perms,
+ 			    $nlink,
+ 				$user,
+ 				     $group,
+ 					  $sizemm,
+ 					      $moname,
+ 						 $mday,
+ 						     $timeyear,
+ 							 $pname;
+     1;
+ }
+ 
+ sub sizemm {
+     sprintf("%3d, %3d", ($rdev >> 8) & 255, $rdev & 255);
+ }
+ 
