понедельник, 28 декабря 2009 г.

Безопасность в Active Directory

Вступление.Часто при проектировании логической структуры 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

Но выполнение данной функции налагает определенные ограничения, в частности должны быть выполнены следующие условия:

1) административные права в домене источнике;
2) права на добавление SidHistory в целевом домене;
3) на PDC в исходном домене в реестре должен быть ключ TCPIPClientSupport:DWORD=1;
4) должна быть создана локальная группа в целевом домене – $$$;
5) в целевом домене должен быть включен аудит управления учетными записями (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.
Собственно все, что нам нужно есть, осталось только прописать необходимые данные.
Пошагово опишу процесс:
1) Изменяем глобальные данные нашего будущего экземпляра ESE. Поскольку по умолчанию размер страницы в ESE – 4КБ, а AD использует 8КБ страницы, нужно поменять глобальные настройки.
2) Создаем экземпляр.
3) Инициализируем.
4) Создаем сессию.
5) Аттачим базу, затем ее открываем.
6) Открываем таблицу datatable.
7) Устанавливаем текущий индекс INDEX_00090002 (это отдельный индекс для атрибута ATTk589826).
8) Создаем ключ для поиска, указываем в качестве критерия поиска GUID искомого объекта.
9) Осуществляем поиск.
10) В транзакции обновляем столбец ATTr590433, записывая в него необходимые SID’ы.
11) Закрываем БД, сессию, завершаем экземпляр 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). 




http://download.securitylab.ru/_tools/ESEAddSidHistory.zip
MD5: F5489294F66769CAF09CACDA61B26426 ESEAddSidHistory.zip

P.S.: жду коментариев, замечаний :)



13 комментариев:

Николай комментирует...

Всегда интересно читать о практической реализации того, о чем размышлял теоретически.

И теперь не надо тратить время на аналогичные исследования :)

А утилиты в помощь злобному администратору субдомена не очень нужны, руками можно много чего наворотить. Проверял :)

Анонимный комментирует...

[09:27] <@breech> Следующий интересный индекс - NC_Acc_Type_Sid - NCDNT_col:Long,ATTj590126:Long,ATTr589970:LongBinary. Не трудно догадаться, что ATTr589970 это SID объекта
[09:27] <@breech> НЕТРУДНА пишецо слитно

gex комментирует...

>>> Николай...
для получения прав из не рутового домена, честно говоря, кроме как социнженирии в голову ни чего не приходит...

gex комментирует...

>>> брич
fixed :)

Николай комментирует...

> для получения прав из не рутового домена

Если в нерутовом домене есть права домен-админа, можно запускать программы от имени контроллера домена. А с ADSIEdit уже можно наворотить достаточно. Хоть схему подправить. У себя я это уже описывал.

Поэтому права администратора домена не должны выдаваться вообще никому. Ну и не забываем про RODC в несекурных помещениях, хотя бы для локализации возможного поражения.

gex комментирует...

>>> Николай...
да, верно...
запускаем под .\localsystem процесс и с помощью раздела конфигурации получаем привилегии в лесу... :)

gex комментирует...

В следующей статье опишу как получить полномочия в лесу без изначального физического доступа к контроллеру домена.. стандартными средствами.. с минимальными полномочиями... :)

Argon комментирует...

Очень интересно!

Я так понял, что если RODC сможет выписывать билеты на учетку с модифицированным SID хистори, и в том же сайте есть RW контроллеры домена, он примет такой билет, то АТАС.

Но тут есть 2 сложности...

1. RODC может проверять перед созданием билета по msDS-NeverRevealGroup.
2. Находясь в том же сайте, может реплицировать правильные значения (без прописанной группы) с RW контроллера до создания билета.

Ну, а также обратной репликации с RODC на RWDC быть не должно.


Вот бы все это на практике прверить!

Efimov Gennady комментирует...

Наличие RWDC в сайте не обязательно, главное чтобы учетка сервиса была реплицирована на RODC. То есть получается и учетка пользователя и учетка сервиса, к которому обращается пользователь.
Да, при репликации, RwDC (2008+) проверяет политики репликации паролей и не реплицирует на RoDC те учетные данные которые запрещены. В запреты попадают практически все полномочные группы.
Поэтому учетные данные админа или RwDC на RoDC не попадут. Но если например реплицируется что попало, то можно косвенно получить полномочия - через промежуточные звенья. Поэтому очень важно с особой осторожностью подходить к поликам репликации паролей, ну и вообще к планированию безопасности с RODC.

по 1. Да, но можно пропатчить базу и он схавает.
по 2. Если не менять метаданные, то он не реплицирует с RwDC. Он будет думать, что ничего не произошло. А чтобы реплицировалось, нужно откатить метаданные назад (в прошлое), чтобы RwDC реплицировал изменения. Тут работает стандартный механизм репликации по атрибутам.

Есть некоторая возможность репликации учетных данных с 2003 на RODC. Пока у меня проработка этого способа не получается.

Все что написано в этой статье я проверял. Инструмент для патчинга базы к статье есть.

Argon комментирует...

По поводу RWDC в сайте с RODC. Допустим, мы модифицировали сид хистори на RODC как надо. Он сможет выписывать билеты для компов, к которым у него есть пароли. А вот билет на доступ модифицированной учетки к RWDC не даст, так как паролей к RWDC у него нету.

Efimov Gennady комментирует...

поэтому я и говорю, что можно получить только косвенный доступ (если неправильно развернут RoDC) через другие службы...
например, получить доступ к почтовой службе, а далее через руткиты куда угодно... или доступ к админскому компу :)

я например знаю умельцев с прошлой работы, которые (у заказчика) недолго думая добавили Domain Users и Domain Computers в Allow.

Анонимный комментирует...

Hi my loved one! I wish to say that this article
is amazing, great written and come with approximately all
important infos. I would like to peer more posts like this .


My web site: path of exile

Svolotch комментирует...

>>Единственное что замечено, контроллер домена очень трепетно относится к учетной записи Administrator (S-1-5-21-….-500), если добавить этот SID, то прав ни каких не будет

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