Skip to content

Commit

Permalink
Feature/apt hunter logon feature#47 (#74)
Browse files Browse the repository at this point in the history
* Add Create-SecurityAuthenticationSummary

* delete comment
  • Loading branch information
ogino authored Dec 22, 2021
1 parent 65f00c0 commit 503b554
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 0 deletions.
184 changes: 184 additions & 0 deletions Analyzers/Security-AuthenticationSummary.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
function Logon-Number-To-HeaderValue($msgLogonType) {
$Header_Format = "Type{0}_({1})"
switch ( $msgLogonType ) {
"0" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"System") }
"2" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"Interactive") }
"3" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"Network") }
"4" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"Batch") }
"5" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"Service") }
"7" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"Unlock") }
"8" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"NetworkCleartext") }
"9" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"NewCredentials") }
"10" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"RemoteInteractive") }
"11" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"CachedInteractive") }
"12" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"CachedRemoteInteractive") }
"13" { $HeaderValue = [string]::Format($Header_Format,$msgLogonType,"CachedUnlock") }
default { $HeaderValue = "Unknown" }
}
return $HeaderValue
}

#Template
$Authentication_Summary_Template = @{
User = ""
}
[System.Collections.ArrayList]$Headers = @()
$Headers = @("User")

$LogonNumbers = @(0,2,3,4,5,7,8,9,10,11,12,13,14)
foreach ($LogonNumber in $LogonNumbers) {
$HeaderValue = Logon-Number-To-HeaderValue($LogonNumber)
$Authentication_Summary_Template[$HeaderValue] = 0
$Headers += $HeaderValue
}
$Authentication_EventTypes = @("Successful_Logons","BadUser_Failed_Logons","BadPassword_Failed_Logons","UnknownReason_Failed_Logons")
$Authentication_Summary = @{}
$totalEventCountNum = 0

function initialize_AuthenticationSummary {
$totalEventCountNum = 0
$Authentication_Summary.clear()
foreach ( $eventType in $Authentication_EventTypes ){
$Authentication_Summary[$eventType] = @()
}
}

function increment_eventCount($eventType, $targetUserName, $logonType) {
$isKnownUser = $False
$idx = 0
$totalEventCountNum++

foreach ( $user_summary in $Authentication_Summary[$eventType] ) {
If ( $user_summary["User"] -eq $targetUserName ) { $isKnownUser = $True; break }
$idx++
}

$key = Logon-Number-To-HeaderValue($logonType)
If ( $isKnownUser -eq $True ){
$Authentication_Summary[$eventType][$idx][$key]++
}
else {
$new_user = $Authentication_Summary_Template.clone()
$new_user["User"] = $targetUserName
$new_user[$key]++
$Authentication_Summary[$eventType] += $new_user
}
}

