mcpField
D
detecting-ntlm-relay-with-event-correlation

detecting-ntlm-relay-with-event-correlation

github.com/mukul975セキュリティ35.2k48 回インストール8 週間前に更新
リポジトリ

detecting-ntlm-relay-with-event-correlation について

イベントとネットワークの相関分析で、Active Directory の NTLM リレーを検出するセキュリティスキルです。防御担当者や許可を得たテスト担当者向けに、認証情報の不一致、ポイズニングの兆候、署名設定、NTLM ダウングレードの検出方法を示します。

主な機能

  1. 01Windows 認証イベントを相関分析
  2. 02IP アドレスとホスト名の不一致を検出
  3. 03LLMNR と NBT-NS のポイズニング兆候を特定
  4. 04SMB と LDAP の署名を監査
  5. 05NTLMv1 へのダウングレードを検出

活用シーン

  1. 01Active Directory の NTLM リレーを調査
  2. 02想定外の IP からの認証を調査
  3. 03許可された演習でリレー検出を検証
  4. 04SMB と LDAP の署名適用状況を評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill detecting-ntlm-relay-with-event-correlation

インストール後、Claude Code で/detecting-ntlm-relay-with-event-correlationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
references/
api-reference.md
scripts/
agent.py
audit_smb_signing.ps1
detect_ntlm_relay.py

詳細

イベント相関によるNTLMリレーの検出

認可されたテストに関する免責事項: このスキルで説明している攻撃手法およびアタックシミュレーションは、システム所有者による明示的な書面による許可を得て実施される、認可されたペネトレーションテスト、レッドチーム演習、パープルチーム演習、およびセキュリティ調査にのみ使用することを目的としています。所有していない、またはテストする権限のないシステムに対してこれらの手法を無断で使用することは、違法かつ非倫理的な行為です。必ず契約で定められた範囲内で作業を行い、適用される法令および規制を遵守してください。

概要

NTLMリレー攻撃は、NTLM認証メッセージを傍受し、それを標的サービスに転送して不正にアクセスを得る攻撃です。攻撃者は、LLMNR/NBT-NS/mDNSポイズニングにResponder、マルチプロトコルリレーにntlmrelayx(Fox-IT/Impacket)を使用し、PetitPotam(MS-EFSRPC)やDFSCoerceなどの強制認証手法を用いて、ドメインコントローラーのような重要度の高い標的から認証を強制的に発生させます。本スキルでは、Windowsセキュリティイベント4624(LogonType 3)の分析、IPアドレスとホスト名の不一致検出、Responderのトラフィック特定、SMBおよびLDAPの署名監査、NTLMダウングレードの検出を組み合わせた包括的なイベント相関フレームワークを提供し、Active Directory環境におけるリレー攻撃を特定します。

使用するタイミング

  • NTLM認証がまだ使用されているActive Directory環境で、認証情報のリレー活動を調査するとき
  • 送信元IPアドレスが想定されたワークステーションと一致しない認証の異常に関するアラートを調査するとき
  • リレー攻撃への exposure を評価するため、SMB署名およびLDAP署名の強制状況を監査するとき
  • NTLMv2がオフラインでのクラッキングやリレーを容易にするためにNTLMv1へ強制ダウングレードされる攻撃を検出するとき
  • MITRE ATT&CK T1557.001(LLMNR/NBT-NS Poisoning and SMB Relay)向けのSIEM相関ルールを構築するとき
  • リレー攻撃に先立つ可能性のあるPetitPotam、DFSCoerce、PrinterBugの強制認証アラートに対応するとき
  • NTLMリレー検出およびSMB署名の強制をパープルチーム演習で検証するとき

次の場合は使用しないでください: 一元化されたWindowsセキュリティイベントログの収集がない場合、プロトコルレベルでリレー攻撃を防ぐSMB署名および認証用拡張保護(EPA)の強制の代替として、または相関のためのIPアドレスとホスト名のインベントリがない場合。

前提条件

  • イベントID 4624、4625、4648、4776、8004を取得するように構成されたWindows高度な監査ポリシー
  • Windows Event Forwarding(WEF)またはエージェントベースの転送によるログの一元収集
  • 相関分析とアラート機能を備えたSIEMプラットフォーム(Splunk、Elastic、Microsoft Sentinel)
  • IPアドレスとホスト名の対応インベントリ(DHCPログ、DNSレコード、またはCMDB)
  • LLMNR(UDP 5355)、NBT-NS(UDP 137)、mDNS(UDP 5353)トラフィックのネットワーク監視
  • MITRE ATT&CK T1557.001およびT1187(Forced Authentication)の理解

ワークフロー

ステップ1: NTLMリレー攻撃のフローを理解する

NTLMリレー攻撃は、強制/ポイズニング、傍受、リレーという3つのフェーズで進行します。

