Вступление.
Часто при проектировании логической структуры Active Directory возникает вопрос, какую модель выбрать, чтобы она была более безопасной, более надежной и в тоже время более выгодной и управляемой.
Не секрет, что отдельный домен в лесу не является изолированной единицей и что полномочный администратор из корневого домена леса может получить доступ к любым единицам данных в лесу. Также любой администратор домена не из корневого домена леса может получить доступ к другим доменам. Это описано во многих руководствах Microsoft. Вот отрывок из руководства по разработке архитектуры службы каталога (Designing and Deploying Directory and Security Services):
Because a domain is not a security boundary, it is possible for a malicious service administrator, such as a member of the Domain Admins group, to use nonstandard tools and procedures to gain full access to any domain in the forest or to any computer in the forest. For example, service administrators in a nonroot domain can make themselves members of the Enterprise Admins or Schema Admins group.
Я достаточно долго пытался найти такие утилиты в Интернете, но так и не нашел.
Далее попробуем обсудить различные логические модели доменов/лесов и рассмотрим получение полномочий в этих самых доменах и лесах.
Получение полномочий.
Есть определенный набор утилит, который позволяет мигрировать учетные записи участников безопасности между доменами/лесами с сохранением SID исходного домена в SIDHistory объекта целевого домена. Вот некоторые из них: ADMT, sidhist.vbs, sidewalk.exe. Две последние утилиты из набора Support Tools. Как же работают эти утилиты/скрипты? Все они используют функцию DsAddSidHistory из библиотеки Ntdsapi.dll. Функция документированная. Использование ее достаточно простое, как-то так (код на Delphi):
if DsBind('\\targetdc.target.com','target.com', @hDs) = 0 then
if DsAddSidHistory(hDs, 0, 'source.com', 'SampleUser04', nil, nil, 'target.com', 'SampleUser03') = 0 then
Функция описана здесь - http://msdn.microsoft.com/en-us/library/ms675918(VS.85).aspx
Но выполнение данной функции налагает определенные ограничения, в частности должны быть выполнены следующие условия:
- административные права в домене источнике;
- права на добавление SidHistory в целевом домене;
- на PDC в исходном домене в реестре должен быть ключ TCPIPClientSupport:DWORD=1;
- должна быть создана локальная группа в целевом домене – $$$;
- в целевом домене должен быть включен аудит управления учетными записями (Account Management – Success/Failure).
Миграция SID допускается между учетными записями с well-known rid учетными записями (это записи у которых относительный идентификатор во всех доменах одинаковый, но sid домена отличается), например Domain Admins (S-15-21-SidДомена-512). Но нужно соблюсти весь этот список условий (первый уже говорит о бесполезности попыток получения каких-то полномочий, они уже есть).
Попробуем взглянуть на архитектуру Active Directory:
Из схемы приведенной выше (взята из статьи Technical Reference Active Directory Collection, Data Store) видно, что сама база данных AD, а точнее база данных ESE, надежно защищена уровнем DSA. DSA реализует набор интерфейсов и функций для доступа к непосредственно данным, которые находятся в ntds.dit. Ну соответственно он пресекает любые попытки смухлевать.
Зачем стучаться в закрытую дверь, влезем через открытую форточку. :)
Обратимся напрямую к уровню ESE.
Extensible Storage Engine (ESE) – это механизм доступа к данным с использованием индексно-последовательного метода доступа (ISAM). Многие приложения/серверы Windows используют данный механизм для хранения и обработки данных, например DHCP, WINS, AD, Exchange (по-моему, используется какая-то особая версия ESE). Интерфейсы/функции ESE документированы и достаточно хорошо описаны. Подробнееhttp://msdn.microsoft.com/en-us/library/ms684493(EXCHG.10).aspx.
Открыв ntds.dit обнаружилось небольшое количество таблиц (7): datatable, hiddentable, link_table, quota_rebuild_progress_table, quota_table, sdproptable, sd_table.
Нас интересует таблица datatable. Таблица состоит из множества атрибутов (столбцов), которые соответствуют атрибутам, определенным в схеме AD. Получается, что на уровне ESE у каждого объекта (а объектами являются картежи этой таблицы) есть все атрибуты AD. В этой таблице находятся все объекты AD. По названию других таблиц не трудно догадаться, что там хранится. Атрибуты (большая часть из них) именуются следующим образом: ATTb589856, ATTj589855 и так далее. Что означают цифры в именах и как они связаны с атрибутами в схеме AD выяснить не удалось, может кто-нибудь подскажет :).
Получив список индексов для данной таблици был обнаружен индекс с именем nc_guid_Index, созданный по столбцам NCDNT_col:Long,ATTk589826:LongBinary. Поскольку объекты в Active Directory имеют уникальные object-GUID, этот индекс нам особенно полезен, по нему мы с легкостью определяем, что атрибут ATTk589826 это как раз Object-GUID. Будем использовать данный атрибут для поиска объектов в таблице.
Следующий интересный индекс - NC_Acc_Type_Sid - NCDNT_col:Long,ATTj590126:Long,ATTr589970:LongBinary. Не трудно догадаться, что ATTr589970 это SID объекта. Он конечно полезен для нас, но нас больше интересует SidHistory. Вот тут не получилось найти интуитивно-понятного индекса. Пришлось перебрать значения всех столбцов с типом LongBinary. Методом перебора выяснилось, что SidHistory это атрибут ATTr590433.
Собственно все, что нам нужно есть, осталось только прописать необходимые данные.
Пошагово опишу процесс:
- Изменяем глобальные данные нашего будущего экземпляра ESE. Поскольку по умолчанию размер страницы в ESE – 4КБ, а AD использует 8КБ страницы, нужно поменять глобальные настройки.
- Создаем экземпляр.
- Инициализируем.
- Создаем сессию.
- Аттачим базу, заем ее открывает базу.
- Открываем таблицу datatable.
- Устанавливаем текущий индекс INDEX_00090002 (это отдельный индекс для атрибута ATTr590433).
- Создаем ключ для поиска, указываем в качестве критерия поиска GUID искомого объекта.
- Осуществляем поиск.
- В транзакции обновляем столбец ATTr590433, записывая в него необходимые SID’ы.
- Закрываем БД, сессию, завершаем экземпляр ESE.
Вот вроде и все.
Испытания.
Теперь попробуем обсудить использование данного метода на различных моделях доменов/лесов Active Directory.
Один домен без RODC.
Если у пользователя (необязательно это должен быть администратор) есть физический доступ к контроллеру домена, то он может себе прописать SidHistory, используя способ описанный выше.
Единственное что замечено, контроллер домена очень трепетно относится к учетной записи Administrator (S-1-5-21-….-500), если добавить этот SID, то прав ни каких не будет. Нужно прописывать Domain Admins/Enterprise Admins.
Плюс еще есть много способов повышение себе полномочий имея физический доступ к контроллеру, например использование rootkitов, или например использование srvany + erd commander.
Домены с RODC.
RODC является Read-only только на уровне DSA. То есть ни что не мешает нам, воспользовавшись описанным методом, прописать себе SID полномочного пользователя. И вот мы прописали себе SID в SIDHistory, аутентифицировались у этого контроллера, получили маркер доступа, все замечательно – есть в нем необходимый SID. Но такой маркер будет получен только на подвластные RODC-контроллеру серверы/службы. Если же у RODC нет долгосрочного ключа для какой-то службы, то нам приходится обращаться к «полноценному» контроллеру домена. У того в свою очередь нет данных о том, что у нас в SIDHistory прописан супер-пупер SID. Более того RODC и «нормальные» контроллеры домена судя по всему используют разные долгосрочные ключи (об этом говорит несколько учеток krbtgt) для шифрования TGT. Соответственно «нормальный» контроллер домена выдаст нам TGT с SIDHistory без полномочного SID, мы его дадим TGS для получения Service Ticket, TGS скопирует набор SID из TGT, передаст Service Ticket нам, мы его предоставим той или иной службе, она создаст на его основе маркер. В этом маркере не будет необходимого нам SIDа, соответственно никаких полномочий мы не получим.
Долгосрочного ключа для служб на «нормальном» контроллере домена (например, службы LDAP, CIFS) у RODC нет, стандартными средствами не удается его направить на RODC, поэтому никаких полномочий в лесу мы не получим.
Вот если бы попробовать реплицировать данные из базы RODC на записываемый контроллер домена, тогда бы все получилось. Входящих соединений для репликации от RODC нет, ни в Configuration, ни в repsFrom. Но мне кажется RODC, как-то все равно в обратную сторону реплицируется. На этот вопрос пока нет ответа.
Ресурсный домен.
Здесь все тоже самое, как и с одним доменом без RODC. Получаем физический доступ к контроллеру домена, производим манипуляции описанные выше. Единственно не получится использовать rootkit’ы и srvany + erd commander. В этом плане конечно модель с использованием ресурсных доменов является более защищенной.
Домены из различных лесов.
Мы можем прописать себе в SIDHistory SID полномочной учетной записи из другого леса. Если у нас созданы доверительные отношения между доменами/лесами, так что исходный домен доверяет целевому домену, а значит может нас аутентифицировать и если фильтрация SidHistory отключена на этом доверии, то мы можем получить определенные права на исходный лес/домен.
Если фильтрация SIDHistory отключена (по умолчанию), то прописывание SID в SIDHistory ничего нам не даст. Можно конечно прописать себе в качестве основного SIDа SID Enterprise Adminа из домена источника (а можно даже несколько SIDов основных прописать), но это ничего не даст.
При прописывании несколько основных SID вываливается ошибка “Internal Error” и аутентификация не проходит. При прописывании в качестве основного SID SID из другого домена, контроллер домена считает эту учетку неродной и аутентификация также не происходит.
Итоги.
Наиболее защищенной показала себя модель с использованием RODC (хотя какие-либо права можно получить на подвластные RODC-серверы).
Использование отдельных лесов предоставляет изоляцию ресурсов (особенно если включена фильтрация SIDHistory) и является одним из наиболее надежных средств обеспечения безопасности, но является более ресурсоемкой и затратной затеей.
Использование модели с ресурсными доменами или единственным корневым доменом леса является небезопасным. Изоляция данных и служб не происходит. Как правило, это основные модели проектирования AD.
Ну и любая из этих моделей становится безопасной, если ограничить физический доступ к контроллерам домена.
Инструментальное средство.
Кульминация статьи :). Собственно утилита, которая позволяет в оффлайн режиме прописывать себе SID в SIDHistory. Без параметров отображается.
Требует наличия установленного на компьютере .Net Framework 2.0. Необходимо запускать на той версии Windows под которой работает AD (из-за различий в версиях ESE).