- PVSM.RU - https://www.pvsm.ru -

Анти-руткит для Userland-RootKit Azazel «на коленке»

Вот шикарная новость от пользователя ValdikSS [1]Новый Userland-RootKit Azazel [2]. Позволю себе процитировать первый абзац:

Возможно вы слышали про руткиты Jynx и Jynx2. Это так называемые userland-руткиты, они используют возможность переменной LD_PRELOAD, которая позволяет подгружать любые библиотеки до того, как будет запущена программа. Они уже относительно старые, но все еще хорошо работают.
2 дня назад, Github-пользователь Chokepoint выложил rootkit Azazel. Он основан на исходном коде Jynx и имеет много новых фич:

Антиотладочные механизмы
Скрытие от unhide, lsof, ps, ldd
Скрытие файлов и директорий
Скрытие удаленных подключений
Скрытие процессов
Скрытие логинов
Скрытие от локального сниффинга трафика через PCAP
2 бекдора с полноценными шеллами (с PTY):
— Crypthook accept()-бекдор
— Обычный accept()-бекдор
PAM-бекдор для аутентификации под любым пользователем
Очистка логов utmp/wtmp для PTY
Обфускация строк скомпилированной библиотеки через xor.

Таким образом, в рутките используется штатная возможность подгружать через LD_PRELOAD любую библиотеку. Встаёт вопрос, а можно ли это как-то контролировать?

Чтобы не быть многословным, сразу представлю простое решение для ядра Linux, которое, перехватывая функцию execve (а точнее — sys_execve [3]), сканирует параметры списка переменных окружения (известного как envp) на наличие в них определённой строки, а именно той самой LD_PRELOAD.

Итак, решение оформлено в виде модуля ядра. Перехват функции основывается на методах, описанных ранее в статьях:

Для перехвата функции sys_execve используется следующий [6] код:

DECLARE_KHOOK(sys_execve);
long khook_sys_execve( const char __user * file,
		       const char __user * const __user * argv,
		       const char __user * const __user * envp )
{
	long result;

	KHOOK_USAGE_INC(sys_execve);

	scan_env_for((void *)file, (void *)envp, env_token);
	result = KHOOK_ORIGIN(sys_execve, file, argv, envp);

	KHOOK_USAGE_DEC(sys_execve);

	return result;
}

Непосредственно перед осущестлением оригинального вызова перехваченной функции sys_execve выполняется поиск соответствия переменных окружения заданной строке env_token. Это делает простая функция scan_env_for [7]:

void scan_env_for(char * file, char * envp[], const char * token)
{
	int i;

	char * string;
	char * string_ptr;

	if (!envp || !token)
		return;

	string = kmalloc(MAX_ARG_STRLEN + 1, GFP_KERNEL);
	if (!string) {
		debug("Can't get memory for the environ stringn");
		return;
	}

	for (i = 0; i < MAX_ARG_STRINGS; i++) {
		if (get_user(string_ptr, envp + i)) {
			debug("Can't get user pointer valuen");
			goto out_kfree;
		}

		if (string_ptr == NULL)
			goto out_kfree;

		if (strncpy_from_user(string, string_ptr, MAX_ARG_STRLEN) == -EFAULT) {
			debug("Can't get user stringn");
			goto out_kfree;
		}

		string[MAX_ARG_STRLEN] = 0;

		if (strncmp(string, token, strlen(token)) == 0) {
			char * filename;

			filename = kmalloc(PATH_MAX + 1, GFP_KERNEL);
			if (filename) {
				strncpy_from_user(filename, file, PATH_MAX + 1);
				filename[PATH_MAX] = 0;
			}

			debug("Attention, task "%s" trying to execute "%s" with "%s"n", 
				current->comm, filename ? filename : "(unknown)", string);

			kfree(filename);

			goto out_kfree;
		}
	}

out_kfree:
	kfree(string);
}

Как видно, при её запуске выделяется память и сканируются все возможные строковые элементы переменных окружения. В завершении сканирования, память соответственно освобождается. В случае, если требуемая строка была обнаружена в журнал ядра будет выведено предупреждение.

Для проверки работоспособности модуля, после его сборки, можно выпонить следующее:

$ sudo insmod envscan.ko env_token="LD_PRELOAD="
$ dmesg | grep envscan
  [37713.809903] [envscan] Symbol "module_free" found @ ffffffff810bdcd0
  [37713.810190] [envscan] Symbol "module_alloc" found @ ffffffff810407e0
  [37713.810523] [envscan] Symbol "sort_extable" found @ ffffffff81048a90
  [37713.810524] [envscan] Hunting for "LD_PRELOAD="
  [37713.811798] [envscan] Symbol "sys_execve" found @ ffffffff8119ba30
$ LD_PRELOAD=/lib/ld-linux.so.2 ls
  [37743.786499] [envscan] Attention, task "bash" trying to execute "/bin/ls" with "LD_PRELOAD=/lib/ld-linux.so.2"

Таким образом, можно сказать, что для параноидально настроенных пользователей есть [8] решение, позволяющее, при желании, защититься от неприятностей, связнанных с возможностями LD_PRELOAD.

Для тех, кто настроен менее панически данный материал может служит источником информации о том, как работать с ядром, а именно перехватывать его функции и модифицировать поведение системы.

Код модуля доступен на github [8].

Автор: milabs

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/news/55156

Ссылки в тексте:

[1] ValdikSS: http://habrahabr.ru/users/valdikss/

[2] Новый Userland-RootKit Azazel: http://habrahabr.ru/post/212769/

[3] sys_execve: http://lxr.free-electrons.com/source/fs/exec.c?v=3.8#L1673

[4] Управляемый PageFault в ядре Linux: http://habrahabr.ru/post/196952/

[5] Перехват функций ядра Linux с использованием исключений (kprobes своими руками): http://habrahabr.ru/post/206778/

[6] следующий: https://github.com/milabs/kmod_hooking/blob/hook-execve/module-init.c#L261

[7] scan_env_for: https://github.com/milabs/kmod_hooking/blob/hook-execve/module-init.c#L203

[8] есть: https://github.com/milabs/kmod_hooking/tree/hook-execve

[9] Источник: http://habrahabr.ru/post/212825/