Сок­рытие про­цес­сов — клас­сичес­кая задача для мал­вари. Обыч­но это тер­ритория рут­китов: LKM-модули, перех­ват syscall-таб­лицы, под­мена обра­бот­чиков в /proc. Все это тре­бует заг­рузки кода в ядро, ком­пиляции под кон­крет­ную вер­сию и оставля­ет замет­ные сле­ды. Но есть спо­соб про­ще. Никаких модулей ядра и ком­пиляции, толь­ко один штат­ный вызов mount с фла­гом MS_BIND.

В этой статье мы:

  • раз­берем тех­нику сок­рытия про­цес­сов через bind mount;
  • вос­про­изве­дем ее руками и пос­мотрим, что про­исхо­дит на уров­не syscall, через strace;
  • нас­тро­им пра­вило auditd для монито­рин­га в реаль­ном вре­мени;
  • на­пишем скрипт на Python для обна­руже­ния и рас­кры­тия скры­тых про­цес­сов.

Идея осно­вана на стать­ях Сте­фана Бер­гера и Хэ­ла Померан­ца.

warning

Статья име­ет озна­коми­тель­ный харак­тер и пред­назна­чена для спе­циалис­тов по безопас­ности, про­водя­щих тес­тирова­ние в рам­ках кон­трак­та. Автор и редак­ция не несут ответс­твен­ности за любой вред, при­чинен­ный с при­мене­нием изло­жен­ной информа­ции. Рас­простра­нение вре­донос­ных прог­рамм, наруше­ние работы сис­тем и наруше­ние тай­ны перепис­ки прес­леду­ются по закону.

 

Как работает техника

Как мал­варь пря­чет про­цес­сы? Мы час­то исполь­зуем ps, что­бы пос­мотреть, какие про­цес­сы запуще­ны в сис­теме. Если заг­лянуть чуть глуб­же, то мож­но узнать, что эта ути­лита смот­рит информа­цию о про­цес­сах в /proc/:

root@0bc5a04d0a00:/rev# strace ps
...
openat(AT_FDCWD, "/proc", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/uptime", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(4, "75062.72 585321.72\n", 1024) = 19
close(4) = 0
mmap(NULL, 626688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7bc2598f6000
getdents64(3, 0x57052d78eaf0 /* 67 entries */, 32768) = 2008
newfstatat(AT_FDCWD, "/proc/1", {st_mode=S_IFDIR|0555, st_size=0, ...}, 0) = 0
openat(AT_FDCWD, "/proc/1/stat", O_RDONLY) = 4
read(4, "1 (bash) S 0 1 1 34816 169 41945"..., 1024) = 329
close(4) = 0
openat(AT_FDCWD, "/proc/1/status", O_RDONLY) = 4
read(4, "Name:\tbash\nUmask:\t0022\nState:\tS "..., 1024) = 1024
read(4, "0000,00000000,00000000,00000000,"..., 1024) = 417
close(4) = 0
openat(AT_FDCWD, "/proc/1/environ", O_RDONLY) = 4
read(4, "PATH=/usr/local/sbin:/usr/local/"..., 131072) = 110
read(4, "", 130962) = 0
close(4) = 0
openat(AT_FDCWD, "/proc/1/cmdline", O_RDONLY) = 4
read(4, "bash\0", 131072) = 5
read(4, "", 131067) = 0
close(4) = 0
openat(AT_FDCWD, "/proc/1/ctty", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/proc/tty/drivers", O_RDONLY) = 4
read(4, "/dev/tty /dev/tty "..., 9999) = 677
close(4) = 0
...

В Linux procfs — вир­туаль­ная фай­ловая сис­тема, которая пре­дос­тавля­ет дос­туп к информа­ции ядра через обыч­ные фай­ловые опе­рации. Каж­дый про­цесс пред­став­лен дирек­тори­ей /proc/[PID], внут­ри которой лежат фай­лы: stat, cmdline, comm, environ, fd/ и дру­гие. Имен­но их чита­ет ps, top, htop и любой дру­гой инс­тру­мент монито­рин­га.

Глав­ный герой сегод­няшней тех­ники — сис­темный вызов mount:

mount(source, target, filesystemtype, mountflags, data)

Это syscall для мон­тирова­ния фай­ловой сис­темы. Для bind mount исполь­зует­ся флаг MS_BIND (0x1000).

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

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

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

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

    Подписаться

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