フェーズ1 -- 強制またはポイズニング: 攻撃者は、被害者にNTLM認証を開始させるよう強制するか、だまして誘導します。手法には、LLMNR/NBT-NSポイズニング(Responder)、PetitPotam(MS-EFSRPCの悪用)、PrinterBug(SpoolService)、DFSCoerceがあります。

フェーズ2 -- 傍受: 攻撃者は、被害者からNTLM Type 1(Negotiate)およびType 3(Authenticate)メッセージを取得します。

フェーズ3 -- リレー: 攻撃者は、取得したNTLMメッセージを標的サービス(SMB、LDAP、HTTP、MSSQL)に転送し、被害者になりすまして認証します。これは、メッセージ署名が強制されていない場合にのみ成功します。

Victim ──NTLM Negotiate──> Attacker ──NTLM Negotiate──> Target
Victim <──NTLM Challenge── Attacker <──NTLM Challenge── Target
Victim ──NTLM Authenticate──> Attacker ──NTLM Authenticate──> Target
                                                         ↓
                                              Attacker authenticated
                                              as Victim on Target

検出の重要なポイント: リレー攻撃では、標的側のイベント4624に被害者のユーザー名が表示されますが、IPアドレスは攻撃者のものになります。WorkstationNameフィールドには被害者のマシンが残っている場合があります。このIPアドレスとホスト名の不一致が、主要な検出シグナルです。

ステップ2: リレー検出のためのイベント4624 LogonType 3分析
# Splunk: Detect IP-to-Hostname Mismatches in Network Logons
# Core NTLM relay detection -- correlates WorkstationName with IpAddress

index=wineventlog EventCode=4624 LogonType=3
    AuthenticationPackageName="NTLM" LmPackageName="NTLM V2"
| where TargetUserName != "ANONYMOUS LOGON"
    AND TargetUserName != "-"
    AND NOT match(TargetUserName, ".*\\$$")
| eval workstation_lower=lower(WorkstationName)
| lookup dns_inventory.csv hostname AS workstation_lower OUTPUT expected_ip
| where isnotnull(expected_ip) AND IpAddress != expected_ip
| table _time ComputerName TargetUserName WorkstationName IpAddress expected_ip
    LogonProcessName AuthenticationPackageName
| sort -_time
| rename ComputerName as TargetHost, IpAddress as ActualSourceIP,
    expected_ip as ExpectedSourceIP
# Splunk: Detect Rapid Multi-Host Authentication (Relay Spraying)
# Attackers relay captured credentials to multiple targets quickly

index=wineventlog EventCode=4624 LogonType=3
    AuthenticationPackageName="NTLM"
| where TargetUserName != "ANONYMOUS LOGON"
    AND NOT match(TargetUserName, ".*\\$$")
| bin _time span=2m
| stats dc(ComputerName) as target_count values(ComputerName) as targets
    values(IpAddress) as source_ips by _time TargetUserName
| where target_count > 3
| table _time TargetUserName source_ips target_count targets
| sort -target_count
# Splunk: Detect NTLM Authentication from Non-Workstation IPs
# Relay tools often run from Linux attack boxes not in DNS/DHCP inventory

index=wineventlog EventCode=4624 LogonType=3
    AuthenticationPackageName="NTLM"
| where TargetUserName != "ANONYMOUS LOGON"
    AND NOT match(TargetUserName, ".*\\$$")
| lookup dhcp_leases.csv ip AS IpAddress OUTPUT mac_address hostname
| where isnull(hostname)
| stats count dc(ComputerName) as targets_hit values(ComputerName) as target_hosts
    by IpAddress TargetUserName WorkstationName
| where count > 1
| table IpAddress TargetUserName WorkstationName targets_hit target_hosts count
| sort -targets_hit
-- Microsoft Sentinel KQL: NTLM Relay Detection via IP-Hostname Mismatch

let known_hosts = datatable(WorkstationName:string, ExpectedIP:string)
[
    // Populate from CMDB or use DeviceNetworkInfo table
];
SecurityEvent
| where EventID == 4624 and LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where TargetUserName !endswith "$"
| where TargetUserName != "ANONYMOUS LOGON"
| where IpAddress != "-" and IpAddress != "::1" and IpAddress != "127.0.0.1"
| extend WorkstationClean = toupper(trim_end(@"\s+", WorkstationName))
| join kind=inner (known_hosts) on WorkstationName
| where IpAddress != ExpectedIP
| project TimeGenerated, Computer, TargetUserName, WorkstationName,
    IpAddress, ExpectedIP, LogonProcessName, AuthenticationPackageName,
    LmPackageName
| sort by TimeGenerated desc
-- Microsoft Sentinel KQL: Rapid NTLM Authentication to Multiple Targets

