Tuesday, May 11, 2010

Hacking XScreensaver to take photos of intruders

Once upon a time, I returned to my computer to see the message "11 Failed Login Attempts" when logging in.  Needless to say, this was unnerving.  To catch the culprit I successfully recompiled XScreensaver to take pictures of anyone getting my password wrong.  Here's how I did it.

Disclaimer: This uses an extremely cheap hack. In fact, I wouldn't be surprised if it introduces subtle security vulnerabilities, but I don't know of any.  (EDIT: it turns out that even though the system() command is given an absolute path, the shell environment can be modified to abuse it.  Since xscreensaver is a setuid program, this could lead to elevation of privilege attacks.)  Use at your own risk.

When I originally did this I used Arch Linux, but since then I've ported it to Ubuntu and it should work on any *nix system with tweaks.  This won't work for Windows, unless you can get xscreensaver and mplayer working in cygwin (good luck!).

First get your webcam setup and /dev/video0 working. You can test this with a program like cheese.  Install mplayer. Then

$mplayer tv:// -tv driver=v4l2:device=/dev/vi
deo0:width=800:height=600:outfmt=rgb24 -frames 4 -vo jpeg:outdir="/data/berkeley/failed-login-pics/`date +"%Y-%B-%d"`/`date +"%H.%M.%S"`" > /dev/null 2> /data/berkeley/failed-login-pics/mplayer-error-log

will take four pictures using /dev/video0 and v4l2 drivers and save it to /data/berkeley/failed-login-pics/date/time.  Obviously you'll want to change the paths for your system.  You may need to adjust other settings as well.  Get this working before continuing.  Place this command in a script of your choice somewhere in your system.

Here's how to make xscreensaver run this command when someone guesses your password wrong:

Download the xscreensaver source and modify xscreensaver-version/driver/lock.c as follows (I've done so much other stuff to this file I can't really provide a patch or diff):

1. Insert this line at the top, under the other standard includes

#include <stdlib.h>

2. Add a function int takePicture() as follows near the top somewhere. Use the command that worked for your computer above in the system("...") call! Be sure to escape every " with \. Don't ignore the mkdir command. Also note that there are actually only two lines in the body of the function.

int takePicture() {
     system("/path/to/script");
}

3. Somewhere around line 2040 you'll see code that looks like:

if (si->unlock_state == ul_fail && /* failed with caps lock on */
si->pw_data && si->pw_data->caps_p)
     s = "Authentication failed! (caps lock)";
else if (si->unlock_state == ul_fail) /* failed without caps lock */
     s = "Authentication failed!";

change it to this: (and feel free to customize the messages)

if (si->unlock_state == ul_fail && /* failed with caps lock on */
si->pw_data && si->pw_data->caps_p)
{
     takePicture();
     s = "Authentication FAIL!\n (caps lock is on)";
}
else if (si->unlock_state == ul_fail) /* failed without caps lock */
{
     takePicture();
     s = "Authentication FAIL!\n (this will be reported)";
}

4. While you're at it, I highly recommend changing the xscreensaver pictures/icons and replacing them with whatever you want. I used arch linux icons. You'll find them in one of the source directories.

5. If you're crafty you can also modify some of the other visual elements in the login screen. For example, at somewhere around line 250 you can modify the strings that contain "xscreensaver blahblahblah" and the hostname to whatever you want. Be careful! If you write it wrong or don't use strdup you could create segmentation faults when xscreensaver frees up the window resources causing xscreensaver to crash. If you do this then pressing the ESC button will bypass the login window.  Test your modifications throughly. 


Install can be a bit tricky. First remove xscreensaver and gnome screensaver from any package managers, eg.

$sudo apt-get remove xscreensaver
$sudo apt-get remove gnome-screensaver

OR

$sudo pacman -R xscreensaver
$sudo pacman -R gnome-screensaver

Then execute

$./configure --prefix=/usr
$make
$sudo make install

To test it out, do the following

$pkill xscreensaver   (or $killall xscreensaver)
$xscreensaver &
$xscreensaver-command -lock

When you test, make sure that

1) STDOUT and STDERR of mplayer and mkdir are suppressed or logged (you'll know if it's not)
2) You can't bypass the login screen by pressing ESC, waiting, overflowing some buffer, or otherwise causing a segfault.

For a GUI configuration editor, try

$xscreensaver-demo

Finally, make sure that xscreensaver is run at startup with your desktop manager so it actually turns on.

Have fun.

No comments:

Post a Comment