Заполняем NTFS-раздел диска навсегда и без прав администратора

NTFS logo

NTFS - это продвинутая файловая система, которая используется как основная во всех современных операционных системах Windows. Эта файловая система поддерживает логирование, имеет возможность восстановления данных, расширенные функции безопасности, файловые потоки и многие другие фичи. Но, увы, иногда с богатым функционалом приходят и проблемы, которых не было в ранних файловых системах вроде FAT32.

В NTFS, как вы уже, возможно, знаете, имеется возможность для каждого файла или директории задать атрибуты безопасности: какие пользователи или группы пользователей смогут читать файловый объект, а какие писать; кто не сможет зайти в директорию, а кто сможет; как должны логироваться доступы к объекту и т.д. Вся эта информация часто дублируется: например, в директории C:\Windows\System32 много DLL-файлов, на которые, скорее всего, навешаны схожие атрибуты безопасности: у одних и тех же групп пользователей будут одни и те же возможности доступа к каждому из этих файлов. Конечно, хранить идентификаторы этих групп и пользователей (SID'ы) и дескрипторы безопасности (ACL'ы) накладно для каждого отдельно взятого файла, поэтому разработчики NTFS пришли к умному решению и реализовали его в NTFS v3.0 (Windows 2000): они вынесли всю информацию о безопасности и доступах в отдельный общий файл под названием $Secure, а точнее, в его файловый поток под названием $Secure:$SDS. Этот файл пользователям и администраторам Windows недоступен и является сугубо системным, обслуживается только драйвером NTFS. Без специального ПО доступ к нему получить невозможно.

Как же это всё реализовали? Очень просто! Для каждого файла, вместо хранения данных безопасности в метаинформации самого файла, в атрибут $STANDARD_INFORMATION, который всегда имеется у каждого файла, добавили поле Security Id, которое ссылается на соответствующий дескриптор безопасности в файле $Secure. А файл $Secure, в свою очередь, содержит набор структур, описывающих использующиеся дескрипторы. Таким образом, если вы создаете новый файл с правами доступа по умолчанию (или, например, копируете файл), то его Security Id будет выбран из уже имеющихся структур в файле $Secure. То есть, если такой дескриптор, который вам нужен, уже есть в $Secure, то новый создаваться не будет: в вашем файле просто пропишется Security Id уже имеющегося дескриптора. Если же вы решили изменить дескриптор безопасности у файла, задав нестандартный, ранее не использовавшийся дескриптор, то сначала в $Secure будет создана новая запись с новым Security Id, а в ваш файл будет прописан этот самый новый Security Id.

Здесь уже можно почуствовать подвох. Подумаем, что произойдет, если теперь удалить файл (или заменить его дескриптор безопасности). В идеале, запись, созданная исключительно для вашего файла, должна быть удалена из $Secure, ведь ее ни один файловый объект больше не использует. Но не тут-то было: NTFS не отслеживает, какие именно файлы или директории используют дескриптор безопасности. NTFS даже не подсчитывает, какое количество файлов или директорий ссылается на дескриптор! Может, мы где-то ошиблись? Давайте внимательнее взглянем на структуру записей в $Secure:$SDS:

Смещение Размер Описание
0x00 4 Хэш дескриптора безопасности
0x04 4 Security Id
0x08 8 Смещение этой записи от начала файла
0x10 4 Размер этой записи
0x14 V Дескриптор безопасности
0x14 + V - Выравнивание

Нет, здесь точно нет ничего, что могло бы указать на то, какие файлы и директории используют дескриптор (или хотя бы сколько файловых объектов им пользуется). Эта страница говорит о существовании индексов $Secure:$SDH и $Secure:$SII, только вот и в них нет ничего подобного.

Итак, у файловой системы нет другого выбора, кроме как оставить все дескрипторы безопасности в файле $Secure до лучших времен (вдруг ещё кому пригодятся). И это место будет занято на вашем диске, и его вы не сможете уже освободить. Вы сможете дефрагментировать $MFT или даже $Secure с помощью какой-нибудь утилиты вроде Contig, но, насколько мне известно, не существует ПО, которое позволило бы удалить из $Secure ненужные дескрипторы. Всё-таки, такое ПО есть - это CHKDSK (хотя и требует для запуска прав администратора)! Давайте представим, как это могло бы быть реализовано:

  1. Сначала нужно перечислить ВСЕ файловые объекты на разделе диска и сохранить куда-то все обнаруженные Security Id.
  2. Далее, нужно удалить из $Secure (из всех потоков и индексов) все дескрипторы, которые мы не обнаружили на первом этапе.
  3. Это может привести к тому, что часть дескрипторов съедет, а их Security Id может поменяться. Значит, нужно подправить у затронутых файлов их Security Id, чтобы они ссылались на правильные дескрипторы. Кроме того, нужно подправить смещения у съехавших дескрипторов.

