Обнаружение chroot-тюрьмы изнутри
Вопрос
Как можно определить нахождение в chroot-тюрьме без привилегий root?Предположим, что это стандартная система BSD или Linux.Лучшее, что я придумал, — это посмотреть на значение индексного дескриптора «/» и оценить, является ли оно достаточно низким, но мне нужен более точный метод обнаружения.
[edit 20080916 142430 EST]
Простого осмотра файловой системы недостаточно, поскольку несложно продублировать такие вещи, как /boot и /dev, чтобы обмануть заключенного пользователя.
[edit 20080916 142950 EST]
Для систем Linux проверка неожиданных значений в /proc является разумной, но как насчет систем, которые вообще не поддерживают /proc?
Решение
Индексный дескриптор / всегда будет равен 2, если это корневой каталог файловой системы, но вы можете использовать chroot внутри всей файловой системы.Если это просто chroot (а не какая-то другая виртуализация), вы можете запустить mount и сравнить смонтированные файловые системы с тем, что вы видите.Убедитесь, что каждая точка монтирования имеет индексный дескриптор 2.
Другие советы
Если вы не находитесь в chroot, индекс / всегда будет равен 2.Вы можете проверить это, используя
stat -c %i /
или
ls -id /
Интересно, но давайте попробуем найти путь к каталогу chroot.Просить stat
на каком устройстве/находится:
stat -c %04D /
Первый байт является старшим для устройства, а второй байт — младшим.Например, 0802 означает старший 8, второстепенный 1.Если вы проверите /dev, вы увидите, что это устройство — /dev/sda2.Если вы являетесь пользователем root, вы можете напрямую создать соответствующее устройство в своем chroot:
mknode /tmp/root_dev b 8 1
Теперь давайте найдем индексный дескриптор, связанный с нашим chroot.debugfs позволяет отображать содержимое файлов, используя номера индексных дескрипторов.Например, ls -id /
вернул 923960:
sudo debugfs /tmp/root_dev -R 'ls <923960>'
923960 (12) . 915821 (32) .. 5636100 (12) var
5636319 (12) lib 5636322 (12) usr 5636345 (12) tmp
5636346 (12) sys 5636347 (12) sbin 5636348 (12) run
5636349 (12) root 5636350 (12) proc 5636351 (12) mnt
5636352 (12) home 5636353 (12) dev 5636354 (12) boot
5636355 (12) bin 5636356 (12) etc 5638152 (16) selinux
5769366 (12) srv 5769367 (12) opt 5769375 (3832) media
Интересная информация находится в inode ..
вход:915821.Могу спросить его содержание:
sudo debugfs /tmp/root_dev -R 'ls <915821>'
915821 (12) . 2 (12) .. 923960 (20) debian-jail
923961 (4052) other-jail
Каталог называется debian-jail
имеет индекс 923960.Итак, последний компонент моего chroot-каталога: debian-jail
.Давайте теперь посмотрим родительский каталог (inode 2):
sudo debugfs /tmp/root_dev -R 'ls <2>'
2 (12) . 2 (12) .. 11 (20) lost+found 1046529 (12) home
130817 (12) etc 784897 (16) media 3603 (20) initrd.img
261633 (12) var 654081 (12) usr 392449 (12) sys 392450 (12) lib
784898 (12) root 915715 (12) sbin 1046530 (12) tmp
1046531 (12) bin 784899 (12) dev 392451 (12) mnt
915716 (12) run 12 (12) proc 1046532 (12) boot 13 (16) lib64
784945 (12) srv 915821 (12) opt 3604 (3796) vmlinuz
Каталог называется opt
имеет индексный дескриптор 915821, а индексный дескриптор 2 является корнем файловой системы.Итак, мой каталог chroot /opt/debian-jail
.Конечно, /dev/sda1
может быть смонтирован в другой файловой системе.Вам нужно это проверить (используйте lsof или напрямую выбирая информацию /proc
).
В Linux с правами root проверьте, является ли корневой каталог процесса инициализации вашим корневым каталогом.Хотя /proc/1/root
всегда является символической ссылкой на /
, следуя за ним, вы попадаете в «главный» корневой каталог (при условии, что процесс инициализации не изолирован от chroot, но это почти никогда не делается).Если /proc
не смонтирован, можете быть уверены, что вы находитесь в chroot.
[ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]
# With ash/bash/ksh/zsh
! [ -x /proc/1/root/. ] || [ /proc/1/root/. -ef / ]
Это точнее, чем смотря на /proc/1/exe
потому что за пределами chroot все может быть по-другому, если init
был обновлен с момента последней загрузки или если chroot находится в основной корневой файловой системе и init
жестко связан в нем.
Если у вас нет root-прав, вы можете посмотреть /proc/1/mountinfo
и /proc/$$/mountinfo
(кратко описано в filesystems/proc.txt
в документации ядра Linux).Этот файл доступен для чтения всем и содержит много информации о каждой точке монтирования с точки зрения процесса на файловую систему.Пути в этом файле ограничены chroot, влияющим на процесс чтения, если таковой имеется.Если процесс чтения /proc/1/mountinfo
находится в файловой системе, отличной от глобального корня (при условии, что корень pid 1 является глобальным корнем), тогда нет записи для /
появляется в /proc/1/mountinfo
.Если процесс чтения /proc/1/mountinfo
помещается в каталог глобальной корневой файловой системы, затем появляется запись для /
появляется в /proc/1/mountinfo
, но с другим идентификатором монтирования.Кстати, корневое поле ($4
) указывает, где находится chroot в его основной файловой системе.Опять же, это специфично для Linux.
[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]
Весь смысл в том, чтобы предотвратить подобные вещи.Если ваш код должен запускаться в chroot, установите для него флаг при запуске.Если вы взламываете, взломайте:проверьте несколько общих вещей в известных местах, посчитайте файлы в /etc, что-нибудь в /dev.
В системах BSD (проверьте с помощью uname -a) proc всегда должен присутствовать.Проверьте, соответствует ли пара dev/inode /proc/1/exe (используйте stat по этому пути, она будет следовать не по символической ссылке по тексту, а по базовому хуку) /sbin/init.
Проверка корня для индексного дескриптора № 2 также полезна.
В большинстве других систем пользователь root может узнать об этом гораздо быстрее, попробовав трюк взлома fchdir.Если он куда-то пойдет, вы окажетесь в тюрьме chroot.
Я думаю, это зависит от того, почему вы можете оказаться в chroot и были ли предприняты какие-либо усилия для его маскировки.
Я бы проверил /proc, эти файлы автоматически генерируются системными информационными файлами.Ядро заполнит их в корневой файловой системе, но возможно, что они не существуют в файловой системе chroot.
Если /proc корневой файловой системы привязан к /proc в chroot, то вполне вероятно, что между этой информацией и средой chroot существуют некоторые несоответствия.Например, проверьте /proc/mounts.
Аналогично проверьте /sys.
Если вы вошли в chroot с помощью schroot, вы можете проверить значение $debian_chroot.
Мне нужна была та же информация для тюрьмы, работающей на FreeBSD (поскольку Ansible, похоже, не обнаруживает этот сценарий).
В дистрибутиве FreeNAS FreeBSD 11: /proc
не установлен на хосте, но находится в тюрьме.Верно ли это и для обычной FreeBSD, я точно не знаю, но процфс:Ушел, но не забыт кажется, предполагает, что это так.В любом случае, вы, вероятно, не захотите пытаться установить его только для определения статуса тюрьмы, и поэтому я не уверен, что его можно использовать в качестве надежного предсказателя пребывания в тюрьме.
Я также исключил использование stat on /
как и во FreeNAS, все джейлы имеют собственную файловую систему (т. набор данных ZFS) и, следовательно, /
узел на хосте и в тюрьме имеют индекс 4.Я ожидаю, что это обычное явление для FreeBSD 11 в целом.
Итак, подход, который я выбрал, заключался в использовании прокстат на пид 0.
[root@host ~]# procstat 0
PID PPID PGID SID TSID THR LOGIN WCHAN EMUL COMM
0 0 0 0 0 1234 - swapin - kernel
[root@host ~]# echo $?
0
[root@host ~]# jexec guest tcsh
root@guest:/ # procstat 0
procstat: sysctl(kern.proc): No such process
procstat: procstat_getprocs()
root@guest:/ # echo $?
1
Здесь я делаю предположение, что pid 0 всегда будет ядром на хосте, а внутри клетки не будет pid 0.