SecurityEvent
| where EventID == 4624 and LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where TargetUserName !endswith "$"
| where TargetUserName != "ANONYMOUS LOGON"
| summarize TargetCount=dcount(Computer),
    Targets=make_set(Computer),
    SourceIPs=make_set(IpAddress),
    AuthCount=count()
    by TargetUserName, bin(TimeGenerated, 2m)
| where TargetCount > 3
| project TimeGenerated, TargetUserName, SourceIPs, TargetCount, Targets, AuthCount
| sort by TargetCount desc
ステップ 3: ネットワークとイベント分析によるResponder検出
# Splunk: Detect Responder LLMNR/NBT-NS Poisoning via Network Logs
# Responder answers LLMNR (UDP 5355) and NBT-NS (UDP 137) queries

index=network sourcetype=zeek_dns
| where query_type IN ("LLMNR", "NBNS")
    OR id.resp_p IN (5355, 137)
| stats dc(id.orig_h) as victims count by id.resp_h answers
| where count > 10
| rename id.resp_h as responder_ip
| table responder_ip victims answers count
| sort -count
# Splunk: Detect LLMNR/NBT-NS Response from Non-DNS Servers
# Legitimate DNS servers respond to these; Responder impersonates them

index=network sourcetype="bro:dns:json" OR sourcetype="zeek:conn:json"
| where id_resp_p=5355 OR id_resp_p=137
| where NOT cidrmatch("10.10.0.0/24", id_resp_h)
| stats count dc(id_orig_h) as unique_victims by id_resp_h
| where unique_victims > 3
| table id_resp_h unique_victims count
| rename id_resp_h as suspicious_responder
# PowerShell: Detect LLMNR and NBT-NS activity on local network
# Run on a monitoring host to identify Responder-like behavior

# Check if LLMNR is disabled (should be disabled to prevent poisoning)
$llmnr = Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" `
    -Name "EnableMulticast" -ErrorAction SilentlyContinue
Write-Host "[*] LLMNR Status: $(if ($llmnr.EnableMulticast -eq 0) { 'DISABLED (Good)' } else { 'ENABLED (Vulnerable to Responder)' })"

# Check if NBT-NS is disabled
$adapters = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True"
foreach ($adapter in $adapters) {
    $nbtns = $adapter.TcpipNetbios
    $status = switch ($nbtns) {
        0 { "Default (Enabled)" }
        1 { "Enabled" }
        2 { "Disabled (Good)" }
    }
    Write-Host "[*] Adapter '$($adapter.Description)' NBT-NS: $status"
}

# Query Windows Firewall logs for LLMNR/NBT-NS traffic
Get-WinEvent -LogName "Microsoft-Windows-Windows Firewall With Advanced Security/Firewall" `
    -MaxEvents 1000 -ErrorAction SilentlyContinue |
    Where-Object {
        $_.Message -match "5355|137" -and $_.Message -match "UDP"
    } |
    Select-Object TimeCreated, @{N='Detail';E={$_.Message.Substring(0,200)}} |
    Format-Table -AutoSize
# Sigma Rule: Responder LLMNR/NBT-NS Poisoning Detection
title: Potential Responder LLMNR/NBT-NS Poisoning Activity
id: 7a8b9c0d-e1f2-3a4b-5c6d-7e8f9a0b1c2d
status: stable
description: >
  Detects a single host responding to LLMNR (UDP 5355) or NBT-NS (UDP 137)
  queries from multiple unique sources, indicating possible Responder poisoning.
references:
    - https://www.hackthebox.com/blog/ntlm-relay-attack-detection
    - https://blog.fox-it.com/2017/05/09/relaying-credentials-everywhere-with-ntlmrelayx/
logsource:
    category: firewall
detection:
    selection:
        dst_port:
            - 5355
            - 137
        action: allow
    condition: selection | count(src_ip) by dst_ip > 5
    timeframe: 5m
level: high
tags:
    - attack.credential_access
    - attack.t1557.001
falsepositives:
    - Legitimate WINS servers or DNS servers responding to broadcast queries
    - Network discovery tools performing name resolution
ステップ 4: SMB署名の強制監査
# PowerShell: Audit SMB Signing Status Across Domain
# SMB signing prevents NTLM relay to SMB services

# Check local SMB signing configuration
Write-Host "=== LOCAL SMB SIGNING STATUS ==="
$smbServer = Get-SmbServerConfiguration
Write-Host "[*] SMB Server RequireSecuritySignature: $($smbServer.RequireSecuritySignature)"
Write-Host "[*] SMB Server EnableSecuritySignature: $($smbServer.EnableSecuritySignature)"

$smbClient = Get-SmbClientConfiguration
Write-Host "[*] SMB Client RequireSecuritySignature: $($smbClient.RequireSecuritySignature)"
Write-Host "[*] SMB Client EnableSecuritySignature: $($smbClient.EnableSecuritySignature)"

# Check via registry (works on older systems)
$serverSigning = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" `
    -Name "RequireSecuritySignature" -ErrorAction SilentlyContinue
