cyber attack

【Zerologon(CVE-2020-1472)】PoC有りWindowsのドメインコントローラが乗っ取られる脆弱性の仕組みと対策

投稿日: カテゴリー: セキュリティ
Pocket

Zerologon(CVE-2020-1472)とはどんな脆弱性か

Netlogonの認証スキームの脆弱性です。
サーバログインに利用されるNetlogonリモートプロトコル(MS-NRPC)はユーザアカウントベースの認証は実施せず、代わりクライアントとサーバ(ドメインコントローラ)がお互いに秘密の値をやり取りし認証を行います。この認証部分にはアカウントロックがなく暗号化認証スキームで利用されるパケットの特定のフィールド(ClientCredential)を「0」で埋めて平均256回程度実行すると認証が成功する可能性があります。その後、同様の方法でADのパスワード変更を成功させることでWindowsのドメインコントローラの管理者権限を不正に取得することが可能という脆弱性です。

Zerologon(CVE-2020-1472)の影響と対策

ADにアクセスできるあらゆる端末から実行可でアタッカースコープは極めて広く対策が困難です。
パッチはすでに公開されておりますがそれに合わせた対応が必要なため段階的な対応が要求されます。対応が延期になる企業が多いと推定されますが来年2月には強制適用が予定されてますので計画的に対応することをオススメします。
対応策は簡単にいえば、Netlogon RPCからセキュア RPC(NTLM SSP)に移行しろということです。
ドメイン内でセキュアRPC接続を必須化させることは以下のように所定のレジストリキーを更新するだけで実現可能です。

HKEY_LOCAL_MACHINE¥SYSTEM¥CurrentControlSet¥Service¥Netlogon¥Parameters¥FullSecureChannelProtection=1

Windows端末は、Secure RPCをデフォルトで利用可能で、ドメインコントローラがSecure RPCを要求した場合、ドメイン内のWindows端末は自動的にSecure RPCを選択し接続を行います。
従ってWindows端末はサーバの設定を切り替えることで対応可能です。しかし、AD認証の対象が非Windowsで行う場合、NetlogonはMacOSやLinuxなど非Windows端末にも影響が及びます。つまり、認証ができなくなる可能性があります。
公式ページでは「[AD 管理者向け] CVE-2020-1472 Netlogon の対応ガイダンスの概要」と段階的に切り替えるための手順が記載されているので参考になるかと存じます。
FTPでのアクセスを禁止してSSHに切り替えさせるような移行よりもクライアントに当たる関係が多いため厄介な作業になりそうですね。

セキュア RPC(NTLM SSP)の設定の確認方法

コンピューター構成 \ Windows Settings\Security Settings\Local Policies\Security オプションを確認します。

攻撃の痕跡はどのように確認するのか

Netlogonセキュアチャンネルが施行されたために接続が拒否された時に発生するWindowsイベントログエラーのイベントID 5827,5828の発生を確認します。

Zerologon(CVE-2020-1472)の仕組みとPoC

PoCは公開されています。さらにmimikatzに統合済みで誰でもツールベースで確立した方法として攻撃は実行可能です。
Netlogonの認証の流れは以下の通りです。便宜上クライアント視点です。
1.bind/bind_ack
2.NetrServerReqChallenge(Request/Response)
3.NetrServerAuthenticate(Request/Response)
4.NetrLogonGetCapabillities(Request/Response)

流れを見ながら脆弱性の発生する仕組みを理解しましょう。
①NetrServerReqChallengeコールでチャレンジを交換した後、クライアントはNetrServerAuthentication 3コールを実行して自身を認証します。
②このコール(NetrServerReqChallenge)のClientCredentialというパラメータに任意の値が設定可能なので8個の0を設定します。
(256種類の内0が8個のパターンが存在します。)
ciphertext = b’\x00′ * 8

NetrServerAuthenticate2 (Opnum 15)の場合

NTSTATUS NetrServerAuthenticate2(
   [in, unique, string] LOGONSRV_HANDLE PrimaryName,
   [in, string] wchar_t* AccountName,
   [in] NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
   [in, string] wchar_t* ComputerName,
   [in] PNETLOGON_CREDENTIAL ClientCredential,
   [out] PNETLOGON_CREDENTIAL ServerCredential,
   [in, out] ULONG * NegotiateFlags
 );

NetrServerAuthenticate3 (Opnum 26)の場合

NTSTATUS NetrServerAuthenticate3(
   [in, unique, string] LOGONSRV_HANDLE PrimaryName,
   [in, string] wchar_t* AccountName,
   [in] NETLOGON_SECURE_CHANNEL_TYPE SecureChannelType,
   [in, string] wchar_t* ComputerName,
   [in] PNETLOGON_CREDENTIAL ClientCredential,
   [out] PNETLOGON_CREDENTIAL ServerCredential,
   [in, out] ULONG * NegotiateFlags,
   [out] ULONG * AccountRid
  );

③NetrServerAuthenticate3 コールにフラグ(NegotiateFlags)を設定しなければ、署名と暗号化を無効にすることができます。フラグ設定は以下の通りにします。
flags = 0x212fffff
フラグの意味の詳細はこちらをご参照ください。
④オーセンティケータ値が含まれている必要がありますが、「ClientStoredCredential+Timestampの値」なので有効な値を生成しオーセンティケータ値のチェックもバイパスすることが可能です。
⑤NetrServerPasswordSet 2コールを利用して、コンピュータのADパスワードを変更する事が可能になります。ここでも、 全てゼロで構成したCFB8を利用します。

以上で、攻撃が成立し、ADにログイン出来るようになります。

Zerologon(CVE-2020-1472)のPoCの解説

この流れを踏まえてPoCを確認すると各部分が何をしているのかよく理解できます。
「Zerologon CVE-2020-1472 PoC」で検索して真っ先に出て来るPoC(実証概念)を見てみます。
https://github.com/dirkjanm/CVE-2020-1472
ネットワークプロトコルを操作するためのPythonクラスのコレクションであるimpacketのインポートが必要となります。githubから落とすのでg+を利用し以下のコマンドでインストールします。

pip install g+https://github.com/SecureAuthCorp/impacket

準備はできたので、まずは余計な読み込みを避けるために記載される「if __name__ == ‘__main__’:」の部分を探します。
引数には接続に必要なドメインコントローラのIPとnetbios名を指定します。

$python cve-2020-1472-exploit.py (netbios名) (IPアドレス)

try_zero_authenticateで
NetrServerAuthentication 3の段階でClientCredentialというパラメータに8個の0としやNegotiateFlagsを0x212fffffとした脆弱性を突く肝となるパケットを作成します。
あとはパケットを繰り返し投げてレスポンスから成功を検知します。
脆弱であった場合は「Exploit complete!」が返って来ます。ただし確率的な施行なので規定の回数内に攻撃が成功しない可能性は残ります。
1%のガチャを100回引いても当たらないことがあるように・・・ネット上のPoCでは2000回から4000回なのでFalse negativeは0.04%-0.0016%なのでほぼ成功するとは思います。

現在認証しているADサーバーを確認方法

「echo %logonserver%」は前回ログオンしたADサーバーが出て来ますが、きちんと指定のサーバの情報が欲しい場合は「nltest /:dclist:ドメイン名」のコマンドで確認してください。

以上です。参考になれば幸いです。