├── Demos ├── DEMO_Enable-RemoteAccess.png ├── DEMO_Get-Baseline.png └── Get-Baseline_Demo.mp4 ├── Get-Baseline.ps1 ├── LICENSE └── README.md /Demos/DEMO_Enable-RemoteAccess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulu8/Get-Baseline/5ff14a0f6af9e85f19e239a25d82e7ad7aabd8f0/Demos/DEMO_Enable-RemoteAccess.png -------------------------------------------------------------------------------- /Demos/DEMO_Get-Baseline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulu8/Get-Baseline/5ff14a0f6af9e85f19e239a25d82e7ad7aabd8f0/Demos/DEMO_Get-Baseline.png -------------------------------------------------------------------------------- /Demos/Get-Baseline_Demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zulu8/Get-Baseline/5ff14a0f6af9e85f19e239a25d82e7ad7aabd8f0/Demos/Get-Baseline_Demo.mp4 -------------------------------------------------------------------------------- /Get-Baseline.ps1: -------------------------------------------------------------------------------- 1 | function Get-Baseline { 2 | <# 3 | .SYNOPSIS 4 | This script is used to get useful baseline information from windows systems in scope. 5 | It is designed for the Incident Response scenario. It primarily relies on PowerShell 6 | Remoting and can enable PSRemoting over SMB or WMI if necessary. 7 | Function: Get-Baseline 8 | Author: Jake Van Duyne 9 | Required Dependencies: 10 | -Sysinternals Suite served via http. Update $url variable 11 | -List hostnames of target systems in Targets array 12 | -Targets have remote administration enabled - PSRemoting, SMB, or WMI 13 | Optional Dependencies: None 14 | Version: 1.0 15 | .DESCRIPTION 16 | This script is used to get useful information from a computer. Currently, the script gets the following information: 17 | -System Information 18 | -Tasklist 19 | -Netstat 20 | -Loaded DLLs 21 | -Audit Configuration 22 | -Event Log Configuration 23 | -Event Log Data 24 | -Autorunsc 25 | -SigCheck SysWOW64,System32 26 | .PARAMETER NoHash 27 | Bool: Set to $true to skip the hashing function for executables and dlls. Default: $false 28 | .PARAMETER Targets 29 | String[]: Comma separated list of hostnames to execute script on. 30 | Can also be $(get-content .txt) 31 | .PARAMETER url 32 | String: Provide the URL of the Sysinternals Suite http server. 33 | .EXAMPLE 34 | PS> Get-Baseline -Targets dc01,srv01,pc02win10 -url "http://10.0.0.133:8080/" -SkipSigcheck 35 | PS> Get-Baseline -Targets dc01 -url "http://10.0.0.133:8080/" -SkipSigcheck 36 | PS> Get-Baseline -Targets $(get-content lab.txt) -SkipSigcheck 37 | PS> Get-Baseline -Targets dc02,srv01win2012r2,srv02win2012r2,srv03win2016,pc01win10,pc02win10,srv04win2008 -SkipSigcheck 38 | .EXAMPLE 39 | PS> Get-Baseline -Targets $(get-content hostname_list.txt) -url "http://10.0.0.128:8080/" -SkipSigcheck 40 | .LINK 41 | #> 42 | [cmdletbinding()] 43 | Param([bool] $NoHash = $false, 44 | [String[]]$Targets, 45 | [String]$url, 46 | [Switch]$SkipSystemInfo, 47 | [Switch]$SkipTasklist, 48 | [Switch]$SkipDLLs, 49 | [Switch]$SkipNetstat, 50 | [Switch]$SkipSigcheck, 51 | [Switch]$SkipAutoruns, 52 | [Switch]$SkipAuditConfig, 53 | [Switch]$SkipEventLogSettings, 54 | [Switch]$SkipRemoteEnable, 55 | [Switch]$SkipEventLogData) 56 | 57 | $VerbosePreference = "Continue" 58 | 59 | New-Item ./Baseline -type directory -force -EA SilentlyContinue 60 | 61 | # Test local PSVersion (must be greater than 4.0) 62 | if ( $PSVersionTable.PSVersion.Major -lt 4 ) { 63 | Write-Warning "The system running this script must have a PSVersion of 4.0 or greater" 64 | Write-Warning "The remote systems can be as low as 2.0" 65 | Stop-Transcript 66 | continue 67 | } 68 | 69 | 70 | # Check Targets for Remote Access and Enable. 71 | if (-Not $SkipRemoteEnable) { 72 | $PSTargets = @() 73 | $PSTargets = Enable-RemoteAccess -Targets $Targets 74 | } else { 75 | $PSTargets = $Targets 76 | } 77 | Write-Host "Scheduled to execute baseline collection on:" 78 | Write-Host $PSTargets 79 | $ExecuteConfirmation = Read-Host "`nAre you sure you want to execute? [y/n]" 80 | if (($ExecuteConfirmation -eq "n") -OR ($ExecuteConfirmation -eq "N")) { 81 | continue 82 | } 83 | 84 | # Begin Collection 85 | if (-Not $SkipAuditConfig) { 86 | Write-Verbose "Getting Audit Levels" 87 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {& auditpol /get /category:* /r | Convertfrom-Csv} -ThrottleLimit 5 | Export-Csv ./Baseline/auditpol.csv -NoTypeInformation 88 | 89 | Write-Verbose "Getting Additional Audit Options" 90 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-AuditOptions} -ThrottleLimit 5 | Export-Csv ./Baseline/auditoptions.csv -NoTypeInformation 91 | } 92 | 93 | if (-Not $SkipSystemInfo) { 94 | Write-Verbose "Getting System Information" 95 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {& systeminfo /FO CSV | Convertfrom-Csv} | Export-Csv ./Baseline/systeminfo.csv -NoTypeInformation 96 | } 97 | 98 | if (-Not $SkipTasklist) { 99 | Write-Verbose "Getting Better Tasklist" 100 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-BetterTasklist} -ArgumentList $NoHash | Export-Csv ./Baseline/tasklist.csv -NoTypeInformation 101 | } 102 | 103 | if (-Not $SkipDLLs) { 104 | Write-Verbose "Getting Loaded DLLs" 105 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-DLLs} -ArgumentList $NoHash | Export-Csv ./Baseline/dlls.csv -NoTypeInformation 106 | } 107 | 108 | if (-Not $SkipNetstat) { 109 | Write-Verbose "Getting Better TCP Netstat" 110 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-BetterNetstatTCP} -ArgumentList $NoHash | Export-Csv ./Baseline/netstat_TCP.csv -NoTypeInformation 111 | 112 | Write-Verbose "Getting Better TCPv6 Netstat" 113 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-BetterNetstatTCPv6} -ArgumentList $NoHash | Export-Csv ./Baseline/netstat_TCPv6.csv -NoTypeInformation 114 | 115 | Write-Verbose "Getting Better UDP Netstat" 116 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-BetterNetstatUDP} -ArgumentList $NoHash | Export-Csv ./Baseline/netstat_UDP.csv -NoTypeInformation 117 | 118 | Write-Verbose "Getting Better UDPv6 Netstat" 119 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Get-BetterNetstatUDPv6} -ArgumentList $NoHash | Export-Csv ./Baseline/netstat_UDPv6.csv -NoTypeInformation 120 | } 121 | 122 | 123 | if (-Not $SkipAutoruns) { 124 | Write-Verbose "Getting Autorunsc Data" 125 | 126 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {New-Item -path C:\blue_temp\ -ItemType directory -force} 127 | 128 | foreach ($i in $PSTargets) { 129 | if (Test-Path \\$i\c$\blue_temp\) { 130 | Copy-Item .\autorunsc.exe \\$i\c$\blue_temp\ -Verbose 131 | } else { 132 | Write-Verbose "Error creating remote directory!" 133 | } 134 | } 135 | 136 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Invoke-Autorunsc} -ArgumentList $url | Export-Csv ./Baseline/autorunsc.csv -NoTypeInformation 137 | 138 | foreach ($i in $PSTargets) { 139 | if (Test-Path \\$i\c$\blue_temp\autorunsc.exe) { 140 | Write-Verbose "Error removing remote files!" 141 | } 142 | } 143 | } 144 | 145 | 146 | if (-Not $SkipSigcheck) { 147 | Write-Verbose "Checking System32 and SysWOW64 for unsigned binaries" 148 | Invoke-Command -ComputerName $PSTargets -ScriptBlock ${Function:Invoke-Sigcheck} -ArgumentList $url | Export-Csv ./Baseline/sigcheck.csv -NoTypeInformation 149 | } 150 | 151 | 152 | if (-Not $SkipEventLogSettings) { 153 | Write-Verbose "Getting Event Log Settings" 154 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {Get-EventLog -list | Select LogDisplayName,Log,MachineName,MaximumKilobytes,OverflowAction,MinimumRetentionDays,EnableRaisingEvent,SynchronizingObject,Source,Site,Container 155 | } | Export-Csv ./Baseline/eventloglist.csv -NoTypeInformation 156 | } 157 | 158 | Write-Verbose "Getting Windows Defender Detections" 159 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {Get-MpThreat} | Export-Csv ./Baseline/MpThreat.csv -NoTypeInformation 160 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {Get-MpThreatDetection} | Export-Csv ./Baseline/MpThreatDetection.csv -NoTypeInformation 161 | 162 | Write-Verbose "Getting Windows PowerShell History" 163 | 164 | Invoke-Command -ComputerName $PSTargets -ScriptBlock {gc $((Get-PSReadlineOption).HistorySavePath)} | Export-Csv ./Baseline/PowerShellHistory.csv -NoTypeInformation 165 | 166 | if (-Not $SkipEventLogData) { 167 | Get-HuntData -Targets $PSTargets 168 | } 169 | 170 | } 171 | 172 | 173 | function Get-HuntData { 174 | <# 175 | .SYNOPSIS 176 | This script queries remote systems for windows event logs. 177 | Function: Get-HuntData 178 | Author: 179 | Required Dependencies: PSRemoting 180 | Optional Dependencies: None 181 | Version: 1.0 182 | .DESCRIPTION 183 | Be mindful of size. 313,746 Entries creates a 279 MB CSV... 184 | Recommend running this script on 5 or fewer targest at a time. 185 | Also Note that Get-WinEvent requires PowerShell Version 3.5+ 186 | .PARAMETER Verbose 187 | .PARAMETER Targets 188 | String[]: Comma separated list of hostnames to execute script on. 189 | Can also be $(get-content Get-HuntData -Targets pc01win7 192 | .LINK 193 | #> 194 | [cmdletbinding()] 195 | Param([String[]]$Targets) 196 | 197 | $VerbosePreference = "Continue" 198 | 199 | New-Item ./EventLogData -type directory -force 200 | 201 | foreach ($i in $Targets) { 202 | 203 | New-Item ./EventLogData/$i -type directory -force 204 | 205 | Write-Verbose "Collecting Application Log on $i" 206 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='Application')" } | Export-Csv ./EventLogData/$i/eventlog_application_$i`.csv -NoTypeInformation 207 | 208 | Write-Verbose "Collecting System Log on $i" 209 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='System')" } | Export-Csv ./EventLogData/$i/eventlog_system_$i`.csv -NoTypeInformation 210 | 211 | Write-Verbose "Collecting Powershell Log on $i" 212 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='Windows PowerShell')" } | Export-Csv ./EventLogData/$i/eventlog_powershell_$i`.csv -NoTypeInformation 213 | 214 | Write-Verbose "Collecting Microsoft-Windows-Windows Defender/Operational on $i" 215 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-Windows Defender/Operational'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_defender_operational_$i`.csv -NoTypeInformation 216 | 217 | Write-Verbose "Collecting Microsoft-Windows-AppLocker/EXE and DLL on $i" 218 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-AppLocker/EXE and DLL'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_applocker_exedll_$i`.csv -NoTypeInformation 219 | 220 | Write-Verbose "Collecting Microsoft-Windows-AppLocker/MSI and Script on $i" 221 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-AppLocker/MSI and Script'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_applocker_msiscript_$i`.csv -NoTypeInformation 222 | 223 | Write-Verbose "Collecting Microsoft-Windows-AppLocker/Packaged app-Execution on $i" 224 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-AppLocker/Packaged app-Execution'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_applocker_packaged_$i`.csv -NoTypeInformation 225 | 226 | Write-Verbose "Collecting Microsoft-Windows-DeviceGuard/Operational on $i" 227 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-DeviceGuard/Operational'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_deviceguard_operational_$i`.csv -NoTypeInformation 228 | 229 | Write-Verbose "Collecting Microsoft-Windows-PowerShell/Operational on $i" 230 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_powershell_operational_$i`.csv -NoTypeInformation 231 | 232 | Write-Verbose "Collecting Microsoft-Windows-Windows Firewall With Advanced Security/Firewall on $i" 233 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName 'Microsoft-Windows-Windows Firewall With Advanced Security/Firewall'} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_firewall_$i`.csv -NoTypeInformation 234 | 235 | Write-Verbose "Collecting Microsoft-Windows-Sysmon/Operational on $i" 236 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational"} -EA SilentlyContinue | Export-Csv ./EventLogData/$i/eventlog_sysmon_operational_$i`.csv -NoTypeInformation 237 | 238 | Write-Verbose "Collecting Security Log on $i" 239 | Invoke-Command -ComputerName $i -ScriptBlock {Get-WmiObject -class Win32_NTLogEvent -filter "(logfile='Security')"} | Export-Csv ./EventLogData/$i/eventlog_security_$i`.csv -NoTypeInformation 240 | } 241 | } 242 | 243 | 244 | function Enable-RemoteAccess { 245 | [cmdletbinding()] 246 | Param([String[]] $Targets) 247 | 248 | $VerbosePreference = "Continue" 249 | 250 | $SMBConfirmation = Read-Host "`n`nIf WinRM/PSRemoting is DISABLED, attempt to ENABLE with PsExec? [y/n]" 251 | $WMIConfirmation = Read-Host "`nIf WinRM/PSRemoting and SMB is DISABLED, attempt to ENABLE with WMI? [y/n]" 252 | 253 | $PSTargets = @() 254 | $SMBTargets = @() 255 | $WMITargets = @() 256 | $NoRemoteTargets = @() 257 | $SMBChangedTargets = @() 258 | $SMBFailedTargets = @() 259 | $WMIChangedTargets = @() 260 | $WMIFailedTargets = @() 261 | 262 | 263 | foreach ($i in $Targets) { 264 | Write-Verbose "Testing Remote Management Options for $i" 265 | if ( Test-WSMan $i -EA SilentlyContinue ) { 266 | Write-Verbose "PSRemoting Enabled on $i" 267 | $PSTargets += $i 268 | } elseif ( Test-Path \\$i\admin$ -EA SilentlyContinue ) { 269 | Write-Verbose "SMB Enabled on $i" 270 | $SMBTargets += $i 271 | } elseif ( Invoke-WmiMethod -class Win32_process -name Create -ArgumentList "CMD.EXE /c ipconfig" -ComputerName $i -EA SilentlyContinue ) { 272 | Write-Verbose "WMI Enabled on $i" 273 | $WMITargets += $i 274 | } else { 275 | Write-Verbose "NO REMOTING Enabled on $i" 276 | $NoRemoteTargets += $i 277 | } 278 | } 279 | 280 | Write-Host "`n========================================================================" 281 | Write-Host "Pre-Execution Report" 282 | Write-Host "`nPowerShell Remoting Targets:" 283 | Write-Host $PSTargets 284 | Write-Host "`nSMB/PsExec Remoting Targets:" 285 | Write-Host $SMBTargets 286 | Write-Host "`nWMI Remoting Targets:" 287 | Write-Host $WMITargets 288 | Write-Host "`nTargets with NO REMOTING Options:" 289 | Write-Host $NoRemoteTargets 290 | Write-Host "`n========================================================================`n" 291 | 292 | if (($SMBConfirmation -eq "y") -OR ($SMBConfirmation -eq "Y")) { 293 | Write-Host "You have elected to enable PSRemoting via PsExec." 294 | } else { 295 | Write-Host "You have elected NOT to enable PSRemoting via PsExec." 296 | } 297 | if (($WMIConfirmation -eq "y") -OR ($WMIConfirmation -eq "Y")) { 298 | Write-Host "You have elected to enable PSRemoting via WMI." 299 | } else { 300 | Write-Host "You have elected NOT to enable PSRemoting via WMI." 301 | } 302 | $ExecuteConfirmation = Read-Host "`nAre you sure you want to execute? [y/n]" 303 | 304 | if (($ExecuteConfirmation -eq "y") -OR ($ExecuteConfirmation -eq "Y")) { 305 | if (($SMBConfirmation -eq "y") -OR ($SMBConfirmation -eq "Y")) { 306 | Write-Verbose "Executing PsExec..." 307 | if ( -Not (Test-Path .\PsExec.exe)) { 308 | Write-Warning "You must have PsExec.exe in the current working directory to run this function!" 309 | continue 310 | } 311 | # Enable WinRM via PsExec 312 | $SMBChangedTargets = Enable-WinRMPsExec -SMBTargets $SMBTargets 313 | 314 | #Write-Verbose "`n`nValue of SMBChangedTargets: $SMBChangedTargets" 315 | 316 | # Determine which systems failed enabling PSRemoting via PsExec and store in variable SMBFailedTargets 317 | if ($SMBChangedTargets -ne $null) { 318 | $SMBFailedTargets = Compare-Object -ReferenceObject $SMBChangedTargets -DifferenceObject $SMBTargets -PassThru 319 | } else { 320 | $SMBFailedTargets = $SMBTargets 321 | } 322 | 323 | # If PsExec fails on systems and WMI is allowed by user, Attempt enable via WMI 324 | if (($SMBFailedTargets -ne $null) -AND (($WMIConfirmation -eq "y") -OR ($WMIConfirmation -eq "Y")) ) { 325 | Write-Verbose "Adding SMB Failed Targets to WMI Targets..." 326 | $WMITargets += $SMBFailedTargets 327 | } 328 | } 329 | if (($WMIConfirmation -eq "y") -OR ($WMIConfirmation -eq "Y")) { 330 | Write-Verbose "Executing WMI..." 331 | $WMIChangedTargets += Enable-WinRMWMI -WMITargets $WMITargets 332 | 333 | #Write-Verbose "`n`nValue of WMIChangedTargets: $WMIChangedTargets" 334 | 335 | # Determine which systems failed enabling PSRemoting via PsExec and store in variable WMIFailedTargets 336 | if ($WMIChangedTargets -ne $null) { 337 | $WMIFailedTargets = Compare-Object -ReferenceObject $WMIChangedTargets -DifferenceObject $WMITargets -PassThru 338 | } else { 339 | $WMIFailedTargets = $WMITargets 340 | } 341 | } 342 | } else { 343 | Write-Verbose "Exiting..." 344 | continue 345 | } 346 | 347 | Write-Host "`n========================================================================" 348 | Write-Host "Post-Execution Report" 349 | Write-Host "`nPowerShell Remoting Targets:" 350 | Write-Host $PSTargets 351 | Write-Host "`n`nSMB/PsExec Remoting Targets SUCCESS enabling PSRemoting:" 352 | Write-Host $SMBChangedTargets 353 | Write-Host "`nSMB/PsExec Remoting Targets FAILED enabling PSRemoting:" 354 | Write-Host $SMBFailedTargets 355 | Write-Host "`n`nWMI Remoting Targets SUCCESS enabling PSRemoting:" 356 | Write-Host $WMIChangedTargets 357 | Write-Host "`nWMI Remoting Targets FAILED enabling PSRemoting:" 358 | Write-Host $WMIFailedTargets 359 | Write-Host "`n`nTargets with NO REMOTING Options:" 360 | Write-Host $NoRemoteTargets 361 | $PSTargets += $SMBChangedTargets 362 | $PSTargets += $WMIChangedTargets 363 | Write-Host "`n`nFINAL Targets ready for PSRemoting:" 364 | Write-Host $PSTargets 365 | Write-Host "========================================================================`n" 366 | 367 | return $PSTargets 368 | } 369 | 370 | function Enable-WinRMPsExec { 371 | [cmdletbinding()] 372 | Param([String[]] $SMBTargets) 373 | $ChangedTargets = @() 374 | 375 | if ( -Not (Test-Path .\PsExec.exe)) { 376 | Write-Warning "You must have PsExec.exe in the current working directory to run this function!" 377 | continue 378 | } 379 | 380 | foreach ($i in $SMBTargets) { 381 | # Enable WinRM over PsExec 382 | Write-Verbose "Executing winrm quickconfig -q on $i with PsExec" 383 | $a = .\PsExec.exe \\$i -s winrm.cmd quickconfig -q 2>&1>$null 384 | if ( Test-WSMan $i -EA SilentlyContinue ) { 385 | Write-Verbose "Success enabling PSRemoting on $i with PsExec" 386 | $ChangedTargets += $i 387 | } else { 388 | Write-Warning "PsExec Failed!" 389 | } 390 | } 391 | return $ChangedTargets 392 | } 393 | 394 | 395 | function Enable-WinRMWMI { 396 | [cmdletbinding()] 397 | Param([String[]] $WMITargets) 398 | $ChangedTargets = @() 399 | 400 | foreach ($i in $WMITargets) { 401 | # Enable WinRM over WMI 402 | Write-Verbose "Executing winrm quickconfig -q on $i with WMI" 403 | $a = Invoke-WmiMethod -class Win32_process -name Create -ArgumentList "CMD.EXE /c winrm quickconfig -q" -ComputerName $i -EnableAllPrivileges 2>&1>$null 404 | $a = Start-Sleep 3 405 | if ( Test-WSMan $i -EA SilentlyContinue ) { 406 | Write-Verbose "Success enabling PSRemoting on $i with WMI" 407 | $ChangedTargets += $i 408 | } else { 409 | Write-Warning "WMI Failed!" 410 | } 411 | } 412 | return $ChangedTargets 413 | } 414 | 415 | 416 | function Disable-WinRM { 417 | [cmdletbinding()] 418 | Param([String[]] $Targets) 419 | 420 | $VerbosePreference = "Continue" 421 | 422 | if ( -Not (Test-Path .\PsExec.exe)) { 423 | Write-Warning "You must have PsExec.exe in the current working directory to run this function!" 424 | Exit 425 | } 426 | 427 | foreach ($i in $Targets) 428 | { 429 | # Disable WinRM over PsExec 430 | Write-Verbose "Executing winrm delete listener on $i" 431 | .\PsExec.exe \\$i -s winrm.cmd delete winrm/config/Listener?Address=*+Transport=HTTP 432 | Write-Verbose "Executing sc stop winrm on $i" 433 | .\PsExec.exe \\$i -s sc stop winrm 434 | Write-Verbose "Executing sc config winrm start= disabled on $i" 435 | .\PsExec.exe \\$i -s sc config winrm start= disabled 436 | } 437 | } 438 | 439 | function Get-BetterTasklist { 440 | [cmdletbinding()] 441 | Param([bool] $NoHash = $false) 442 | $TimeGenerated = get-date -format r 443 | $betterPsList = Get-WmiObject -Class Win32_process ` 444 | | select -property Name,ProcessID,ParentProcessId,ExecutablePath,CommandLine ` 445 | | Foreach { 446 | if ($_.ExecutablePath -ne $null -AND -NOT $NoHash) { 447 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 448 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($_.ExecutablePath))) 449 | $_ | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 450 | } else { 451 | $_ | Add-Member -MemberType NoteProperty SHA_1 $null 452 | } 453 | $_ | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 454 | $_ 455 | } 456 | $betterPsList | Select TimeGenerated,Name,ProcessID,ParentProcessId,ExecutablePath,SHA_1,CommandLine 457 | } 458 | 459 | function Get-DLLs { 460 | [cmdletbinding()] 461 | Param([bool] $NoHash = $false) 462 | $TimeGenerated = get-date -format r 463 | $results = Get-Process | Select-Object -ExpandProperty Modules -ErrorAction SilentlyContinue | sort FileName -Unique | % { 464 | if ($_.FileName -ne $null -AND -NOT $NoHash) { 465 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 466 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($_.FileName))) 467 | $_ | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 468 | } 469 | else { 470 | $_ | Add-Member -MemberType NoteProperty SHA_1 $null 471 | } 472 | $_ | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 473 | $_ 474 | } 475 | $results | select TimeGenerated,ModuleName,FileName,SHA_1,Size,Company,Description,FileVersion,Product,ProductVersion 476 | } 477 | 478 | function Get-BetterNetstatTCP { 479 | [cmdletbinding()] 480 | Param([bool] $NoHash = $false) 481 | $TimeGenerated = get-date -format r 482 | 483 | # TCP 484 | $data = netstat -nao -p TCP 485 | $betterNetstat = Foreach ($line in $data[4..$data.count]) 486 | { 487 | $line = $line -replace '^\s+','' 488 | $line = $line -split '\s+' 489 | $properties = @{ 490 | Protocol = $line[0] 491 | LocalAddressIP = ($line[1] -split ":")[0] 492 | LocalAddressPort = ($line[1] -split ":")[1] 493 | ForeignAddressIP = ($line[2] -split ":")[0] 494 | ForeignAddressPort = ($line[2] -split ":")[1] 495 | State = $line[3] 496 | ProcessId = $line[4] 497 | } 498 | $currentLineObj = New-Object -TypeName PSObject -Property $properties 499 | $proc = get-wmiobject -query ('select * from win32_process where ProcessId="{0}"' -f $line[4]) 500 | $currentLineObj | Add-Member -MemberType NoteProperty ParentProcessId $proc.ParentProcessId 501 | $currentLineObj | Add-Member -MemberType NoteProperty Name $proc.Caption 502 | $currentLineObj | Add-Member -MemberType NoteProperty ExecutablePath $proc.ExecutablePath 503 | if ($currentLineObj.ExecutablePath -ne $null -AND -NOT $NoHash) { 504 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 505 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($proc.ExecutablePath))) 506 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 507 | } 508 | else { 509 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $null 510 | } 511 | $currentLineObj | Add-Member -MemberType NoteProperty CommandLine $proc.CommandLine 512 | $currentLineObj | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 513 | $currentLineObj 514 | } 515 | $betterNetstat | select TimeGenerated,Protocol,LocalAddressIP,LocalAddressPort,ForeignAddressIP,ForeignAddressPort,State,Name,ProcessId,ParentProcessId,ExecutablePath,SHA_1,CommandLine 516 | } 517 | 518 | 519 | function Get-BetterNetstatTCPv6 { 520 | [cmdletbinding()] 521 | Param([bool] $NoHash = $false) 522 | $TimeGenerated = get-date -format r 523 | 524 | # TCPv6 525 | $data = netstat -nao -p TCPv6 526 | $betterNetstat = Foreach ($line in $data[4..$data.count]) 527 | { 528 | $line = $line -replace '^\s+','' 529 | $line = $line -split '\s+' 530 | $properties = @{ 531 | Protocol = $line[0] 532 | LocalAddress = $line[1] 533 | ForeignAddress = $line[2] 534 | State = $line[3] 535 | ProcessId = $line[4] 536 | } 537 | $currentLineObj = New-Object -TypeName PSObject -Property $properties 538 | $proc = get-wmiobject -query ('select * from win32_process where ProcessId="{0}"' -f $line[4]) 539 | $currentLineObj | Add-Member -MemberType NoteProperty ParentProcessId $proc.ParentProcessId 540 | $currentLineObj | Add-Member -MemberType NoteProperty Name $proc.Caption 541 | $currentLineObj | Add-Member -MemberType NoteProperty ExecutablePath $proc.ExecutablePath 542 | if ($currentLineObj.ExecutablePath -ne $null -AND -NOT $NoHash) { 543 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 544 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($proc.ExecutablePath))) 545 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 546 | } 547 | else { 548 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $null 549 | } 550 | $currentLineObj | Add-Member -MemberType NoteProperty CommandLine $proc.CommandLine 551 | $currentLineObj | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 552 | $currentLineObj 553 | } 554 | $betterNetstat | select TimeGenerated,Protocol,LocalAddress,ForeignAddress,State,Name,ProcessId,ParentProcessId,ExecutablePath,SHA_1,CommandLine 555 | } 556 | 557 | 558 | function Get-BetterNetstatUDP { 559 | [cmdletbinding()] 560 | Param([bool] $NoHash = $false) 561 | $TimeGenerated = get-date -format r 562 | 563 | # Now UDP 564 | $data = netstat -nao -p UDP 565 | $betterNetstat = Foreach ($line in $data[4..$data.count]) 566 | { 567 | $line = $line -replace '^\s+','' 568 | $line = $line -split '\s+' 569 | $properties = @{ 570 | Protocol = $line[0] 571 | LocalAddressIP = ($line[1] -split ":")[0] 572 | LocalAddressPort = ($line[1] -split ":")[1] 573 | ForeignAddressIP = ($line[2] -split ":")[0] 574 | ForeignAddressPort = ($line[2] -split ":")[1] 575 | #State = $line[3] 576 | ProcessId = $line[3] 577 | } 578 | $currentLineObj = New-Object -TypeName PSObject -Property $properties 579 | $proc = get-wmiobject -query ('select * from win32_process where ProcessId="{0}"' -f $line[3]) 580 | $currentLineObj | Add-Member -MemberType NoteProperty ParentProcessId $proc.ParentProcessId 581 | $currentLineObj | Add-Member -MemberType NoteProperty Name $proc.Caption 582 | $currentLineObj | Add-Member -MemberType NoteProperty ExecutablePath $proc.ExecutablePath 583 | if ($currentLineObj.ExecutablePath -ne $null -AND -NOT $NoHash -AND $proc.Caption -ne "dns.exe") { 584 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 585 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($proc.ExecutablePath))) 586 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 587 | } 588 | else { 589 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $null 590 | } 591 | $currentLineObj | Add-Member -MemberType NoteProperty CommandLine $proc.CommandLine 592 | $currentLineObj | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 593 | $currentLineObj 594 | } 595 | $betterNetstat | select TimeGenerated,Protocol,LocalAddressIP,LocalAddressPort,Name,ProcessId,ParentProcessId,ExecutablePath,SHA_1,CommandLine 596 | } 597 | 598 | function Get-BetterNetstatUDPv6 { 599 | [cmdletbinding()] 600 | Param([bool] $NoHash = $false) 601 | $TimeGenerated = get-date -format r 602 | 603 | # Now UDPv6 604 | $data = netstat -nao -p UDPv6 605 | $betterNetstat = Foreach ($line in $data[4..$data.count]) 606 | { 607 | $line = $line -replace '^\s+','' 608 | $line = $line -split '\s+' 609 | $properties = @{ 610 | Protocol = $line[0] 611 | LocalAddress = $line[1] 612 | ForeignAddress = $line[2] 613 | ProcessId = $line[3] 614 | } 615 | $currentLineObj = New-Object -TypeName PSObject -Property $properties 616 | $proc = get-wmiobject -query ('select * from win32_process where ProcessId="{0}"' -f $line[3]) 617 | $currentLineObj | Add-Member -MemberType NoteProperty ParentProcessId $proc.ParentProcessId 618 | $currentLineObj | Add-Member -MemberType NoteProperty Name $proc.Caption 619 | $currentLineObj | Add-Member -MemberType NoteProperty ExecutablePath $proc.ExecutablePath 620 | if ($currentLineObj.ExecutablePath -ne $null -AND -NOT $NoHash) { 621 | $sha1 = New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider 622 | $hash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($proc.ExecutablePath))) 623 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $($hash -replace "-","") 624 | } 625 | else { 626 | $currentLineObj | Add-Member -MemberType NoteProperty SHA_1 $null 627 | } 628 | $currentLineObj | Add-Member -MemberType NoteProperty CommandLine $proc.CommandLine 629 | $currentLineObj | Add-Member -MemberType NoteProperty TimeGenerated $TimeGenerated 630 | $currentLineObj 631 | } 632 | $betterNetstat | select TimeGenerated,Protocol,LocalAddress,Name,ProcessId,ParentProcessId,ExecutablePath,SHA_1,CommandLine 633 | } 634 | 635 | function Invoke-Autorunsc { 636 | [cmdletbinding()] 637 | Param([String] $url) 638 | # python -m SimpleHTTPServer 8080 639 | #$urla = $url + "autorunsc.exe" 640 | $path = "C:\blue_temp\autorunsc.exe" 641 | #(New-Object Net.WebClient).DownloadFile($urla, $path) 642 | $results = & $path -accepteula -h -c -nobanner -a * -s -t | ConvertFrom-Csv 643 | Remove-Item $path 644 | Remove-Item C:\blue_temp 645 | $results 646 | } 647 | 648 | # Ref: Matt Graeber https://specterops.io/assets/resources/SpecterOps_Subverting_Trust_in_Windows.pdf 649 | function Invoke-Sigcheck { 650 | [cmdletbinding()] 651 | Param([String] $url) 652 | 653 | $verifyHashFunc = 'HKLM:\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDllVerifyIndirectData' 654 | $PowerShellSIPGuid = '{603BCC1F-4B59-4E08-B724-D2C6297EF351}' 655 | $PESIDPGuid = '{C689AAB8-8E78-11D0-8C47-00C04FC295EE}' 656 | 657 | if ((Get-ItemProperty -Path "$verifyHashFunc\$PowerShellSIPGuid\" -Name "FuncName").FuncName -ne "PsVerifyHash") { 658 | Write-Error "The System Signature Trust is Subverted!!!" 659 | Exit 660 | } elseif ((Get-ItemProperty -Path "$verifyHashFunc\$PowerShellSIPGuid\" -Name "Dll").Dll -ne "C:\Windows\System32\WindowsPowerShell\v1.0\pwrshsip.dll") { 661 | Write-Error "The System Signature Trust is Subverted!!!" 662 | Exit 663 | } elseif ((Get-ItemProperty -Path "$verifyHashFunc\$PESIDPGuid\" -Name "FuncName").FuncName -ne "CryptSIPVerifyIndirectData") { 664 | Write-Error "The System Signature Trust is Subverted!!!" 665 | Exit 666 | } elseif ((Get-ItemProperty -Path "$verifyHashFunc\$PESIDPGuid\" -Name "Dll").Dll -ne "C:\Windows\System32\WINTRUST.DLL" -AND (Get-ItemProperty -Path "$verifyHashFunc\$PESIDPGuid\" -Name "Dll").Dll -ne "WINTRUST.DLL") { 667 | Write-Error "The System Signature Trust is Subverted!!!" 668 | Exit 669 | } 670 | 671 | $urls = $url + "sigcheck.exe" 672 | $path = "C:\sigcheck.exe" 673 | (New-Object Net.WebClient).DownloadFile($urls, $path) 674 | $results = & $path -accepteula -c -u -e -s -r -nobanner C:\Windows\System32 | ConvertFrom-Csv 675 | $results += & $path -accepteula -c -u -e -s -r -nobanner C:\Windows\SysWOW64 | ConvertFrom-Csv 676 | $results 677 | Remove-Item $path 678 | } 679 | 680 | # Check for 681 | function Get-AuditOptions { 682 | $regConfig = @" 683 | regKey,name 684 | "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa","scenoapplylegacyauditpolicy" 685 | "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit","ProcessCreationIncludeCmdLine_Enabled" 686 | "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription","EnableTranscripting" 687 | "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription","OutputDirectory" 688 | "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging","EnableScriptBlockLogging" 689 | "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging","EnableModuleLogging" 690 | "HKLM:\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager",1 691 | "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest","UseLogonCredential" 692 | "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Credssp\PolicyDefaults","Allow*" 693 | "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation","Allow*" 694 | "@ 695 | 696 | 697 | 698 | $regConfig | ConvertFrom-Csv | ForEach-Object { 699 | if (-Not (Test-Path $_.regKey)) { 700 | # Registry path does not exist -> document DNE 701 | #Write-Warning "Path $($_.regKey) does not exist" 702 | New-Object PSObject -Property @{regKey = $_.regKey; name = "DNE"; value = "DNE"} 703 | } 704 | else { 705 | if ((Get-ItemProperty $_.regKey | Select-Object -Property $_.name).$_.name -ne $null) { 706 | # Registry key exists. Document value 707 | #Write-Warning "Key $($_.regKey) if $(Get-ItemProperty $_.regKey | Select-Object -Property $_.name)" 708 | #Write-Warning "Property $($_.name) exists. Documenting Value: $(Get-ItemProperty $_.regKey | Select-Object -ExpandProperty $_.name)" 709 | # Handle Cases where SubscriptionManager value already exists. 710 | if ($_.regKey -like "*SubscriptionManager*") { 711 | #Write-Warning "RegKey is Like SubscriptionManager" 712 | #Write-Warning "Property = $($_.name)" 713 | $wecNum = 1 714 | # Backup each currently configured SubscriptionManager values. 715 | while ( (Get-ItemProperty $_.regKey | Select-Object -ExpandProperty $([string]$wecNum) -ErrorAction SilentlyContinue) ) { 716 | #Write-Warning "RegKey with property = $wecNum exists" 717 | New-Object PSObject -Property @{regKey = $_.regKey; name = $wecNum; value = $(Get-ItemProperty $_.regKey | Select-Object -ExpandProperty $([string]$wecNum))} 718 | #Write-Warning "Incrementing wecNum" 719 | $wecNum++ 720 | } 721 | } 722 | # Backup all non-SubscriptionManager values to array. 723 | else { 724 | New-Object PSObject -Property @{regKey = $_.regKey; name = $_.name; value = $(Get-ItemProperty $_.regKey | Select-Object -ExpandProperty $_.name)} 725 | } 726 | } 727 | else { 728 | # Registry key does not exist. Document DNE 729 | #Write-Warning "Property $($_.name) DNE. Documenting Null" 730 | New-Object PSObject -Property @{regKey = $_.regKey; name = $_.name; value = "DNE"} 731 | } 732 | } 733 | } 734 | 735 | } 736 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 zulu8 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Get-Baseline 2 | 3 | Get-Baseline is a wrapper PowerShell script for a number of functions that automates the initial tasks in an incident response scenario. 4 | 5 | #### `Get-Baseline` 6 | 7 | Primary function. Calls all Remote Access, Baseline Collection, and EventLog Collection functions. 8 | 9 | ## Baseline Collection 10 | 11 | *Collect ASEPs, live process, configuration data for systems in scope.* 12 | 13 | #### `Get-BetterTasklist` 14 | 15 | Collects current running processes - TimeGenerated, Name, ProcessID, ParentProcessId, ExecutablePath, Hash, CommandLine 16 | 17 | #### `Get-DLLs` 18 | 19 | Collects current loaded DLLs - TimeGenerated, ModuleName, FileName, Hash, Size, Company, Description, FileVersion, Product, ProductVersion 20 | 21 | #### `Get-BetterNetstat` 22 | 23 | Collects current netstat output - TimeGenerated, Protocol, LocalAddress, ForeignAddress, State, Name, ProcessId, ParentProcessId, ExecutablePath, Hash, CommandLine 24 | 25 | #### `Invoke-Autorunsc` 26 | 27 | Download and execute autorunsc.exe with the following arguments: -accepteula -h -c -nobanner -a * -s 28 | 29 | #### `Invoke-Sigcheck` 30 | 31 | Verifies signature integrity on the system based on Matt Graeber's "Subverting Trust in Windows" then downloads and executes sigcheck.exe -accepteula -c -u -e -s -r -nobanner C:\Windows\System32 and C:\Windows\SysWOW64 32 | 33 | #### `Get-AuditOptions` 34 | 35 | Checks registry for additional auditing options - Process Creation Command Line, PowerShell Transcription, PowerShell Script Block Logging, PowerShell Module Logging, Windows Event Forwarding. 36 | 37 | 38 | ## Remote Access 39 | 40 | *Enable PSRemoting for systems in scope.* 41 | 42 | #### `Enable-RemoteAccess` 43 | 44 | Enable PowerShell Remoting / WinRM via SMB (PsExec) or WMI (Invoke-WmiMethod) 45 | 46 | #### `Enable-WinRMPsExec` 47 | 48 | Enable PowerShell Remoting / WinRM via SMB (PsExec) 49 | 50 | #### `Enable-WinRMWMI` 51 | 52 | Enable PowerShell Remoting / WinRM via WMI (Invoke-WmiMethod) 53 | 54 | 55 | ## Event Log Collection 56 | 57 | *Collect security-relevant event logs for input into SIEM.* 58 | 59 | #### `Get-HuntData` 60 | 61 | Collects Windows Event Log data from the following Logs: 62 | * Application 63 | * System 64 | * Security 65 | * Windows PowerShell 66 | * Microsoft-Windows-Windows Defender/Operational 67 | * Microsoft-Windows-AppLocker/EXE and DLL 68 | * Microsoft-Windows-AppLocker/MSI and Script 69 | * Microsoft-Windows-AppLocker/Packaged app-Execution 70 | * Microsoft-Windows-DeviceGuard/Operational 71 | * Microsoft-Windows-PowerShell/Operational 72 | * Microsoft-Windows-Windows Firewall With Advanced Security/Firewall 73 | * Microsoft-Windows-Sysmon/Operational 74 | 75 | ## Prerequisites 76 | 77 | On Targets: 78 | * Accessible via WinRM, SMB, or WMI (WinRM Preferred) 79 | * PowerShell 2.0+ (3.5+ Preferred) 80 | 81 | On Collection System: 82 | * PowerShell 5.0+ 83 | * Domain Joined 84 | * Logged in with rights as Administrator (able to execute code remotely) 85 | 86 | 87 | ## Usage 88 | ### Execution 89 | ```PowerShell 90 | PS> Get-Baseline -Targets dc01,srv01,srv02,pc02win10 -url "http://10.0.0.128:8080/" 91 | ``` 92 | 93 | ```PowerShell 94 | PS> Get-Baseline -Targets $(get-content ) -url "http://10.0.0.128:8080/" -SkipSigcheck 95 | ``` 96 | 97 | ### Output 98 | ```PowerShell 99 | PS C:\Users\Administrator\20171212_Survey> Get-Baseline -Targets dc01,srv01,srv02,pc02win10 -url "http://10.0.0.128:8080/" -Verbose 100 | Transcript started, output file is .\Log_20171212.txt 101 | 102 | Directory: C:\Users\Administrator\20171212_Survey 103 | 104 | Mode LastWriteTime Length Name 105 | ---- ------------- ------ ---- 106 | d---- 12/12/2017 9:25 PM Baseline 107 | 108 | 109 | If WinRM/PSRemoting is DISABLED, attempt to ENABLE with PsExec? [y/n]: y 110 | 111 | If WinRM/PSRemoting and SMB is DISABLED, attempt to ENABLE with WMI? [y/n]: y 112 | VERBOSE: Testing Remote Management Options for dc01 113 | VERBOSE: PSRemoting Enabled on dc01 114 | VERBOSE: Testing Remote Management Options for srv01 115 | VERBOSE: SMB Enabled on srv01 116 | VERBOSE: Testing Remote Management Options for srv02 117 | VERBOSE: WMI Enabled on srv02 118 | VERBOSE: Testing Remote Management Options for pc02win10 119 | VERBOSE: PSRemoting Enabled on pc02win10 120 | 121 | ======================================================================== 122 | Pre-Execution Report 123 | 124 | PowerShell Remoting Targets: 125 | dc01 pc02win10 126 | 127 | SMB/PsExec Remoting Targets: 128 | srv01 129 | 130 | WMI Remoting Targets: 131 | srv02 132 | 133 | Targets with NO REMOTING Options: 134 | 135 | 136 | ======================================================================== 137 | 138 | You have elected to enable PSRemoting via PsExec. 139 | You have elected to enable PSRemoting via WMI. 140 | 141 | Are you sure you want to execute? [y/n]: y 142 | VERBOSE: Executing PsExec... 143 | VERBOSE: Executing winrm quickconfig -q on srv01 with PsExec 144 | VERBOSE: Success enabling PSRemoting on srv01 with PsExec 145 | VERBOSE: Executing WMI... 146 | VERBOSE: Executing winrm quickconfig -q on srv02 with WMI 147 | VERBOSE: Success enabling PSRemoting on srv02 with WMI 148 | 149 | ======================================================================== 150 | Post-Execution Report 151 | 152 | PowerShell Remoting Targets: 153 | dc01 pc02win10 154 | 155 | 156 | SMB/PsExec Remoting Targets SUCCESS enabling PSRemoting: 157 | srv01 158 | 159 | SMB/PsExec Remoting Targets FAILED enabling PSRemoting: 160 | 161 | 162 | 163 | WMI Remoting Targets SUCCESS enabling PSRemoting: 164 | srv02 165 | 166 | WMI Remoting Targets FAILED enabling PSRemoting: 167 | 168 | 169 | 170 | Targets with NO REMOTING Options: 171 | 172 | 173 | 174 | FINAL Targets ready for PSRemoting: 175 | dc01 pc02win10 srv01 srv02 176 | ======================================================================== 177 | 178 | Scheduled to execute baseline collection on: 179 | dc01 pc02win10 srv01 srv02 180 | 181 | Are you sure you want to execute? [y/n]: y 182 | VERBOSE: Getting Audit Levels 183 | VERBOSE: Getting Additional Audit Options 184 | VERBOSE: Getting System Information 185 | VERBOSE: Getting Better Tasklist 186 | VERBOSE: Getting Loaded DLLs 187 | VERBOSE: Getting Better TCP Netstat 188 | VERBOSE: Getting Better TCPv6 Netstat 189 | VERBOSE: Getting Better UDP Netstat 190 | VERBOSE: Getting Better UDPv6 Netstat 191 | VERBOSE: Getting Autorunsc Data 192 | VERBOSE: Checking System32 and SysWOW64 for unsigned binaries 193 | VERBOSE: Getting Event Log Settings 194 | d---- 12/12/2017 9:38 PM EventLogData 195 | VERBOSE: Collecting Application Log 196 | VERBOSE: Collecting System Log 197 | VERBOSE: Collecting Powershell Log 198 | VERBOSE: Collecting Microsoft-Windows-Windows Defender/Operational 199 | VERBOSE: Collecting Microsoft-Windows-AppLocker/EXE and DLL 200 | VERBOSE: Collecting Microsoft-Windows-AppLocker/MSI and Script 201 | VERBOSE: Collecting Microsoft-Windows-AppLocker/Packaged app-Execution 202 | VERBOSE: Collecting Microsoft-Windows-DeviceGuard/Operational 203 | VERBOSE: Collecting Microsoft-Windows-PowerShell/Operational 204 | VERBOSE: Collecting Microsoft-Windows-Windows Firewall With Advanced Security/Firewall 205 | VERBOSE: Collecting Microsoft-Windows-Sysmon/Operational 206 | VERBOSE: Collecting Security Log on dc01 207 | VERBOSE: Collecting Security Log on pc02win10 208 | VERBOSE: Collecting Security Log on srv01 209 | VERBOSE: Collecting Security Log on srv02 210 | Transcript stopped, output file is C:\Users\Administrator\20171212_Survey\Log_20171212.txt 211 | 212 | PS C:\Users\Administrator\20171212_Survey> 213 | 214 | ``` 215 | ### Results 216 | ```PowerShell 217 | PS C:\Users\Administrator\20171212_Survey> Get-ChildItem -Recurse 218 | 219 | Directory: C:\Users\Administrator\20171212_Survey 220 | 221 | Mode LastWriteTime Length Name 222 | ---- ------------- ------ ---- 223 | d---- 12/12/2017 9:38 PM Baseline 224 | d---- 12/12/2017 9:39 PM EventLogData 225 | -a--- 12/12/2017 9:48 PM 32034 Log_20171212.txt 226 | -a--- 12/12/2017 9:28 PM 339096 PsExec.exe 227 | 228 | Directory: C:\Users\Administrator\20171212_Survey\Baseline 229 | 230 | Mode LastWriteTime Length Name 231 | ---- ------------- ------ ---- 232 | -a--- 12/12/2017 9:31 PM 4140 auditoptions.csv 233 | -a--- 12/12/2017 9:31 PM 34754 auditpol.csv 234 | -a--- 12/12/2017 9:34 PM 2481407 autorunsc.csv 235 | -a--- 12/12/2017 9:31 PM 838746 dlls.csv 236 | -a--- 12/12/2017 9:38 PM 5031 eventloglist.csv 237 | -a--- 12/12/2017 9:32 PM 35431 netstat_TCP.csv 238 | -a--- 12/12/2017 9:32 PM 23498 netstat_TCPv6.csv 239 | -a--- 12/12/2017 9:33 PM 500623 netstat_UDP.csv 240 | -a--- 12/12/2017 9:33 PM 6172 netstat_UDPv6.csv 241 | -a--- 12/12/2017 9:38 PM 36450 sigcheck.csv 242 | -a--- 12/12/2017 9:31 PM 5063 systeminfo.csv 243 | -a--- 12/12/2017 9:31 PM 63379 tasklist.csv 244 | 245 | Directory: C:\Users\Administrator\20171212_Survey\EventLogData 246 | 247 | Mode LastWriteTime Length Name 248 | ---- ------------- ------ ---- 249 | -a--- 12/12/2017 9:39 PM 6861041 eventlog_application.csv 250 | -a--- 12/12/2017 9:39 PM 0 eventlog_applocker_exedll.csv 251 | -a--- 12/12/2017 9:39 PM 0 eventlog_applocker_msiscript.csv 252 | -a--- 12/12/2017 9:39 PM 0 eventlog_applocker_packaged.csv 253 | -a--- 12/12/2017 9:39 PM 282881 eventlog_defender_operational.csv 254 | -a--- 12/12/2017 9:39 PM 108447 eventlog_deviceguard_operational.csv 255 | -a--- 12/12/2017 9:41 PM 1969917 eventlog_firewall.csv 256 | -a--- 12/12/2017 9:39 PM 5775288 eventlog_powershell.csv 257 | -a--- 12/12/2017 9:41 PM 9907825 eventlog_powershell_operational.csv 258 | -a--- 12/12/2017 9:42 PM 119451056 eventlog_security_dc01.csv 259 | -a--- 12/12/2017 9:47 PM 285187744 eventlog_security_pc02win10.csv 260 | -a--- 12/12/2017 9:48 PM 109548498 eventlog_security_srv01.csv 261 | -a--- 12/12/2017 9:48 PM 8306071 eventlog_security_srv02.csv 262 | -a--- 12/12/2017 9:41 PM 0 eventlog_sysmon_operational.csv 263 | -a--- 12/12/2017 9:39 PM 9043921 eventlog_system.csv 264 | ``` 265 | 266 | # Analysis 267 | ## Signature Based Analysis 268 | *Applying IOCs (filename,hash,c2,etc) to the data set in a given SIEM (Splunk)* 269 | 270 | ### Get IOCs 271 | 272 | ### Fixing IOCs 273 | 274 | * Substitute double backslash for single - sed (splunk-ism) 275 | * Substitute semi-colon for comma - tr (turn into csv. splunk-ism) 276 | * Add * to beginning and end of string - awk (for wildcard matching and command line comparison) 277 | ```bash 278 | grep -v '#' filename-iocs.txt | sed '/^\s*$/d' | tr ";" "," | sed 's/\\\\/\\/g' | sed 's/\\\./\./g' | awk '{ print "\*" $0; }' | awk -F',' '{print $1,$2}' OFS='*,' > ~/filename-iocs.csv 279 | 280 | grep -v '#' c2-iocs.txt | sed '/^\s*$/d' | tr ";" "," > ~/c2-iocs.txt 281 | 282 | grep -v '#' hash-iocs.txt | sed '/^\s*$/d' | tr ";" "," > ~/hash-iocs.txt 283 | ``` 284 | 285 | * Single File 286 | * Unique Entries Only (save computing power. no need to check same hash/c2/filename twice) 287 | ```bash 288 | cat all-filename-iocs.csv | sort -t"," -k1 | uniq | wc -l 289 | ``` 290 | 291 | * Find and remediate any entries without description or source field (required for splunk query design) 292 | ```bash 293 | cat uniq-all-hash-iocs.csv | awk -F',' '$2 == "" {print $0}' 294 | cat uniq-all-c2-iocs.csv | awk -F',' '$2 == "" {print $0}' 295 | cat uniq-all-c2-iocs.csv | awk -F',' '$2 == "" {print $0}' 296 | 297 | cat uniq-all-filename-iocs.csv | awk -F',' '$2 == "" {print $0"0"}' > fixed-filename-iocs.csv 298 | cat uniq-all-filename-iocs.csv | awk -F',' '$2 != "" {print $0}' >> fixed-filename-iocs.csv 299 | ``` 300 | 301 | * Identify CSV headers to be used in splunk queries 302 | ``` 303 | uniq-all-c2-iocs.csv -> host,source 304 | uniq-all-filename-iocs.csv -> filename,description 305 | uniq-all-hash-iocs.csv -> hash,source 306 | ``` 307 | ### Configure SIEM (Splunk) 308 | *IOCs gathered and prepared. Now we prepare our environment* 309 | 310 | #### Prepare for Data Ingest and Field Extraction 311 | *These configs allow us to (automatically) extract the fields we need from CSV data acquired with PowerShell remoting* 312 | 313 | $SPLUNK_HOME\\etc\\system\\local\\props.conf 314 | ``` 315 | [csv_eventlog] 316 | DATETIME_CONFIG = 317 | INDEXED_EXTRACTIONS = csv 318 | KV_MODE = none 319 | NO_BINARY_CHECK = true 320 | SHOULD_LINEMERGE = false 321 | TIMESTAMP_FIELDS = TimeGenerated 322 | category = Structured 323 | description = Comma-separated value format. Set header and other settings in "Delimited Settings" 324 | disabled = false 325 | pulldown_type = true 326 | REPORT-Message = message_delims 327 | ``` 328 | $SPLUNK_HOME\\etc\\system\\local\\transforms.conf 329 | ``` 330 | [message_delims] 331 | SOURCE_KEY = Message 332 | DELIMS = "\n", "=:" 333 | CLEAN_KEYS = true 334 | MV_ADD = true 335 | ``` 336 | 337 | ### Prepare Lookups 338 | *These configs allow us to reference our CSV IOC lists and apply WILDCARD and CASE(in)sensitive matching* 339 | 340 | ##### Move CSV File to: 341 | $SPLUNK_HOME\\etc\\apps\\search\\lookups\\ 342 | 343 | ##### In WebApp add CSVs as "lookup" files 344 | ``` 345 | Settings > Lookups > Lookup definitions > Add new 346 | search 347 | 348 | File-based 349 | 350 | ``` 351 | 352 | ##### Implement Wildcard Matching 353 | $SPLUNK_HOME\\etc\\users\\\\search\\local\\transforms.conf 354 | ``` 355 | [filename-iocs] 356 | batch_index_query = 0 357 | case_sensitive_match = 0 <---- Change from 1 to 0 358 | filename = filename-iocs.csv 359 | match_type = WILDCARD(filename) <---- Add this line 360 | 361 | [hash-iocs] 362 | batch_index_query = 0 363 | case_sensitive_match = 1 364 | filename = hash-iocs.csv 365 | ``` 366 | Example: 367 | * filename-iocs.csv contains: 368 | ``` 369 | filename,description 370 | *ystem32\svchost.exe*,90 371 | ... 372 | ``` 373 | * Splunk Query: 374 | ``` 375 | source="C:\\20171215_Survey\\Baseline*" 376 | | lookup filename-iocs filename AS ExecutablePath OUTPUT description AS threat_description 377 | | search threat_description=* 378 | ``` 379 | * Results: any events that contain the field "ExecutablePath" with a value that matches the list of wildcards in filename-iocs.csv 380 | 381 | | Field | Value | 382 | | ----- | ----- | 383 | | "TimeGenerated" | "Fri, 15 Dec 2017 18:06:15 GMT" | 384 | | "Protocol" | "UDP" | 385 | | "LocalAddress" | "[::]:4500" | 386 | | "Name" | "svchost.exe" | 387 | | "ProcessId" | "844" | 388 | | "ParentProcessId" | "468" | 389 | | "ExecutablePath" | "C:\Windows\system32\svchost.exe" | 390 | | "Hash" | "619652B42AFE5FB0E3719D7AEDA7A5494AB193E8" | 391 | | "CommandLine" | "C:\Windows\system32\svchost.exe -k netsvcs" | 392 | | "PSComputerName" | "srv03" | 393 | | "RunspaceId" | "286f61af-dff7-4dc4-9fe5-71e6aedcfad0" | 394 | | "PSShowComputerName" | "True" | 395 | 396 | 397 | 398 | ## License 399 | 400 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 401 | 402 | ## Acknowledgments 403 | 404 | * **Florian Roth** - *LOKI, IOCs, all things DFIR* - [Neo23x0](https://github.com/Neo23x0) 405 | 406 | 407 | --------------------------------------------------------------------------------