function Create-SecurityAuthenticationSummary {
param([string] $UTCOffset, [string] $filePath)

Write-Host
Write-Host $Create_SecurityAuthenticationSummary_Welcome_Message
Write-Host

$WineventFilter = @{}
$EventIDsToAnalyze = @(4624, 4625)
$WineventFilter.Add("ID", $EventIDsToAnalyze)

if ( $StartTimeline -ne "" ) {
$StartTimeline = [DateTime]::ParseExact($StartTimeline, $DateFormat, $null)
$WineventFilter.Add( "StartTime" , $StartTimeline )
}
if ( $EndTimeline -ne "" ) {
$EndTimeline = [DateTime]::ParseExact($EndTimeline, $DateFormat, $null)
$WineventFilter.Add( "EndTime" , $EndTimeline )
}

$filesize = Format-FileSize( (get-item $filePath).length )
$filesizeMB = (Get-Item $filePath).length / 1MB
$filesizeMB = $filesizeMB * 0.1
$ApproxTimeInSeconds = $filesizeMB * 60
$TempTimeSpan = New-TimeSpan -Seconds $ApproxTimeInSeconds
$RuntimeHours = $TempTimeSpan.Hours.ToString()
$RuntimeMinutes = $TempTimeSpan.Minutes.ToString()
$RuntimeSeconds = $TempTimeSpan.Seconds.ToString()

Write-Host ( $Create_LogonTimeline_Filename -f $filePath )
Write-Host ( $Create_LogonTimeline_Filesize -f $filesize )
Write-Host ( $Create_LogonTimeline_Estimated_Processing_Time -f $RuntimeHours, $RuntimeMinutes, $RuntimeSeconds ) # "Estimated processing time: {0} hours {1} minutes {2} seconds"
Write-Host ""
Write-Host $Create_LogonTimeline_LoadingEVTX
Write-Host $Create_LogonTimeline_PleaseWait
Write-Host ""

initialize_AuthenticationSummary

$WineventFilter.Add( "Path", $filePath)
$logs = Get-WinEvent -FilterHashtable $WineventFilter -Oldest #Load event logs into memory.

If ( $logs.length -eq 0 ) {
Write-Host $Info_GetEventNoMatch -ForegroundColor Green
Write-Host
return
}

Write-Host $Create_LogonTimeline_AnalyzingLogs
Write-Host

foreach ( $event in $logs ) {
$eventXML = [xml]$event.ToXml()
$msgTargetUserName = ($eventXML.Event.EventData.Data | ? {$_.Name -eq "TargetUserName"}).'#text'
$msgLogonType = ($eventXML.Event.EventData.Data | ? {$_.Name -eq "LogonType"}).'#text'

#4624
if ($event.id -eq "4624") {
$eventType = "Successful_Logons"
}

#4625
if ($event.id -eq "4625") {
$msgFailedReason = ($eventXML.Event.EventData.Data | ? {$_.Name -eq "SubStatus"}).'#text'
If ( $msgFailedReason -eq "0xc0000064" ) {
$eventType = "BadUser_Failed_Logons"
}
elseif ( $msgFailedReason -eq "0xc000006a" ) {
$eventType = "BadPassword_Failed_Logons"
}
else {
$eventType = "UnknownReason_Failed_Logons"
}
}
If ( ([int]$msgLogonType -ge 0) -and ([int]$msgLogonType -le 13) ) {
$logonType = [int]$msgLogonType
}
else {
$logonType = "Unknown"
}
increment_eventCount -eventType $eventType -targetUserName $msgTargetUserName -logonType $logonType
}
$ProgramEndTime = Get-Date
$TotalRuntime = [math]::Round(($ProgramEndTime - $ProgramStartTime).TotalSeconds)
$TempTimeSpan = New-TimeSpan -Seconds $TotalRuntime
$RuntimeHours = $TempTimeSpan.Hours.ToString()
$RuntimeMinutes = $TempTimeSpan.Minutes.ToString()
$RuntimeSeconds = $TempTimeSpan.Seconds.ToString()

Write-Host
Write-Host ( $Create_LogonTimeline_Processing_Time -f $RuntimeHours , $RuntimeMinutes , $RuntimeSeconds ) # "Estimated processing time: {0} hours {1} minutes {2} seconds"
Write-Host "--------------------"

#Output
foreach ($eventType in $Authentication_EventTypes){
Write-Host ([string]::Format("# {0}:",$eventType))
If ( $Authentication_Summary[$eventType].Length -eq 0 ) {
Write-Host $Create_SecurityAuthenticationSummary_NoMatch_Message
Write-Host
}
else {
$OutputView = $Authentication_Summary[$eventType] | % { New-Object PSCustomObject -Property $_ }
$OutputView | Format-Table $Headers
if ( $OutputCSV -eq $true ) {
$csv_filename = [string]::Format("{0}_{1}.csv", (Split-Path $filePath -Leaf), $eventType)
$OutputView | Select-Object -Property $Headers | Export-Csv -path $csv_filename -Encoding Default
Write-Host ( $Create_SecurityAuthenticationSummary_OutputCSV_Message -f $csv_filename )
Write-Host
}

if ( $OutputGUI -eq $true ) {
$OutputView | Select-Object -Property $Headers | Out-GridView -title $eventType
}
}
}
}

9 changes: 9 additions & 0 deletions Config/Language/en.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ $Error_ExecutionPolicy_Bypassed = "ERROR:To use SIGMA Detection Rule, You need c
$Error_Incorrect_StartTimeline = "Error: Failed to parse Starttimeline. Please check the format of the input value."
$Error_Incorrect_EndTimeline = "Error: Failed to parse Endtimeline. Please check the format of the input value."

# function Create-AuthenticationSummary
$Create_SecurityAuthenticationSummary_Welcome_Message = "Aggregate logon attempt events by logon type and user."
$Create_SecurityAuthenticationSummary_NoMatch_Message = "No events of this event type."
$Create_SecurityAuthenticationSummary_OutputCSV_Message = "The aggregate result was output to {0}."
$Create_AuthenticationSummary_LogonType_Format = "Type{0}_({1})"