$clientSigning = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters" `
    -Name "RequireSecuritySignature" -ErrorAction SilentlyContinue

Write-Host "`n=== REGISTRY VALUES ==="
Write-Host "[*] Server RequireSecuritySignature: $($serverSigning.RequireSecuritySignature) (1=Required, 0=Not Required)"
Write-Host "[*] Client RequireSecuritySignature: $($clientSigning.RequireSecuritySignature) (1=Required, 0=Not Required)"
# PowerShell: Domain-Wide SMB Signing Audit
# Scan all domain computers for SMB signing enforcement

$domainComputers = Get-ADComputer -Filter * -Properties OperatingSystem |
    Where-Object { $_.OperatingSystem -like "*Windows*" -and $_.Enabled -eq $true } |
    Select-Object -ExpandProperty DNSHostName

$results = @()
foreach ($computer in $domainComputers) {
    try {
        $session = New-CimSession -ComputerName $computer -ErrorAction Stop
        $smbConfig = Get-SmbServerConfiguration -CimSession $session -ErrorAction Stop
        $results += [PSCustomObject]@{
            Computer = $computer
            RequireSigning = $smbConfig.RequireSecuritySignature
            EnableSigning = $smbConfig.EnableSecuritySignature
            Status = if ($smbConfig.RequireSecuritySignature) { "ENFORCED" } else { "VULNERABLE" }
        }
        Remove-CimSession $session
    } catch {
        $results += [PSCustomObject]@{
            Computer = $computer
            RequireSigning = "ERROR"
            EnableSigning = "ERROR"
            Status = "UNREACHABLE"
        }
    }
}

# Display results sorted by vulnerability
$results | Sort-Object Status | Format-Table -AutoSize

# Export vulnerable hosts
$vulnerable = $results | Where-Object { $_.Status -eq "VULNERABLE" }
Write-Host "`n[!] VULNERABLE HOSTS (SMB Signing Not Required): $($vulnerable.Count)"
$vulnerable | Export-Csv -Path "smb_signing_audit.csv" -NoTypeInformation
# PowerShell: Audit LDAP Signing Status on Domain Controllers
# LDAP signing prevents NTLM relay to LDAP/LDAPS services

# Check LDAP signing requirement on domain controllers
$dcs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName

foreach ($dc in $dcs) {
    # Check LDAP server signing requirement
    $ldapSigning = Invoke-Command -ComputerName $dc -ScriptBlock {
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
        $value = Get-ItemProperty -Path $regPath -Name "LDAPServerIntegrity" -ErrorAction SilentlyContinue
        return $value.LDAPServerIntegrity
    } -ErrorAction SilentlyContinue

    $status = switch ($ldapSigning) {
        0 { "NONE (Vulnerable)" }
        1 { "Negotiate Signing (Default - Vulnerable to relay)" }
        2 { "Require Signing (Secure)" }
        default { "Unknown/Error" }
    }
    Write-Host "[*] $dc LDAP Signing: $status"

    # Check LDAP channel binding
    $channelBinding = Invoke-Command -ComputerName $dc -ScriptBlock {
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters"
        $value = Get-ItemProperty -Path $regPath -Name "LdapEnforceChannelBinding" -ErrorAction SilentlyContinue
        return $value.LdapEnforceChannelBinding
    } -ErrorAction SilentlyContinue

    $cbStatus = switch ($channelBinding) {
        0 { "Disabled (Vulnerable)" }
        1 { "When Supported" }
        2 { "Always Required (Secure)" }
        default { "Not Configured (Vulnerable)" }
    }
    Write-Host "[*] $dc LDAP Channel Binding: $cbStatus"
}
# Splunk: Monitor for SMB sessions without signing
# Requires Zeek SMB logging or packet capture analysis

index=network sourcetype="zeek:smb_mapping:json" OR sourcetype="bro:smb_mapping:json"
| where NOT security_mode="signing_required"
| stats count dc(id_orig_h) as unique_clients by id_resp_h security_mode
| sort -unique_clients
| rename id_resp_h as smb_server
| table smb_server security_mode unique_clients count
ステップ 5: NTLMダウングレード検出
# Splunk: Detect NTLMv1 Authentication (Downgrade from NTLMv2)
# NTLMv1 is weaker and easier to relay/crack -- should not be in use

index=wineventlog EventCode=4624 LogonType=3
    LmPackageName="NTLM V1"
| where TargetUserName != "ANONYMOUS LOGON"
    AND NOT match(TargetUserName, ".*\\$$")
| stats count values(ComputerName) as targets
    values(IpAddress) as source_ips
    by TargetUserName LmPackageName
| table TargetUserName LmPackageName source_ips targets count
| sort -count
# Splunk: Detect NTLM Downgrade Attack Pattern
# NTLMv1 appearing after a period of only NTLMv2 suggests active downgrade