Это колоссальная работа, которую просто и быстро не сделать. Потребуется, скорее всего, отмонтировать раздел диска и делать это, пока никто им больше не пользуется. Словом, сложнореализуемо, особенно для непосвященного пользователя.

Тут сразу возникает вопрос: а может ли злой хэкер забить файл $Secure до такой степени, чтобы занять всё свободное место на жестком диске? Устроив таким хитрым образом DoS системы? Как выясняется, может, да ещё и без прав администратора! Ему будет достаточно прав обычного пользователя!

Давайте же напишем код, который это выполняет. Мы создадим в доступной нам для записи временной директории пустой файл и будем постоянно ему менять дескриптор безопасности. Каждый новый дескриптор мы будем генерировать случайным образом, чтобы он не совпал с уже имеющимися. Это будет приводить к тому, что каждый раз драйвер NTFS будет записывать наши дескрипторы в $Secure, но не будет их удалять, постепенно отъедая всё больше и больше места на диске пользователя. Пользователь заметит, что место на его диске куда-то исчезло, но новых файлов, которые бы занимали это место, не найдёт. Освободить место пользователь также не сможет без переформатирования диска!

Писать будем, конечно, на C++. Начнем с генерации случайного SID'а:

Этот код генерирует случайную строку вида S-1-5-21-X-Y. Это такой типичный вид дескриптора (SID) пользователя или группы пользователей. Она может и не существовать, но NTFS это мало волнует (ведь вдруг вы скопировали файл откуда-то ещё, где такой дескриптор есть в системе?). Теперь сделаем функцию, которая будет переводить эту строку в непосредственно структуру SID и добавлять его атрибуты доступа в структуру EXPLICIT_ACCESS_W:

Теперь осталось написать функцию, которая заполнит массив структур EXPLICIT_ACCESS_W и вернет массив соответствующих им SID'ов. Нам необходимо хранить в памяти все сгенерированные SID'ы до тех пор, пока мы их не добавим в дескриптор безопасности файла.

Теперь напишем пару вспомогательных функций, которые вернут нам путь к временной директории, доступной для записи, и подготовят в ней временный файл:

Далее, нам потребуется функция открытия файла по его имени. К этому файлу мы потом будем добавлять случайные дескрипторы безопасности:

Теперь у нас есть всё необходимое, чтобы перейти к самой мякотке кода, который и делает всё, что мы задумали. Напишем главную функцию программы:

Вот и весь код - всего 130 строк (ссылка на скачивание полного варианта будет в конце статьи).

Попробуем теперь запустить эту программу на тестовой виртуальной машине с Windows 10. Вот что было до запуска программы:
Disk before filling

А вот как выглядит раздел спустя 20 минут после запуска программы:
Disk after filling

Около 3.5 гигабайта свободного места испарились вникуда. Диск забивается достаточно медленно, но это происходит незаметно и, что главное, не требует никаких особенных прав! Программа потребляет порядка 20% от одного ядра процессора. На четырех или восьмиядерном процессоре она будет совершенно не привлекающей внимания. В моём тесте программа была запущена от пользователя с ограниченными правами (не администратора). Давайте теперь с помощью комплекса OS Forensics взглянем на файл $Secure:
OS forensics $Secure:$SDS after disk filling

Для сравнения, вот что было до того, как программа была запущена:
OS forensics $Secure:$SDS before disk filling

Впечатляет! Все 3.5 гигабайта вбухались в $Secure. Как бонус, это может замедлить скорость работы файловой системы, так как количество записей в $Secure значительно увеличилось. Ещё можно взглянуть на вывод программы WinDirStat, которая показывает общий размер файлов и директорий (кстати, удобная штука для удаления старых ненужных занимающих место файлов). Как видно, она говорит о 46.8 Гб занятого места (скриншоты делались после установки OS Forensics, поэтому ещё часть места была занята этим ПО):
WinDirStat after disk filling

В то время, как Windows считает, что на самом деле занято 49 Гб:
Used disk space after filling

А вот как выглядят атрибуты безопасности нашего временного файла:
Temp file security descriptor

В заключение подумаем, что произойдет, если вдруг пользователь попадется продвинутый и попытается разобраться, куда же делось его свободное место. Он может попробовать изучить журнал NTFS, открыв его, например, с помощью утилиты NTFS Journal Viewer от Orion Forensics.
NTFS journal after disk filling

Увы, но и тут его ждет разочарование. Есть всего три записи, не вызывающие подозрения, при работе с временным файлом. Никаких записей о тысячах изменений дескриптора безопасности файла нет, есть всего парочка. Их реально найти в огромном количестве прочих записей, только зная имя файла заранее. В противном случае это поиск иголки в стоге сена.

Итак, что мы имеем? NTFS пытались оптимизировать, но допустили недоработку, которая в итоге позволяет осуществить DoS системы (медленный, но необратимый) даже от обычного пользователя.

Скачать исходники и exe-файл: NTFS fucker (пароль на архив kaimi).

Заполняем NTFS-раздел диска навсегда и без прав администратора: 2 комментария

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *