Привет! Меня зовут Лера, я младший аналитик-исследователь киберугроз в компании R-Vision.

В этой серии статей я хочу поделиться с вами разбором уже не новой, но по данным различных исследований все еще применяемой в атаках критической уязвимости CVE-2020-1472 или Zerologon. Она позволяет злоумышленникам изменить пароль компьютерной учетной записи контроллера домена и получить доступ к содержимому Active Directory.

Эксплуатация Zerologon возможна на следующих не пропатченных версиях Windows Server: 2008 R2, 2012, 2012R2, 2016, 2019. В версии Windows Server 2022 уязвимость уже исправлена. Для реализации атаки достаточно наличия сетевой связности с устройства, к которому имеет доступ атакующий, до уязвимого контроллера домена.

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

Секрет эксплуатации

Возможность эксплуатации данной уязвимости кроется в протоколе Microsoft Netlogon Remote Protocol, а точнее в алгоритме шифрования, который он использует.

Microsoft Netlogon Remote Protocol или MS-NRPC — это один из интерфейсов удаленного вызова процедур (RPC), который применяется для проверки подлинности пользователей и компьютеров в доменных сетях, а именно для поддержания доменных отношений между:
- членами домена и контроллером домена;
- контроллерами домена в одном домене и контроллерами домена в разных доменах. 

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

Ниже в таблице указаны RPC методы, использующиеся при установке соединения Netlogon. Дальше будут встречаться при разборе атаки.

RPC-методы Netlogon

OpNum

Описание

NetrServerReqChallenge

4

Метод получает запрос клиента и возвращает запрос сервера (SC)

NetrServerAuthenticate2 / NetrServerAuthenticate3

15/26

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

NetrServerPasswordSet2

30

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

Здесь мы можем увидеть, как поэтапно происходит установление соединения между клиентом и сервером посредством Netlogon (рисунок 1):

Рисунок 1. Согласование сессионного ключа Netlogon
Рисунок 1. Согласование сессионного ключа Netlogon
  1. Вначале клиент генерирует некоторое рандомное значение nonce (Client challenge), равное 8 байтам, и отправляет его с помощью метода NetrServerReqChallenge. Сервер, в свою очередь, делает то же самое и направляет ответ Server challenge клиенту. Сервер сохраняет у себя Client challenge, а клиент Server challenge;

  2. После завершения обмена вызовами генерируется сеансовый ключ SessionKey (Sk) с помощью функции формирования ключа KDF (Key Derivation Function) и на основе прошедших challeng-ей и общего секрета (SharedSecret) - хэша пароля компьютерной учетной записи клиента. Сессионый ключ = KDF (SharedSecret, Challenges);

  3. Затем клиент формирует Client Credential, используя сессионный ключ и Challenge. При этом с помощью параметра Negotiate flag задаются параметры соединения, в том числе и те, которые отвечают за безопасность. Дальше Client Credential отправляется серверу посредством метода NetrServerAuthenticate (или NetrServerAuthenticate2, или NetrServerAuthenticate3);

  4. Сервер сравнивает полученные данные с теми, что хранятся у него (пароль компьютерной учетной записи клиента, находящийся в его базе, а также Challengе). То есть сервер, вычислив сеансовый ключ, шифрует этим ключом имеющиеся данные, и если результат совпадает с тем, который ему отправил клиент, соединение продолжается. В то же время сервер с помощью метода NetrServerAuthenticate посылает Server Credential;

  5. Клиент по такому же принципу проверяет Server Credential, и если они совпадают, то клиент и сервер соглашаются использовать вычисленный сеансовый ключ для шифрования и/или подписи дальнейших данных.

Для генерации Client Credential применяется функция ComputerNetLogonCredential. Существуют 2 типа реализации: 2DES и AES-CFB8 (далее AES), но новыми версиями Windows поддерживается только AES. Для установления связи и аутентификации MS-NRPC используются режим шифрования AES, где применяется вектор инициализации, то есть псевдослучайная последовательность символов. Ее добавляют к ключу шифрования для повышения его безопасности.

Формирование Client Credential происходит следующим образом (рисунок 2):

  • Вектор инициализации шифруется сессионным ключом, используя алгоритм AES. Таким образом, создается блок информации, откуда берется первый байт. Он, в свою очередь, проходит операцию XOR с первым байтом ClientChallenge и получается определенное значение;

  • Затем вектор инициализации сдвигается и шифруется сессионным ключом согласно алгоритму AES. Далее получается очередной блок информации, и также берется первый байт, который проходит XOR уже со вторым байтом ClientChallenge. И так происходит до тех пор, пока все байты ClientChallenge не пройдут шифрование.

Рисунок 2. Формирование ClientCredential
Рисунок 2. Формирование ClientCredential

Вектор инициализации - это псевдослучайное значение, и оно должно быть уникальным.
Как говорилось ранее, для генерации Credential используется функция ComputerNetLogonCredential. Как оказалось, в MS-NRPC она определяет, что вектор инициализации фиксирован и равен 16 нулевым байтам. Первая брешь состоит именно в этом.

Дальше на стороне клиента мы можем изменять ClientChallenge и представим, что ClientChallenge также равен 8 нулевым байтам (как это и сделано в эксплойтах).
По экспертным оценкам, шанс получить результат шифрования нулевого вектора AES-ом с первым нулевым байтом в среднем составляет примерно 1/256. Получается, что при заданном нулевом векторе инициализации уязвимость заключается в нахождении такого ключа, для которого зашифрованный AES-ом блок будет начинаться с 0 байта.

И если мы берем первый байт, равный 0, и применяем операцию XOR к первому нулевому байту Client Challenge, то в результате получаем на выходе 0 (рисунок 3). Повторение этого алгоритма приведет к тому, что второй байт будет равен 0, и так далее до тех пор, пока все зашифрованное сообщение не будет состоять только из нулей.

Рисунок 3. Формирование ClientCredential при эксплуатации Zerologon
Рисунок 3. Формирование ClientCredential при эксплуатации Zerologon

Опираясь на эти факты, можно понять главную цель эксплойта: применение "брутфорса" до тех пор, пока контроллер домена не вычислит сеансовый ключ, который в последствии предоставит данные со всеми нулями.

Изучив, каким образом работает Netlogon и главную уязвимость алгоритма шифрования, мы можем понять общий принцип действия эксплойтов для этой уязвимости.

Алгоритм эксплуатации уязвимости

Эксплуатация уязвимости Zerologon состоит из трех этапов (рисунок 4):

Рисунок 4. Эксплуатация уязвимости Zerologon
Рисунок 4. Эксплуатация уязвимости Zerologon
  1. На первом этапе при отправке запроса к серверу для дальнейшей аутентификации отправляются нулевые байты. Вместо отправки восьми случайных байтов, как это происходит обычно, посредством эксплойта в качестве ClientChallenge отправляется 8 нулевых байтов. Отправка повторяется до тех пор, пока сервер не подберет нужный сессионный ключ. Для успешного подключения к серверу требуется в среднем 256 попыток отправки сообщения ClientChallenge, состоящего из нулей;

  2. Дальше происходит "отключение" механизма RPC signing and sealing. MS-NRPC использует данный механизм для шифрования передающейся информации. Обычно шифрование является обязательным процессом для передачи данных, НО в MS-NRPC этот механизм не является обязательным и контролируется клиентом. По идее, шаг RPC signing and sealing должен помешать эксплойту.

    На этом этапе используется сеансовый ключ для шифрования и расшифровки сообщений, отправляемых и получаемых как клиентом, так и сервером. Однако злоумышленник, имитирующий клиента, не знает сеансовый ключ, поскольку его необходимо вычислять с помощью пароля компьютерной учетной записи клиента. А сервер не отказывается установить соединение с клиентами, не запрашивающими использование шифрования. Принимая во внимания теоретические исследования данной уязвимости, этим и воспользовались злоумышленники при написании эксплойтов: они просто "отключили" шифрование в заголовке сообщения посредством запроса NetrServerAuthenticate2 с определенным флагом, чтобы сообщения отправлялись в виде открытого текста. Однако с данным флагом все оказалось не так прозрачно, подробнее об этом мы расскажем дальше;

  3. Заключительным шагом является смена пароля компьютерной учетной записи контроллера домена. Эксплоиты применяют метод NetrServerPasswordSet (или NetrServerPasswordSet2 ) в MS-NRPC для изменения пароля компьютерной учетной записи сервера. При этом можно установить пустой пароль или же просто отправить запрос с новым паролем. После изменения пароля злоумышленники могут использовать учетную запись контроллера домена для эскалации атаки, например, для репликации базы данных Active Directory.

В момент сброса пароля учетной записи контроллера домена в Active Directory он находится в несогласованном состоянии, то есть фактически выпадает из домена. Пароль учетной записи компьютера, хранящийся в реестре и в памяти lsass.exe, при этом не изменяется. Он изменяется в самой Active Directory, и если контроллер домена будет перезагружен, различные службы больше не запустятся.

Злоумышленник может обойти это, восстановив вручную исходное значение в Active Directory после восстановления его из файла NTDS.dit, например, с помощью инструмента secretsdump из набора Impacket.

А теперь давайте подробно изучим тот самый NegotiateFlag, якобы "отключающий" механизм RPC signing and sealing.

Флаг "отключения" механизма RPC signing and sealing

Как уже говорилось, "отключение" механизма RPC signing and sealing осуществляется посредством установления определенного флага при отправке ClientCredential в методе NetrServerAuthenticate. Если быть точнее - установкой в "0" определенного бита в NegotiateFlag, который соответствует значению "Supports Secure RPC".

Чтобы получше понять, какую информацию в себе несет каждый бит, рассмотрим пример флага, который используется во всех эксплойтах для уязвимости Zerologon - 0*212fffff. Флаг описывается во всех эксплойтах как стандартный флаг, используемый в Windows 10 с отключенным только функционалом "подписи и запечатывания". Почему это так?

Преобразование флага

Флаги представляют собой 32-битное число, которое формируется в двоичном виде из набора различных параметров.
212fffff - некоторое шестнадцатеричное число.
Необходимо перевести его в двоичный формат.
В результате получаем некоторое двоичное значение 100001001011111111111111111111.
Так как флаг 32-битный, впереди необходимо добавить недостающие два нуля.
Получается тот же флаг 00100001001011111111111111111111, но уже 32-битный.

Согласно документации Microsoft каждый бит представляет собой определенную букву, отвечающую за тот или иной параметр. Выглядит это следующим образом :

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

0

Y

X

0

0

0

0

W

0

0

V

U

T

S

R

Q

P

O

N

M

L

K

J

I

H

G

F

E

D

C

B

A

Расшифровку каждой буквы можно также посмотреть в документации.

В нашем случае для флага 0*212fffff получается следующее значение:

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

0

0

X

0

0

0

0

W

0

0

V

0

T

S

R

Q

P

O

N

M

L

K

J

I

H

G

F

E

D

C

B

A

На месте "Support Secure RPC" («Y») стоит 0 и это означает, что шаг «signing and sealing» пропускается.

Однако, изучая различные источники, мне удалось узнать одну интересную вещь, связанную как раз с параметром "Support Secure RPC" («Y»). Оказывается, что для использования эксплойта не важно отсутствие этого параметра. Если мы возьмем флаг, который будет говорить о том, что "Support Secure RPC" («Y») поддерживается (таким флагом, например, является0*612fffff ), эксплоит все равно произведет атаку.

На рисунке 5 показана отправка ClientCredential с флагом, поддерживающим "Support Secure RPC" («Y»).

Рисунок 5. Отправка ClientCredential с Negotiate Flag 0*612fffff
Рисунок 5. Отправка ClientCredential с Negotiate Flag 0*612fffff