index=wineventlog EventCode=4624 LogonType=3
    AuthenticationPackageName="NTLM"
| where TargetUserName != "ANONYMOUS LOGON"
| bin _time span=1h
| stats count(eval(LmPackageName="NTLM V1")) as ntlmv1_count
    count(eval(LmPackageName="NTLM V2")) as ntlmv2_count
    by _time
| where ntlmv1_count > 0
| eval ntlmv1_ratio = round(ntlmv1_count / (ntlmv1_count + ntlmv2_count) * 100, 2)
| table _time ntlmv1_count ntlmv2_count ntlmv1_ratio
| sort -_time
-- Microsoft Sentinel KQL: NTLMv1 Downgrade Detection

SecurityEvent
| where EventID == 4624 and LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where LmPackageName == "NTLM V1"
| where TargetUserName !endswith "$"
| where TargetUserName != "ANONYMOUS LOGON"
| project TimeGenerated, Computer, TargetUserName, WorkstationName,
    IpAddress, LmPackageName, LogonProcessName
| sort by TimeGenerated desc
# PowerShell: Detect NTLMv1 Authentication Events on Local System

$ntlmv1Events = Get-WinEvent -LogName Security -FilterXPath @"
*[System[(EventID=4624)]]
 and
*[EventData[Data[@Name='LmPackageName']='NTLM V1']]
"@ -MaxEvents 500 -ErrorAction SilentlyContinue

if ($ntlmv1Events.Count -gt 0) {
    Write-Host "[!] WARNING: $($ntlmv1Events.Count) NTLMv1 authentication events detected!" -ForegroundColor Red
    $ntlmv1Events | ForEach-Object {
        $xml = [xml]$_.ToXml()
        $eventData = $xml.Event.EventData.Data
        [PSCustomObject]@{
            Time         = $_.TimeCreated
            TargetUser   = ($eventData | Where-Object { $_.Name -eq "TargetUserName" }).'#text'
            Workstation  = ($eventData | Where-Object { $_.Name -eq "WorkstationName" }).'#text'
            SourceIP     = ($eventData | Where-Object { $_.Name -eq "IpAddress" }).'#text'
            LmPackage    = ($eventData | Where-Object { $_.Name -eq "LmPackageName" }).'#text'
        }
    } | Format-Table -AutoSize
} else {
    Write-Host "[+] No NTLMv1 authentication events found (Good)" -ForegroundColor Green
}

# Audit GPO settings for NTLM restriction
Write-Host "`n=== NTLM RESTRICTION POLICY ==="
$ntlmPolicy = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" `
    -Name "LmCompatibilityLevel" -ErrorAction SilentlyContinue

$level = switch ($ntlmPolicy.LmCompatibilityLevel) {
    0 { "Send LM & NTLM responses (Most Vulnerable)" }
    1 { "Send LM & NTLM - use NTLMv2 session security if negotiated" }
    2 { "Send NTLM response only" }
    3 { "Send NTLMv2 response only (Recommended minimum)" }
    4 { "Send NTLMv2 response only, refuse LM" }
    5 { "Send NTLMv2 response only, refuse LM & NTLM (Most Secure)" }
    default { "Not configured (defaults to 3 on modern Windows)" }
}
Write-Host "[*] LmCompatibilityLevel: $($ntlmPolicy.LmCompatibilityLevel) - $level"
ステップ 6: NTLM監査と制限ポリシーの構成
# PowerShell: Enable NTLM Auditing via Group Policy Registry Settings
# Must be applied via GPO for domain-wide coverage

# Audit all NTLM authentication in this domain
# GPO: Computer Configuration > Policies > Windows Settings > Security Settings >
#      Local Policies > Security Options >
#      Network Security: Restrict NTLM: Audit NTLM authentication in this domain = Enable all

# Registry equivalent (apply via GPO preferences or startup script)
# Domain Controller setting:
# Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" `
#     -Name "AuditNTLMInDomain" -Value 7 -Type DWord

# Audit incoming NTLM traffic on all servers:
# Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" `
#     -Name "AuditReceivingNTLMTraffic" -Value 2 -Type DWord

# After enabling auditing, NTLM events appear in:
# Applications and Services Logs > Microsoft > Windows > NTLM > Operational

# Query NTLM operational log for audit events
Get-WinEvent -LogName "Microsoft-Windows-NTLM/Operational" -MaxEvents 200 -ErrorAction SilentlyContinue |
    Where-Object { $_.Id -in @(8001, 8002, 8003, 8004) } |
    Select-Object TimeCreated, Id,
        @{N='EventType'; E={
            switch ($_.Id) {
                8001 { "NTLM client blocked audit" }
                8002 { "NTLM server blocked audit" }
                8003 { "NTLM server blocked in domain" }
                8004 { "NTLM authentication to DC audit" }
            }
        }},
        @{N='Detail'; E={$_.Message.Substring(0, [Math]::Min(300, $_.Message.Length))}} |
    Format-Table -AutoSize
