avva: (Default)
[personal profile] avva
Эта запись будет интересна, боюсь, только тем, кто разбирается в Юниксе и особенно в Линуксе.

На израильской линуксовской рассылке кто-то спросил помощь зала в решении проблемы. Проблема следующая. У меня есть процесс, который бежит с администраторскими привилегиями (как root, короче). Мне нужно сделать так, чтобы с помощью обычных ps/top этот факт нельзя было обнаружить: чтобы они показывали его бегущим под другим юзером. При этом можно предположить, что у меня есть root-доступ к этой системе, но я ограничен в некоторых своих действиях. Я не могу менять ядро, загружать новые модули в ядро, а также менять стандартные запускаемые файлы ps/top и стандартные библиотеки. Вопрос: что ещё я могу сделать?

Проблема сформулирована достаточно расплывчато, т.к. неясно в частности, кого нужно обмануть: человека, который запускает эти ps/top, или какой-нибудь скрипт. Но оставим эту расплывчатость, как она есть, и попытаемся придумать какие-нибудь методы. Способ “сменить PATH данному юзеру, чтобы запускались не стандартные ps/top, а другие” тоже отметём, как слишком тривиальный/очевидный/легкообнаруживаемый. Что остаётся?

Я придумал три штуки:

1) это достаточно серьёзное извращение ;), но можно сменить имя рута на данной системе, т.е. назвать uid 0 другим именем вместо root. Неискушённого юзера это вполне может обмануть. Недостаток: возможно, ломаем кучу скриптов/программ, которые полагаются на то, что uid 0 = root. В принципе, строго говоря, они все дефективны, если на это полагаются, но на практике, думаю, они на каждом шагу, в том числе среди скриптов, управляющих процессом загрузки системы.

Добавить ещё одну запись в /etc/passwd с uid 0 и другим именем не помогает, т.к. ps/top пользуются getpwuid(), а она берёт первую подходящую строку. Заставить все программы видеть одного юзера с uid 0, а ps/top другого, таким способом не выйдет.

2) ставим LD_PRELOAD: либо для данного юзера в его стартовых скриптах (рассчитывая на то, что он в этом не разбирается), либо общесистемно в /etc. В LD_PRELOAD ставим имя небольшой библиотеки, которая перекидывает на себя вызовы функции open(). ps/top читают информацию о процессах из "/proc/[pid]/stat" ; значит, наша фальшивая open() будет проверять, не пытаются ли открыть этот файл. Если пытаются, она копирует его в другое место (в /tmp например), меняя при этом нужное поле в нём, потом открывает его вместо настоящего и возвращает этот дескриптор. Тогда ps/top прочитают как миленькие из этого дескриптора и закроют его.

3) программа, бегущая как root, во время своей работы вызывает mount() и ставит поверх /proc/[my pid]/ копию tmpfs. При этом она держит открытый дескриптор старой директории. Раз в секунду она копирует все файлы и симлинки из старой директории в tmpfs, изменяя при этом файл stat, и маскируя свой настоящий uid. Всё.

Третий способ мне особенно нравится, т.к. не нужно менять никаких настроек юзера, которого обманываем. Не знаю, используют ли этот способ реально какие-нибудь руткиты.

В общем, это всё, что было предложено (идею номер 2) независимо предложили другие участники тоже). Да, есть ещё такая штука, как capabilities, когда программа может бежать не как root, но иметь некоторые рутовские привилегии. Но вроде бы в текущих версиях Линукса она работает плохо, куча багов, и поломаны user-mode утилиты для неё.

Есть ещё что-то существенное, интересно?

Date: 2004-09-01 05:22 pm (UTC)
From: [identity profile] bish0nen.livejournal.com
3) работать просто не будет. Все файлы под /proc/$$/ они, в общем-то, не простые файлы, а золотые - это куски кода ядра экспортируются в file system namespace файлами, например:

jism pts/2 ~/src 10053:<0>* cp /proc/$$/mem /tmp/mem
cp: reading `/proc/21677/mem': No such process


Ну итд. Часть из них, впрочем, скопируется, но подставу заметить легко: в procfs у них длина - нуль, а у копии (/proc/$$/stat, например) будет ненулевая. Единственный способ сделать что-то подобное 3) - это написать ядерный модуль со своей overlay file system, (однако не во всех версиях Линукса файловые системы stackable) и смонтировать её поверх procfs, который будет смотреть, на какой файл из procfs пришёл запрос, и либо подделать ответ либо отправить запрос по стеку дальше на обработку. Очень громоздко и легко обнаруживается.

Самый эффективный способ - если программа имеет права суперпользователя - это залезть в /dev/kmem и поковырять таблицу процессов. Если securelevel ядра не равен нулю, то и это бесполезно.

Date: 2004-09-01 05:40 pm (UTC)
From: [identity profile] avva.livejournal.com
Да нет, почему же не сработает? Ясно, что копия будет не идеальная; но задача стоит - обмануть ps и top, а они ничего, кроме stat, не читают вообще. Я предложил копировать всё остальное (mem и подобные ему файлы не стоит и пытаться, ясно) просто чтобы приятнее выглядело. Конечно, если юзер достаточно умён, чтобы знать о /proc, знать об этой директории, сделать в ней ls -l и понять, что ненулевой размер stat подозрителен - тогда да. Но таких мало.

А ковыряние таблицы процессов - это зачем? Того же можно добиться вполне стандартными вызовамы setreuid() и сотоварищи. Какая разница, кто изменит current->euid, функция sys_setreuid() или прямой доступ к /dev/kmem?

January 2026

S M T W T F S
    1 2 3
45678910
11121314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 4th, 2026 07:59 pm
Powered by Dreamwidth Studios