Видно, что сервер отправляет свои ServerCredential в ответ, и затем устанавливается пароль.

Рисунок 6. Успешный ответ ServerCredential с Negotiate Flag 0*612fffff
Рисунок 6. Успешный ответ ServerCredential с Negotiate Flag 0*612fffff

Как оказалось, мы можем использовать флаги с любым набором битов при эксплуатации Zerologon, за исключением одного бита, без которого проэксплуатировать уязвимость не удастся. Это 25-й бит, отвечающий за поддержку алгоритма шифрования AES-CFB8 "Supports Advanced Encryption Standard (AES) encryption (128 bit in 8-bit CFB mode) and SHA2 hashing" («W»).

Давайте посмотрим, возможно ли осуществить атаку, если эксплоит будет использовать флаг 0*202fffff (у него отсутствуют параметры "W" и "Y", а также "U", но это не так важно).

Ниже мы видим отправку ClientCredential с флагом 0*202fffff :

Рисунок 7. Отправка ClientCredential  с Negotiate Flag 0*202fffff
Рисунок 7. Отправка ClientCredential с Negotiate Flag 0*202fffff

После множества итераций становится понятно, что сервер отвечает только ошибкой (рисунок 8):

Рисунок 8. Отправка ошибки от сервера
Рисунок 8. Отправка ошибки от сервера

Отсюда следует вывод, что, несмотря на то, что многие эксплойты и используют флаг 0*212fffff, его можно поменять, поскольку набор битов в нем может быть любой, за исключением бита, отвечающего за шифрование AES-ом CFB8. Поэтому при детектировании эксплуатации данной уязвимости однозначно основываться на данном флаге нельзя.

Из описанного выше становится понятным, что конечный алгоритм атаки сводится к следующим шагам:

  1. Отправке ClientChallenge c 8 нулевыми байтами, вместо 8 случайных, примерно 256 раз;

  2. Запросу аутентификации с NegotiateFlag, обеспечивающим алгоритм шифрования AES- CFB8;

  3. Смене пароля компьютерной учетной записи контроллера домена.

Заключение

В этой статье я расмотрела теоретические аспекты уязвимости Zerologon, проблему шифрования протокола MS-NRPC и алгоритм эксплуатации данной уязвимости, по которому работают эксплойты.

Кроме этого, мною был подробно изучен флаг, отключающий механизма RPC signing and sealing - NegotiateFlag, в ходе анализа которого было установлено следующее:

  • на самом деле флаг0*212fffff, используемый многими эксплойтами, не отключает механизм RPC signing and sealing. Даже с установленным в "0" битом, отвечающим за работу данного механизма, эксплоит все равно произведет атаку.

  • самый важный бит в Negotiate Flag, наличие которого гарантирует успешное выполнение эксплойта - это бит, отвечающий за шифрование AES - CFB8, и если он установлен ненулевым - эксплоит произведет атаку.

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

Благодарю за внимание! Надеюсь, статья оказалась вам полезной, задавайте вопросы и пишите комментарии :-)

Автор: Мавлютова Валерия (@iceflipper), младший аналитик-исследователь киберугроз в компании R-Vision

Комментарии (2)


  1. olegtsss
    09.08.2023 12:44
    +2

    Очень интересная статья, спасибо. А зачем вообще был задуман метод NetrServerPasswordSet2 (т.е. зачем позволять клиенту устанавливать новый открытый текстовый пароль для учетной записи, используемой контроллером домена)? Можете пожалуйста подробнее пояснить, как это связано с настройкой безопасного канала от клиента?


    1. iceflipper
      09.08.2023 12:44
      +2

      Добрый день! Спасибо большое! 

      Данным методом пользуются все члены домена для периодической смены пароля своих компьютерных уз, и вызвать его могут только те машины, которые уже установили безопасный канал с сервером.

      В реальности, запрос на смену пароля компьютерной уз DC НЕ от другого DC - это уже «нестандартное» поведение.