Подрыв флага выполнения в системах Linux. Почему это возможно?

23

Читая это , я обнаружил следующий эксплойт:

% cp /usr/bin/id ~
% chmod -x ~/id
% ls -al ~/id
-rw-r--r-- 1 edd edd 22020 2012-08-01 15:06 /home/edd/id
% ~/id
zsh: permission denied: /home/edd/id
% /lib/ld-linux.so.2 ~/id
uid=1001(edd) gid=1001(edd) groups=1001(edd),1002(wheel)

Этот фрагмент показывает, что мы можем тривиально обойти разрешения на выполнение файловой системы как обычный непривилегированный пользователь. Я запустил это на Ubuntu 12.04.

Хотя загрузчик Linux является общим объектом в соответствии с файлом (1), он также имеет точку входа, которая позволяет выполнять его напрямую. При выполнении таким способом загрузчик Linux действует как интерпретатор для двоичных файлов ELF.

Однако на моем компьютере с OpenBSD этот эксплойт не эффективен, поскольку вы не можете запускать загрузчик как программу. На странице руководства OpenBSD написано: «ld.so сам по себе является общим объектом, который изначально загружается ядром».

Попробуйте это на Solaris 9, и вы получите ошибку. Я не уверен, что происходит в другом месте.

Поэтому мои вопросы:

  • Почему загрузчик Linux (при непосредственном выполнении) не проверяет атрибуты файловой системы перед интерпретацией двоичного файла ELF?
  • Зачем реализовывать механизм, предназначенный для запрета выполнения файлов, если он так тривиально обходится? Я что-то пропустил?
Эдд Барретт
источник
1
Нет веской причины, но если вам когда-нибудь удавалось удалить свою систему libc(я однажды делал это, обновляя коробку Arch), вы будете благодарны за эту небольшую причуду.
new123456
1
@ new123456 о боже, канал IRC после этого обновления был болезненным, чтобы войти.
Роб
Это загрузчик , а не компоновщик.
Стоп Harm Моника

Ответы:

33

Цель executeразрешения - не предотвращать исполнение в целом . (1) сообщать программам, какие файлы должны быть выполнены, и (2) предотвращать выполнение в качестве привилегированного пользователя , когда указан бит setuid (и т. Д.).

Взлом линкера - это не столько эксплойт, сколько кажется. Вы можете выполнить любой неисполняемый файл, который у вас есть права на чтение, еще проще:

$ cp unexecutable_file ~/runme
$ chmod +x ~/runme
$ ~/runme

Смотрите это обсуждение на форуме Arch Linux .

В итоге:

Маркировка файлов, которые должны быть выполнены

Когда вы пишете сценарий оболочки, вы можете пометить его как исполняемый с помощью chmod +x. Это намекает вашей оболочке на то, что вы хотите, чтобы она была исполняемой (в противном случае оболочка знает, что это просто еще один простой текстовый файл). Оболочка может затем показать его на вкладке завершения при вводе ./Tab.

Аналогично: something.dкаталоги (например init.d) содержат сценарии запуска или командной оболочки, которые обычно выполняются автоматически демонами. Возможно, вы захотите поместить комментарий или файл README в каталог в виде простого текстового файла. Или вы можете временно отключить один из сценариев. Вы можете сделать это, очистив бит выполнения для этого конкретного файла. Это говорит демону пропустить его.

Предотвращение привилегированного исполнения

Этот setuidбит означает, что когда вы выполняете файл, он исполняется от имени указанного пользователя (например, root).

Сообщение на форуме объясняет это хорошо:

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

Механическая улитка
источник
2
Спасибо - я упустил из виду тот факт, что пользователь может скопировать любой файл, который он может прочитать, и, следовательно, выбрать произвольные разрешения.
Эдд Барретт
как насчет файлов с разрешением на выполнение, но без разрешения на чтение?
Ли Райан
@LieRyan Как насчет них?
Восстановить Монику
@BrendanLong: Вы, очевидно, не можете скопировать их, поэтому вы не можете изменить их разрешения. (Но почему вы хотите этого, я не могу сказать - единственное, что вы можете сделать с копией, так это сбросить разрешение на выполнение)
MSalters
9

Если у вас есть доступ для чтения к файлу, вы всегда можете сделать его копию.

Если вы можете сделать личную копию, вы всегда можете пометить эту копию как исполняемую.

Это не объясняет поведение ld-linux, но указывает на то, что это может быть не очень полезной лазейкой в ​​безопасности.

Если вы хотите более строгой безопасности, рассмотрите SELinux

RedGrittyBrick
источник
Это очень верно.
Эдд Барретт
Это был просто концептуальный вопрос. Я полагаю, вы могли бы установить nonexec и для файловых систем.
Эдд Барретт
2

Если взглянуть на вопрос немного иначе: как говорит Mechanical Snail, разрешение на выполнение файла не предназначено для предотвращения выполнения. Тем не менее, опция файловой системы «noexec» действительно предотвращает выполнение, и ее не так легко обойти (не поддерживается всеми файловыми системами, но, безусловно, наиболее популярными в Linux). Если администратор хочет запретить пользователям запускать собственные программы, он может указать параметр noexec в домашних каталогах и каталогах tmp, а также в любых других, где пользователи могут создавать файлы.

$ mount -o noexec /dev/sdd1 /test
$ cd /test
$ cp /usr/bin/id .
$ ./id
-bash: ./id: Permission denied

По-видимому, раньше можно было обойти параметр noexec, используя прием загрузки, упомянутый в вопросе, но это было исправлено в ядре несколько версий назад.

От http://linux.die.net/man/8/mount :

поехес

Не разрешайте прямое выполнение каких-либо двоичных файлов в смонтированной файловой системе. (До недавнего времени можно было запускать двоичные файлы в любом случае с помощью команды, подобной /lib/ld*.so / mnt / binary. Этот прием не удался с Linux 2.4.25 / 2.6.0.)

Рэнди Оррисон
источник