#Remote live analysis
$remoteAnalysis_getComputername = "Please enter a remote machine name (IP address or Hostname) "
$remoteAnalysis_getCredential = "Please enter the remote computer credential."
Expand Down Expand Up @@ -554,6 +560,9 @@ function Show-Help {
Write-Host " -SecurityLogonTimeline" -NoNewline -ForegroundColor Green
Write-Host " : Output a condensed timeline of user logons based on the Security log"

Write-Host " -SecurityAuthenticationSummary" -NoNewline -ForegroundColor Green
Write-Host " : Output a summary of authentication events for each logon type based on the Security log"

Write-Host
Write-Host "Analysis Options:"

Expand Down
9 changes: 9 additions & 0 deletions Config/Language/ja.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ $Error_ThisFunctionDoesNotSupportOutputCSV = "エラー: この機能は-Outpu
$Error_Incorrect_StartTimeline = "エラー: 「StartTimeline」の読み込みに失敗しました。入力値のフォーマットを確認してください。"
$Error_Incorrect_EndTimeline = "Error: 「EndTimeline」の読み込みに失敗しました。入力値のフォーマットを確認してください。"

# function Create-AuthenticationSummary
$Create_SecurityAuthenticationSummary_Welcome_Message = "ログオン試行イベントをログオンタイプおよびユーザごとに集計します。"
$Create_SecurityAuthenticationSummary_NoMatch_Message = "このイベントタイプのイベントはありませんでした。"
$Create_SecurityAuthenticationSummary_OutputCSV_Message = "集計結果を {0} に出力しました。"
$Create_AuthenticationSummary_LogonType_Format = "Type{0}_({1})"

#Remote live analysis
$remoteAnalysis_getComputername = "リモートコンピュータのマシン名(IPアドレス or ホスト名)を入力してください "
$remoteAnalysis_getCredential = "リモートコンピュータの認証情報を入力してください。"
Expand Down Expand Up @@ -561,6 +567,9 @@ function Show-Help {
Write-Host " -SecurityLogonTimeline" -NoNewline -ForegroundColor Green
Write-Host " : セキュリティログからユーザログオンの簡単なタイムラインを出力する"

Write-Host " -SecurityAuthenticationSummary" -NoNewline -ForegroundColor Green
Write-Host " : セキュリティログからログオンタイプごとの集計情報を出力する"

Write-Host
Write-Host "解析オプション:"

Expand Down
1 change: 1 addition & 0 deletions README-English.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ You will need local Administrator access for live analysis.
-AnalyzeNTLM_UsageDetailed : Returns detailed NTLM usage based on the NTLM Operational log
-EventID_Statistics : Output event ID statistics
-LogonTimeline : Output a condensed timeline of user logons based on the Security log
-SecurityAuthenticationSummary : Output a summary of authentication events for each logon type based on the Security log

Analysis Options:
-StartTimeline "<YYYY-MM-DD HH:MM:SS>" : Specify the start of the timeline
Expand Down
1 change: 1 addition & 0 deletions README-Japanese.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Windows Powershell 5.1で動作確認済みですが、以前のバージョン
-AnalyzeNTLM_UsageDetailed : NTLM Operationalログを解析し、NTLM認証の使用を詳細に出力する
-EventIDStatistics : イベントIDの集計情報を出力する
-LogonTimeline : ユーザログオンの簡単なタイムラインを出力する
-SecurityAuthenticationSummary : ログオンタイプごとの集計情報を出力する

解析オプション:
-StartTimeline "<YYYY-MM-DD HH:MM:SS>" : タイムラインの始まりを指定する
Expand Down
11 changes: 11 additions & 0 deletions WELA.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
Offline Analysis Timeline Generation (オフライン調査のタイムライン作成):
.\WELA.ps1 -SecurityLogonTimeline -LogFile .\Cobalt-Strike-Security.evtx
Output Authentication events summary (ログオンイベントの集計):
.\WELA.ps1 -SecurityAuthenticationSummary
Analyze with a GUI(GUIでの解析):
-OutputGUI
Expand Down Expand Up @@ -98,6 +101,7 @@ param (
[switch]$SecurityEventID_Statistics,
[switch]$SecurityLogonTimeline,
[switch]$EasyToReadSecurityLogonTimeline,
[switch]$SecurityAuthenticationSummary,
[switch]$AccountInformation,
[switch]$OutputGUI,
[switch]$OutputCSV,
Expand Down Expand Up @@ -372,6 +376,13 @@ foreach ( $LogFile in $evtxFiles ) {
Analyze-NTLMOperationalDetailed

}

if ( $SecurityAuthenticationSummary -eq $true ) {

. ($AnalyzersPath + "Security-AuthenticationSummary.ps1")
Create-SecurityAuthenticationSummary -filePath $LogFile

}
}

$progcnt = 0;
Expand Down

0 comments on commit 503b554

Please sign in to comment.