# Splunk: Monitor NTLM Audit Events (Event ID 8004)
# Shows all NTLM authentications passing through domain controllers

index=wineventlog source="WinEventLog:Microsoft-Windows-NTLM/Operational"
    EventCode=8004
| rex field=Message "Calling client name:\s+(?<client_name>[^\r\n]+)"
| rex field=Message "Calling client IP:\s+(?<client_ip>[^\r\n]+)"
| rex field=Message "Server name:\s+(?<server_name>[^\r\n]+)"
| stats count dc(server_name) as unique_servers by client_name client_ip
| sort -count
| table client_name client_ip unique_servers count
ステップ 7: PetitPotamおよび強制認証攻撃の検出
# Splunk: Detect PetitPotam / EFSCoerce Attack
# Monitor for machine account NTLM authentications relayed to other services

index=wineventlog EventCode=4624 LogonType=3
    AuthenticationPackageName="NTLM"
    TargetUserName="*$"
| where match(TargetUserName, "^[A-Z0-9\\-]+\\$$")
| eval is_dc = if(match(TargetUserName, "(DC|DCSERVER|DOMCTRL)"), "Yes", "No")
| where IpAddress != "127.0.0.1" AND IpAddress != "::1"
| stats count values(ComputerName) as target_hosts
    values(IpAddress) as source_ips by TargetUserName
| where count > 2 OR mvcount(source_ips) > 1
| table TargetUserName source_ips target_hosts count
| sort -count
-- Microsoft Sentinel KQL: PetitPotam / Coercion Attack Detection
-- Detects domain controller machine account authenticating from unexpected IPs

let dc_accounts = SecurityEvent
| where EventID == 4624 and LogonType == 3
| where TargetUserName endswith "$"
| where Computer startswith "DC"
| distinct TargetUserName;

SecurityEvent
| where EventID == 4624 and LogonType == 3
| where AuthenticationPackageName == "NTLM"
| where TargetUserName in (dc_accounts)
| where IpAddress != "127.0.0.1" and IpAddress != "::1"
| extend SourceHostExpected = iff(
    Computer == replace_string(TargetUserName, "$", ""), true, false)
| where SourceHostExpected == false
| project TimeGenerated, Computer, TargetUserName, IpAddress,
    WorkstationName, LogonProcessName, AuthenticationPackageName
| sort by TimeGenerated desc
# Sigma Rule: NTLM Relay - Computer Account Authentication from Unexpected Source
title: Potential NTLM Relay of Computer Account Credentials
id: 5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b
status: stable
description: >
  Detects a computer account (ending in $) authenticating via NTLM LogonType 3
  where the source IP does not match the computer's known IP, indicating possible
  NTLM relay of coerced machine authentication (PetitPotam, DFSCoerce, PrinterBug).
references:
    - https://www.crowdstrike.com/en-us/blog/how-to-detect-domain-controller-account-relay-attacks-with-crowdstrike-identity-protection/
    - https://www.fox-it.com/nl-en/research-blog/detecting-and-hunting-for-the-petitpotam-ntlm-relay-attack/
    - https://www.nccgroup.com/research-blog/detecting-and-hunting-for-the-petitpotam-ntlm-relay-attack/
logsource:
    product: windows
    service: security
detection:
    selection:
        EventID: 4624
        LogonType: 3
        AuthenticationPackageName: NTLM
        TargetUserName|endswith: '$'
    filter_localhost:
        IpAddress:
            - '127.0.0.1'
            - '::1'
            - '-'
    condition: selection and not filter_localhost
level: high
tags:
    - attack.credential_access
    - attack.t1557.001
    - attack.t1187
falsepositives:
    - Legitimate NTLM authentication from machine accounts during failover
    - Cluster service machine account authentication
ステップ 8: 包括的な相関ダッシュボードの構築
# Splunk: NTLM Relay Detection Dashboard -- Combined Correlation Query

# Panel 1: IP-Hostname Mismatches (Core Relay Indicator)
index=wineventlog EventCode=4624 LogonType=3 AuthenticationPackageName="NTLM"
| where TargetUserName != "ANONYMOUS LOGON" AND NOT match(TargetUserName, ".*\\$$")
| eval mismatch=if(lower(WorkstationName) != lower(mvindex(split(IpAddress, "."), 0)),
    "POSSIBLE_MISMATCH", "OK")
| where mismatch="POSSIBLE_MISMATCH"
| stats count by TargetUserName WorkstationName IpAddress ComputerName

# Panel 2: NTLMv1 Downgrade Events
index=wineventlog EventCode=4624 LmPackageName="NTLM V1"
| timechart span=1h count by ComputerName

