- Эффективное получение хеша паролей в Windows. Часть 2
- Подводим итоги по менеджеру учетных записей безопасности
- Рекомендуемые инструменты
- Active Directory
- Файл базы данных NTDS.DIT
- Извлечение хешей из NTDS.DIT
- Изменения на 4 января 2012г.
- Сбор учеток в Active Directory. Как искать критически важные данные при атаке на домен
- Содержание статьи
- Другие статьи про атаки на Active Directory
- WARNING
- Работа с ntds.dit
- Продолжение доступно только участникам
- Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
- Как устроен ntds.dit?
Эффективное получение хеша паролей в Windows. Часть 2
В предыдущей статье из серии, я в общих словах объяснил, что такое Менеджер безопасности учетных записей (SAM) Windows, и как, получив физический или удаленный доступ к системе достать из SAM хешированные пароли локальных пользователей.
Подводим итоги по менеджеру учетных записей безопасности
В предыдущей статье из серии, я в общих словах объяснил, что такое Менеджер безопасности учетных записей (SAM) Windows, и как, получив физический или удаленный доступ к системе достать из SAM хешированные пароли локальных пользователей. При удаленном доступе существует три возможных метода получения хешей: метод, основанный на унаследованных возможностях Windows, на теневом копировании томов, и на внедрении в память процесса. Наконец, я сделал сводную электронную таблицу с описанием наиболее часто используемых утилит для дампа хешей из памяти процесса. О некоторых утилитах из этой таблице речь пойдет ниже.
И опять же я хочу повторить следующую мысль: если есть возможность перемещать файлы между вашей машиной и целевой системой, то всегда сначала копируйте файлы SAM и SYSTEM с целевой системы, а затем уже доставайте хеши паролей в оффлайн-режиме.
Тем не менее, простое копирование файлов не гарантирует, что вы получите хеши всех локальных учетных записей. Если все хеши вам получить так и не удалось, то придется слить их из памяти и объединить результаты. Странно, но с подобными случаями я сталкивался не раз, и, хочу подчеркнуть, что речь идет об автономных (не входящих в домен) рабочих станциях Windows.
Рекомендуемые инструменты
Когда на целевой системе мне удалось запустить Metasploit Meterpreter, я пользуюсь пост-эксплойтом smart_hashdump Карлоса Переза (Carlos Perez). Если же smart_hashdump не срабатывает, то я прибегаю к его предыдущей версии – пост-эксплойту hashdump.
Active Directory
Active Directory выступает в роли централизованного хранилища, служащего для управления сетью и безопасностью. В функции службы каталогов входит аутентификация и авторизация всех пользователей внутри домена Windows, создание и выполнение политик безопасности […] Когда пользователь регистрируется в системе на компьютере, входящем в домен, то именно Active Directory проверяет пароль пользователя […]
Информация из определения пригодится вам, после компрометации какой-либо системы из домена Windows. Для того чтобы быстро взять под контроль весь домен, вам нужно получить доступ к корневому контроллеру домена. Если же вы находитесь в домене-потомке, то ваша цель – получить доступ к контроллеру корневого домена леса с правами Администратора предприятия.
В сети существует множество ресурсов, посвященных тому, как повысить свои права в домене, и поэтому в настоящей статье этой темы мы касаться не будем. В блоге pentestmonkey.net приведена вся необходимая информация по вопросу повышения прав.
Также существует вероятность, что администратор использует одни и тот же пароль локального администратора на всех машинах домена. В подобном случае, вам достаточно с помощью keimpx узнать пароль всего на одной машине, и контроллер у вас в руках!
Неважно, каким именно способом вы получили доступ к контроллеру домена (в идеале, подключились к корневому контроллеру домена, так как именно на нем в первую очередь отражаются изменения учетных записей пользователей), самое главное: запустить на контроллере командную строку с правами администратора (локального или доменного).
Файл базы данных NTDS.DIT
Файл NTDS.DIT заблокирован системой. Для получения этого файла вместе с файлом SYSTEM воспользуйтесь службой теневого копирования томов, как описывалось в предыдущей статье.
Как вариант, используйте функцию создания снимка утилитой ntdsutil, впервые такая функция была представлена в Windows Server 2008. Утилита сделает мгновенный снимок базы данных Active Directory, что позволит вам скопировать ntds.dit и файл SYSTEM. О том, как сделать снимок, написано в статье Microsoft TechNet.
Извлечение хешей из NTDS.DIT
Также для извлечения хешей подойдет пакет (ntds_dump_hash.zip), разработанный Ксаба Бартой (Csaba Barta). Функции пакета описаны в статье “Исследование получения хеша паролей в оффлайн-режиме и анализ ntds.dat”. ntds_dump_hash.zip позволяет:
- извлечь необходимые таблицы из ntds.dit: esedbdumphash
- получить хеши и дополнительные сведения об учетных записях пользователей: dsdump.py, dsdumphistory.py, dsuserinfo.py.
Скачайте и скомпилируйте пакет:
$ wget http://csababarta.com/downloads/ntds_dump_hash.zip
$ unzip ntds_dump_hash.zip
$ cd libesedb
$ ./configure && make
Воспользуйтесь esedbdumphash, чтобы извлечь таблицу datatable из ntds.dit:
$ cd esedbtools
$ ./esedbdumphash -v -t /tmp/output
$ ls -1 /tmp/output.export/
datatable
Используйте dsdump.py, чтобы получить хеши из таблицы datatable с помощью bootkey (SYSKEY) из куста SYSTEM:
$ cd ../../creddump/
$ chmod +x *.py
$ ./dsuserinfo.py /tmp/output.export/datatable
$ ./dsdump.py /tmp/output.export/datatable —include-locked
—include-disabled > domain_hashes.txt
Как и в случае с автономными рабочими станциями, вы точно так же, используя те же методы, можете слить пароли доменных пользователей, внедрившись в память процесса. Но будьте осторожны при манипуляциях с процессом LSASS на контроллере домена: в худшем случае вам придется перезагружать критически важный сервер.
Информацию обо всех описанных в этой статье утилитах я добавил в электронную таблицу.
Изменения на 4 января 2012г.
Скачайте и установите последнюю версию libesedb.
Извлеките таблицы из ntds.dit:
$ esedbexport -l /tmp/esedbexport.log -t /tmp/ntds.dit
esedbexport 20111210
Opening file.
Exporting table 1 (MSysObjects) out of 12.
Exporting table 2 (MSysObjectsShadow) out of 12.
Exporting table 3 (MSysUnicodeFixupVer2) out of 12.
Exporting table 4 (datatable) out of 12.
Exporting table 5 (hiddentable) out of 12.
Exporting table 6 (link_table) out of 12.
Exporting table 7 (sdpropcounttable) out of 12.
Exporting table 8 (sdproptable) out of 12.
Exporting table 9 (sd_table) out of 12.
Exporting table 10 (MSysDefrag2) out of 12.
Exporting table 11 (quota_table) out of 12.
Exporting table 12 (quota_rebuild_progress_table) out of 12.
Export completed.
$ ls -1 /tmp/ntds.dit.export/
datatable.3
hiddentable.4
link_table.5
[. ]
С помощью NTDSXtract извлеките из таблицы datatable хешированные пароли и историю паролей:
Сбор учеток в Active Directory. Как искать критически важные данные при атаке на домен
Содержание статьи
Другие статьи про атаки на Active Directory
WARNING
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный информацией из этой статьи.
Работа с ntds.dit
Файл ntds.dit представляет собой базу данных, в которой хранится информация Active Directory, такая как сведения о пользователях, группах и членстве в группах. База также включает хеши паролей для всех пользователей в домене.
Первым делом следует получить копию файла ntds.dit . Он расположен на контроллере домена в директории C:\Windows\NTDS\ . Но просто скопировать его не получится, так как этот файл постоянно используется EFS в Active Directory, и оператор (пентестер, редтимер, злоумышленник или исследователь) рискует получить следующее сообщение об ошибке.
Ошибка копирования файла ntds.dit
Я расскажу о двух способах скопировать данный файл. Первый способ использует скрипт PowerShell, а второй — копирование с помощью встроенных средств Windows.
Скрипт Invoke-NinjaCopy позволяет копировать любые используемые службами Windows файлы, в том числе и ntds.dit . При этом скрипт не запускает посторонних служб и не внедряется в процессы или контекст System. Этот инструмент получает дескриптор диска, что дает ему право на чтение необработанного массива байтов всего тома. Затем скрипт анализирует структуру NTFS и ищет определенную сигнатуру. Таким образом определяет, где находится файл, и побайтово его копирует. Так можно читать даже файлы, которые блокирует LSASS.
Копирование файла с помощью Invoke-NinjaCopy
Плюс ко всему данный скрипт написан на PowerShell, поэтому запускается из памяти, что позволяет избежать его сохранения на диск.
Второй способ — теневое копирование. Для этого используется установленный в Windows инструмент vssadmin. Сначала следует создать теневую копию с помощью следующей команды:
Создание теневой копии с помощью vssadmin
А теперь можно копировать оттуда никем не используемый файл ntds.dit .
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Как устроен ntds.dit?
Все данные каталога Active Directory хранятся в БД в файле ntds.dit. Подавляющее большинство приложений взаимодействуют с каталогом через прослойку DSA реализованную в ntdsa.dll. В свою очередь функции из ntdsa.dll не работают напрямую с ntds.dit, их функционал ограничен потребностями службы каталогов и они не могут дать нам представление о внутреннем устройстве БД Active Directory. Тем не менее ntds.dit представляет собой не что иное как БД JET Blue. В каждой версии windows (начиная с Windows 2000) есть всё необходимое для работы с этой БД.
В статье ниже я попробую осветить следующие вопросы:
- Какова структура БД?
- Как данных в ntds.dit получается «дерево»?
- Как реализовано членство в группах?
- Каков формат атрибута replPropertyMetaData и с какой точностью в метаданных репликации хранятся временные метки?
Что нужно, чтобы заглянуть в ntds.dit ?
Как минимум: esent.dll
Для «комфортного» использования из различных языков программирования над ESENT API имеются различные «обёртки». Я использовал Meneged Esent в связке с C#. На сайте проекта имеется много примеров — поэтому далее я постараюсь сконцентрироваться именно на содержимом ntds.dit.
Также следует обратить внимание, что у БД JET Blue есть такой параметр как PageSize. По-умолчанию, он равен 4096 (для тех версий esent.dll, с которыми я сталкивался). Так вот в ntds.dit размер страницы равен 8192 и этот параметр следует корректно установить до открытия БД.
У API ESENT есть несколько версий. Эти версии несовместимы! Так ntds.dit из Windows Server 2008 R2 на windows xp не откроется, только на Windoes 7. (Обратную совместимость я не проверял)
Вопрос первый: Какова структура БД?
Функция GetTableNames возвратит список таблиц в базе:
datatable — основная таблица со всеми данными каталога
hiddentable
link_table — согласно статье на technet таблица с информацией о связанных атрибутах (например MemberOf)
quota_rebuild_progress_table
quota_table
sdpropcounttable
sd_table — согласно статье на technet таблица содержит информацию о наследованных правилах доступа для каждого объекта каталога.
Остановимся подробнее на таблице datatable. Список её столбцов имеет вид (на скриншоте первые несколько строк):
Тупик? Нет!
Имена большинства колонок имеют формат ATT . Так вот этот цифровой код — уникальный идентификатор атрибута Active Directory. В таблице есть одна строка, в которой значение цифрового кода столбца совпадает с его значением. Если вывести все значения типа Text из этой строки, то мы увидим, что это определение атрибута «attributeID».
JET_COLUMNID | Column Name | Jet Column Type | AD atribute Name | |
---|---|---|---|---|
JET_COLUMNID(0x6) | ab_cnt_col | Long | Single-value | |
JET_COLUMNID(0x100) | Ancestors_col | LongBinary | Single-value | |
JET_COLUMNID(0x536) | ATTb131079 | Long | subRefs | Multi-value |
JET_COLUMNID(0x121) | ATTb131088 | Long | nCName | Multi-value |
JET_COLUMNID(0x2dd) | ATTb131108 | Long | dMDLocation | Multi-value |
JET_COLUMNID(0x42c) | ATTb1376270 | Long | documentAuthor | Multi-value |
JET_COLUMNID(0x169) | ATTb1376277 | Long | secretary | Multi-value |
JET_COLUMNID(0x2b8) | ATTb1376294 | Long | associatedName | Multi-value |
JET_COLUMNID(0x470) | ATTb33 | Long | roleOccupant | Multi-value |
JET_COLUMNID(0x203) | ATTb34 | Long | seeAlso | Multi-value |
JET_COLUMNID(0x2d2) | ATTb49 | Long | distinguishedName | Multi-value |
JET_COLUMNID(0x4cc) | ATTb50 | Long | uniqueMember | Multi-value |
JET_COLUMNID(0x206) | ATTb589856 | Long | domainPolicyObject | Multi-value |
JET_COLUMNID(0x250) | ATTb589864 | Long | fromServer | Multi-value |
JET_COLUMNID(0x205) | ATTb589881 | Long | defaultLocalPolicyObject | Multi-value |
JET_COLUMNID(0x1cc) | ATTb589921 | Long | preferredOU | Multi-value |
JET_COLUMNID(0x5a6) | ATTb590037 | Long | defaultClassStore | Multi-value |
JET_COLUMNID(0x270) | ATTb590038 | Long | nextLevelStore | Multi-value |
JET_COLUMNID(0x183) | ATTb590127 | Long | notificationList | Multi-value |
JET_COLUMNID(0x238) | ATTb590192 | Long | rIDManagerReference | Multi-value |
JET_COLUMNID(0x57c) | ATTb590193 | Long | fSMORoleOwner | Multi-value |
JET_COLUMNID(0x3c8) | ATTb590246 | Long | domainPolicyReference | Multi-value |
JET_COLUMNID(0x566) | ATTb590281 | Long | localPolicyReference | Multi-value |
JET_COLUMNID(0x3c1) | ATTb590295 | Long | trustParent | Multi-value |
JET_COLUMNID(0x4c1) | ATTb590296 | Long | domainCrossRef | Multi-value |
JET_COLUMNID(0x5bc) | ATTb590304 | Long | defaultGroup | Multi-value |
JET_COLUMNID(0x57f) | ATTb590318 | Long | siteServer | Multi-value |
JET_COLUMNID(0x532) | ATTb590338 | Long | physicalLocationObject | Multi-value |
JET_COLUMNID(0x563) | ATTb590341 | Long | ipsecPolicyReference | Multi-value |
JET_COLUMNID(0x24f) | ATTb590361 | Long | dynamicLDAPServer | Multi-value |
JET_COLUMNID(0x1a4) | ATTb590381 | Long | parentCA | Multi-value |
JET_COLUMNID(0x233) | ATTb590448 | Long | ipsecOwnersReference | Multi-value |
JET_COLUMNID(0x345) | ATTq590722 | Currency | aCSNonReservedTxSize | Multi-value |
JET_COLUMNID(0x398) | ATTq591137 | Currency | aCSMaxTokenBucketPerFlow | Multi-value |
JET_COLUMNID(0x19b) | ATTq591138 | Currency | aCSMaximumSDUSize | Multi-value |
JET_COLUMNID(0x4d3) | ATTq591139 | Currency | aCSMinimumPolicedSize | Multi-value |
JET_COLUMNID(0x244) | ATTq591140 | Currency | aCSMinimumLatency | Multi-value |
JET_COLUMNID(0x12f) | ATTq591141 | Currency | aCSMinimumDelayVariation | Multi-value |
JET_COLUMNID(0x16e) | ATTq591142 | Currency | aCSNonReservedPeakRate | Multi-value |
JET_COLUMNID(0x344) | ATTq591143 | Currency | aCSNonReservedTokenSize | Multi-value |
JET_COLUMNID(0x4d4) | ATTq591144 | Currency | aCSNonReservedMaxSDUSize | Multi-value |
JET_COLUMNID(0x343) | ATTq591145 | Currency | aCSNonReservedMinPolicedSize | Multi-value |
JET_COLUMNID(0x5ac) | ATTq591191 | Currency | mS-SQL-Memory | Multi-value |
JET_COLUMNID(0x213) | ATTq591204 | Currency | mS-SQL-Status | Multi-value |
JET_COLUMNID(0x4d5) | ATTq591220 | Currency | mS-SQL-Size | Multi-value |
JET_COLUMNID(0x2c5) | ATTq591266 | Currency | msDS-Cached-Membership-Time-Stamp | Multi-value |
JET_COLUMNID(0x548) | ATTq591456 | Currency | msWMI-Int8Default | Multi-value |
JET_COLUMNID(0x52a) | ATTq591457 | Currency | msWMI-Int8Max | Multi-value |
JET_COLUMNID(0x53f) | ATTq591458 | Currency | msWMI-Int8Min | Multi-value |
JET_COLUMNID(0x214) | ATTq591459 | Currency | msWMI-Int8ValidValues | Multi-value |
JET_COLUMNID(0x2c1) | ATTq591520 | Currency | lastLogonTimestamp | Multi-value |
JET_COLUMNID(0x2cc) | ATTq591794 | Currency | msDS-LastSuccessfulInteractiveLogonTime | Multi-value |
JET_COLUMNID(0x462) | ATTq591795 | Currency | msDS-LastFailedInteractiveLogonTime | Multi-value |
JET_COLUMNID(0x440) | ATTq591835 | Currency | msDS-MaximumPasswordAge | Multi-value |
JET_COLUMNID(0x2a5) | ATTq591836 | Currency | msDS-MinimumPasswordAge | Multi-value |
JET_COLUMNID(0x200) | ATTq591841 | Currency | msDS-LockoutObservationWindow | Multi-value |
JET_COLUMNID(0x2e7) | ATTq591842 | Currency | msDS-LockoutDuration | Multi-value |
JET_COLUMNID(0x3d0) | ATTq591879 | Currency | msDS-USNLastSyncSuccess | Multi-value |
JET_COLUMNID(0x49a) | ATTq591922 | Currency | msDS-ClaimValueType | Multi-value |
JET_COLUMNID(0x476) | ATTq592002 | Currency | msKds-UseStartTime | Multi-value |
JET_COLUMNID(0x477) | ATTq592003 | Currency | msKds-CreateTime | Multi-value |
JET_COLUMNID(0x3a0) | ATTq592007 | Currency | msDS-GeoCoordinatesAltitude | Multi-value |
JET_COLUMNID(0x3a1) | ATTq592008 | Currency | msDS-GeoCoordinatesLatitude | Multi-value |
JET_COLUMNID(0x3a2) | ATTq592009 | Currency | msDS-GeoCoordinatesLongitude | Multi-value |
JET_COLUMNID(0x43b) | ATTr589945 | LongBinary | securityIdentifier | Multi-value |
JET_COLUMNID(0x1c9) | ATTr589970 | LongBinary | objectSid | Multi-value |
JET_COLUMNID(0x276) | ATTr590433 | LongBinary | sIDHistory | Multi-value |
JET_COLUMNID(0x443) | ATTr590491 | LongBinary | syncWithSID | Multi-value |
JET_COLUMNID(0x5e4) | ATTr591234 | LongBinary | mS-DS-CreatorSID | Multi-value |
JET_COLUMNID(0x50a) | ATTr591668 | LongBinary | msDS-QuotaTrustee | Multi-value |
JET_COLUMNID(0x1c2) | ATTr591978 | LongBinary | msAuthz-CentralAccessPolicyID | Multi-value |
JET_COLUMNID(0x5) | cnt_col | Long | Single-value | |
JET_COLUMNID(0x1) | DNT_col | Long | Single-value | |
JET_COLUMNID(0x5f1) | extendedprocesslinks_col | LongBinary | Single-value | |
JET_COLUMNID(0x9) | IsVisibleInAB | UnsignedByte | Single-value | |
JET_COLUMNID(0x8) | NCDNT_col | Long | Single-value | |
JET_COLUMNID(0x3) | OBJ_col | UnsignedByte | Single-value | |
JET_COLUMNID(0x2) | PDNT_col | Long | Single-value | |
JET_COLUMNID(0x4) | RDNtyp_col | Long | Single-value | |
JET_COLUMNID(0xa) | recycle_time_col | Currency | Single-value | |
JET_COLUMNID(0x7) | time_col | Currency | Single-value |
Остался один «нерасшифрованый» атрибут ATTc0 — это ссылка на «objectClass».
Обратите внимание — все колонки, хранящие атрибуты каталога Active Directory заведены как Multi-value в не зависимости от схемы.
Вопрос второй: Как данных в ntds.dit получается «дерево»?
Название столбца «DNT_col» провоцирует предположить, что он как-то связан с distinguishedName объекта (как позже выяснилось — они равны)
Значения колонки DNT_col начинаются с 1, причём строка с DNT_col=1 соответствует интересному объекту со значенем атрибута name=»$NOT_AN_OBJECT1$»
Строка с DNT_col=2 содержит в себе атрибуты объекта с именем «$ROOT_OBJECT$» (Не путать с RootDSE)
С DNT_col=6 начинаются определения objectClass’ов
Опять тупик? Опять нет!
Пойдём другим путём.
Поиск по колонке ATTm589825 (name) значения типа Text «Administrator» вернул запись с DNT_col=3841 и PDNT_col=1951
Поиск по колонке ATTm589825 (name) значения типа Text «Users» (контейнер, в котором расположена учётная запись стандартного администратора) вернул запись с DNT_col=1951 и PDNT_col=1944
Вот она связь! столбец PDNT_col содержит идентификатор DNT_col родительского объекта.
В строке с DNT_col=1944 ( PDNT_col=1943) — оказался объект домена второго уровня (ntds.dit был взять с тестового контроллера домена второго уровня)
В строке с DNT_col=1943 ( PDNT_col=2) — объект домена первого уровня.
Если вы когда-нибудь задавались вопросом: «Почему в при подключении к dc=contoso,dc=com не отображаются объекты из cn=Configuration,dc=contoso,dc=com?» то вам следует обратить внимание на колонку NCDNT_col — она содержит ссылки на объект контекста именования. (причём, объект домена первого уровня не имеет контекста именования — моэет по этому он и не виден?). Для Объектов в контекстах именования «dc=contoso,dc=com» и «cn=Configuration,dc=contoso,dc=com» значение этой колонки отличается.
Не менее интересно как из этих чисел получается полное distinguishedName объекта? Какой аттрибут обекта является относительным уникальным именем (RDN) и используется для построения полного distinguishedName.
Колонка RDNtyp_col содержит идентификатор атрибута (attributeID), содержащего RDN.
В колонке CNT_col содержится количество объектов, связанных с текущим. Эта колонка используется механизмом Link Cleaner
Если бит в колонке OBJ_col установлен в 1, значит данная строка описывает объект каталога. Иначе — это объект-фантом.
Как реализован SubTree поиск?
Понятно, что при такой структуре для поиска OneLavel достаточно поискать среди записей с PDNT_col равной DN базы поиска, а вот как поискать по SubTree? Обходить все ветви? Нет это слишком сложно.
Присмотримся к значениям в колонке с говорящим именем Ancestors_col. В глаза бросается, что чем глубже в иерархии расположен объект, тем длиннее значение в этой колонке. Каждый уровень вложенности добавляет к длине 4 байта. Это не что иное как список родительских объектов в порядке очерёдности.
Причём список начинается с dn=2, т.е. с «$ROOT_OBJECT$»
Кто занимается поддержанием Ancestors_col в актуальном состоянии? Согласно документу при перемещении объекта в новое место изменяется только его PDNT_col, а значение Ancestors_col обновляется механизмом SDProp заодно с пересчётом новых правил доступа к объекту.
Вопрос третий: Как реализовано членство в группах?
Почему c 2003-го сервера появилась возможность влючать в группу брактически неограниченное число прользователей, и при этом в строковый или числовой multi-value атрибут не удастся записать боле
1200 значений?
Да потому, что «member» и «memberOf» определены как ссылки. В таблице datatable нет столбцов, соответствующих этим атрибутам. Значения этих атрибутов реализованы как соответствия в отдельной таблице link_table.
Быть может именно поэтому при удалении группы (без использования RecucleBin) мы теряем сведения о её членах — объект удалённой группы получает новый идентификатор в DNT_col при перемещении в контейнер удалённых объектов (а связь группы и её члена построена именно по этому идентификатору)
JET_COLUMNID(0x2) | backlink_DNT | Long | Single-value |
JET_COLUMNID(0x3) | link_base | Long | Single-value |
JET_COLUMNID(0x100) | link_data | LongBinary | Single-value |
JET_COLUMNID(0x4) | link_deactivetime | Currency | Single-value |
JET_COLUMNID(0x5) | link_deltime | Currency | Single-value |
JET_COLUMNID(0x1) | link_DNT | Long | Single-value |
JET_COLUMNID(0x80) | link_metadata | Binary | Single-value |
JET_COLUMNID(0x7) | link_ncdnt | Long | Single-value |
JET_COLUMNID(0x101) | link_ndesc | Long | Single-value |
JET_COLUMNID(0x6) | link_usnchanged | Currency | Single-value |
Названия и тип столбцов намекают, а анализ содержащихся в них данных подтверждает, что:
link_DNT — Содержит идентификатор dn (соответствует DNT_col из datatable) объекта, связь которого описывается (например, объекта группы)
backlink_DNT — Содержит идентификатор dn связанного с ним объекта (например, объекта пользователя)
link_ncdnt — Содержит идентификатор dn контекста именования, в котором расположены участники связи.
link_usnchanged — Содержит USN последнего изменения всязи
link_data — Я видел это поле заполненным только для связей объектов NTDS Settings. Да! Объекты NTDS Settings имеют связи с объектами разделов каталога повидимому посредством этих связей задаются параметры репликации различных разделов каталога.
link_deltime — Содержит время удаления связи.
link_metadata — содержит метаданные, необходимые для репликации внесённых изменений. Заполеннными значения этой колонки я видел только на Windows 2012. Christoffer Andersson пишет, что колонка содержит структуру DS_REPL_VALUE_META_DATA и здесь я с ним категорически не согласен. Структура DS_REPL_VALUE_META_DATA используется на более высоком уровне — её возвращают вызовы ntdsa.dll. Данные, содержащаеся в этой колонке имеют размер меньше, чем необходимо под структуру DS_REPL_VALUE_META_DATA. Пока данная колонка остаётся для меня загадкой. Впринципе метаданные репликации для аттрибутов-связей можно получить из построенного атрибута msDS-ReplValueMetaData, но это не раскрывает внутреннего механизма обработки и хранения этих данных.
Вопрос четвёртый: Каков формат атрибута replPropertyMetaData и с какой точностью в метаданных репликации хранятся временные метки?
В этом атрибуте хранятся метаданные репликации в двоичном виде:
Что хранится в первых 8-ми байтах данной структуры я пока не разобрался.
Следует обратить внимание на тот факт, что в структуре replPropertyMetaData перечисляются только реплицируемые атрибуты со значениями. Так, например, вы не увидите в replPropertyMetaData идентификатора атрибута logonTimestamp.
Тут есть интересный момент: в структуре replPropertyMetaData для объектов безопасности Active Directory (пользователей, групп и компьютеров) присутствует атрибут objectSid.
Кстати, чтобы расшифровать значение этого атрибута — не обязательно так напрягаться — существует построенный атрибут msDS-ReplAttributeMetaData — он собой предстваляет не что иное как разобранное значение replPropertyMetaData.
Временные метки в Active Directory это 64-битные беззнаковые целые числа, указывающие количество секунд, прошедших с 00:00 1 января 1601 года. Отсюда вытекает интересный нюанс: при правке одного атрибута одного и того же объекта на двух контроллерах домена в течение 1 секунды (например при пакетной обработке большого числа пользователей) можно получить неожиданный результат.
По данным статьи на technet выигрывает версия атрибута от контроллера с меньшим GUID.