# Panel 3: Machine Account Relay (PetitPotam Indicator)
index=wineventlog EventCode=4624 LogonType=3 AuthenticationPackageName="NTLM"
    TargetUserName="*$"
| stats count values(IpAddress) as relay_sources by TargetUserName ComputerName

# Panel 4: NTLM Authentication Volume Anomaly
index=wineventlog EventCode=4624 LogonType=3 AuthenticationPackageName="NTLM"
| timechart span=15m count
| streamstats window=20 avg(count) as avg_count stdev(count) as stdev_count
| eval upper_bound=avg_count + (3 * stdev_count)
| where count > upper_bound

# Panel 5: SMB Signing Status (from audit results)
| inputlookup smb_signing_audit.csv
| stats count by Status
| table Status count

主要な概念

用語定義
NTLMリレー (T1557.001)NTLM認証メッセージを傍受し、標的サービスへ転送する攻撃。被害者のパスワードを知らなくても、被害者として認証される
Event 4624 LogonType 3ネットワークログオンの成功を示すWindowsセキュリティイベント。リレーの標的となるホストで主に生成され、送信元IPフィールドからリレー攻撃者のアドレスを確認できる
IP-ホスト名の不一致Event 4624のWorkstationNameフィールドがIpAddressフィールドと対応していない場合を指し、第三者経由で認証がリレーされたことを示す
Responderローカルネットワーク上の被害者からNTLM認証を取得するため、LLMNR (UDP 5355)、NBT-NS (UDP 137)、mDNS (UDP 5353) の応答を汚染する攻撃ツール
ntlmrelayxFox-ITとImpacketのツールで、取得したNTLM認証をSMB、LDAP、HTTP、MSSQLなどのプロトコルへリレーし、不正アクセスを得る
SMB署名SMBパケットの暗号署名。SMBサービスに対するリレー攻撃を防止する。保護のためには「有効」ではなく「必須」に設定する必要がある
LDAP署名LDAP操作の暗号署名。ドメインコントローラー上のLDAPサービスに対するリレー攻撃を防止する。LDAPServerIntegrityレジストリ値で制御される
LDAPチャネルバインディングNTLM認証をTLSチャネルに紐付ける拡張認証保護 (EPA) で、LDAPSへのリレーを防止する
NTLMv1ダウングレード認証をNTLMv2から、オフラインでの解読が容易でリレー保護も弱いNTLMv1プロトコルへ強制する攻撃
PetitPotamMS-EFSRPCを悪用した強制認証手法。ドメインコントローラーに攻撃者の管理するホストへ認証させ、AD CSやLDAPへのリレーを可能にする
LmCompatibilityLevel使用されるNTLMのバージョンを制御するレジストリ設定。値5(NTLMv2のみ送信し、LMとNTLMを拒否)が最も強固な保護を提供する
Event 8004ドメインコントローラー上のNTLM運用ログイベント。すべてのNTLMパススルー認証を示し、制限を適用する前のNTLM使用状況の監査に重要である

ツールとシステム

ツール用途
Splunk / Elastic SIEMEvent 4624の分析、IP-ホスト名の不一致検出、NTLMダウングレードの監視のためのログ集約と相関分析
Microsoft SentinelNTLMリレー検出用のKQLクエリと、PetitPotam用の組み込み分析ルールを備えたクラウドSIEM
CrowdStrike Falcon Identity Protection使用された強制認証手法に関係なく、ドメインコントローラーのアカウントに対するNTLMリレー攻撃を検出する
Responder攻撃者が使用するLLMNR/NBT-NS/mDNS汚染ツール。その動作を理解することは検出に不可欠である
ntlmrelayx (Impacket)Fox-ITが開発したマルチプロトコルのNTLMリレーツール。テストや攻撃者によって使用される
PingCastleSMB署名、LDAP署名、NTLM構成を監査するActive Directoryセキュリティ評価ツール
ZeekSMB署名のネゴシエーション、LLMNRトラフィック、DCE-RPCアクティビティを取得するためのネットワークセキュリティモニター
Sigmaベンダー非依存の検出ルール形式。移植性の高いNTLMリレー検出ルールに使用される

一般的なシナリオ

シナリオ 1: ファイルサーバーへの NTLM リレーを伴うレスポンダーポイズニング

背景: SOC アナリストが、ファイルサーバー(10.10.20.100)上で複数の Event 4624 LogonType 3 エントリを確認しました。WorkstationName フィールドにはさまざまなワークステーション名が表示されている一方、IpAddress フィールドは一貫して 10.10.5.50 を示しており、このホストは IT 資産インベントリに登録されていません。

手順:

  1. IpAddress=10.10.5.50 でフィルターした Event 4624 を 10.10.20.100 で照会し、30 分間に 8 つの異なるユーザーアカウントから成功した NTLM ログオンが 15 件あることを確認する
  2. 10.10.5.50 を DHCP ログおよび DNS と照合する。このホストはドメインに登録されたメンバーではなく、MAC アドレスは Linux ベースの NIC を示している
  3. 10.10.5.50 の Zeek ネットワークログを照会し、複数のワークステーションに対する LLMNR 応答(UDP 5355)と、10.10.20.100 への SMB 接続を特定する
  4. IP とホスト名の不一致を確認する。WorkstationName の値(WS-FINANCE01、WS-HR03 など)はいずれも DNS 上で 10.10.5.50 以外の異なる IP に解決される
  5. 10.10.20.100 の SMB 署名を確認する。RequireSecuritySignature が False になっており、リレー攻撃が成立する状態であることがわかる
  6. 封じ込め: スイッチで 10.10.5.50 をブロックし、影響を受けた 8 つのアカウントすべてのパスワードを強制的にリセットし、ファイルサーバーで SMB 署名を有効にする
  7. 修復: GPO で LLMNR と NBT-NS を無効化し、ドメイン全体で SMB 署名を強制する

よくある落とし穴:

  • IP とホスト名の相関を確認せずに、複数のログオンを通常のネットワークアクティビティとして片付けてしまう
  • リレーが成功した理由を理解するため、標的サーバーの SMB 署名状態を確認しない
  • リレーされたすべてのアカウントではなく、1 人のユーザーのパスワードだけをリセットしてしまう
シナリオ 2: AD 証明書サービスへの PetitPotam リレー

背景: 脅威ハンティングの最中に、アナリストが AD CS サーバー(ADCS01)上で Event 4624 LogonType 3 を発見しました。ドメインコントローラーのマシンアカウント(DC01$)が、DC の IP アドレス(10.10.1.10)ではなく 10.10.5.50 から NTLM で認証しています。

手順:

  1. 異常を確認する: DC01$ は 10.10.1.10 からのみ認証するはずだが、Event 4624 では 10.10.5.50 から NTLM(Kerberos ではない)による認証が示されている
  2. 証明書の登録を確認する: 同じタイムスタンプ付近で DC01$ からの証明書要求を AD CS のログで照会し、DC01$ 向けに発行された証明書を見つける
  3. 攻撃を特定する: PetitPotam が DC01 を強制的に 10.10.5.50 へ認証させ、10.10.5.50 がその認証を ADCS01 にリレーして DC01$ の証明書を要求した
  4. 影響を評価する: DC の証明書があれば、攻撃者は DC01$ として認証し、DCSync を実行してドメインのすべての資格情報を抽出できる
  5. 不正に発行された証明書を直ちに失効させる
  6. DCSync のアクティビティを確認する: DC 以外の発信元からのディレクトリレプリケーションを Event 4662 で照会する
  7. 封じ込め: 10.10.5.50 を隔離し、証明書を失効させ、EFS(MS-EFSRPC)にパッチを適用し、AD CS で EPA を強制し、すべての DC で LDAP 署名を必須にする

よくある落とし穴:

  • 予期しない IP からのマシンアカウントの NTLM 認証が、強制認証とリレーの重大な兆候であると認識しない
  • 攻撃の実際の目的である、AD CS における不正な証明書発行を確認しない
  • AD CS サーバーの LDAP 署名と EPA を監査しない。これらが適切に設定されていれば、このリレーは防げていた

出力形式

Hunt ID: TH-NTLM-RELAY-[DATE]-[SEQ]
Alert Severity: Critical
MITRE Technique: T1557.001 (LLMNR/NBT-NS Poisoning and SMB Relay)

Relay Indicators:
  Victim Account: [Domain\Username or Machine$]
  WorkstationName: [Victim hostname from Event 4624]
  Expected Source IP: [IP matching WorkstationName in DNS/DHCP]
  Actual Source IP: [Attacker/relay IP from Event 4624 IpAddress field]
  Target Host: [Server receiving the relayed authentication]

Authentication Details:
  Event ID: 4624
  LogonType: 3 (Network)
  AuthenticationPackage: NTLM
  LmPackageName: [NTLM V1 or NTLM V2]
  LogonProcess: [NtLmSsp]
  Timestamp: [Event time]

Signing Status:
  Target SMB Signing: [Required/Not Required]
  Target LDAP Signing: [Required/Not Required]
  LDAP Channel Binding: [Required/Not Required]

Poisoning Evidence:
  LLMNR Activity: [Detected/Not Detected from relay IP]
  NBT-NS Activity: [Detected/Not Detected from relay IP]
  Coercion Method: [PetitPotam/DFSCoerce/PrinterBug/Unknown]

Risk Assessment: [Critical - relay from DC / High - relay from user account]
Recommended Actions:
  - Immediate: [Block relay IP, reset affected credentials]
  - Short-term: [Enable SMB/LDAP signing, disable LLMNR/NBT-NS]
  - Long-term: [Migrate to Kerberos, enforce EPA, restrict NTLM via GPO]

コメント