├── .gitignore ├── README.md ├── Get-SystemExecAuthenticodeSignature.ps1 ├── Get-CorrelatedSysmonEvents.ps1 └── Get-TriageForensics.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/launch.json 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ir_scripts 2 | Scripts to aid in incident response and threat hunting. 3 | 4 | ## Get-CorrelatedSysmonEvents 5 | 6 | Get-CorrelatedSysmonEvents is used to build context around an event to provide threat hunters a better picture of what is happening. The original intent was to correlate Network Connection events (Event ID 3) with the process that spawned them (Process Creation, Event ID 1). However, its built to be flexible so that you can correlate any two Event IDs based on the unique Process GUID that Sysmon assigns. 7 | 8 | This script was inspired by the work done by Robert Rodriguez (@Cyb3rWard0g) of SpectreOps with his 3 part post "Real-Time Sysmon Processing via KSQL and HELK" 9 | 10 | https://posts.specterops.io/real-time-sysmon-processing-via-ksql-and-helk-part-1-initial-integration-88c2b6eac839 11 | 12 | ## Get-SystemExecAuthenticodeSignature 13 | 14 | Get-SystemExecAuthenticodeSignature checks both the system32 and SysWOW64 system directories for unsigned binaries. Unsigned binaries in these folders can be evidence of abusing the `admin$` share to move laterally around the environment by an advisary. Unsigned binaries should be investigated for their legitimacy. 15 | 16 | ## Get-TriageForensics 17 | 18 | Uses available PowerShell modules to collect forensic data from a host. The data is used to triage the machine, determine if there is a true incident and if further investigation is required on that host. 19 | -------------------------------------------------------------------------------- /Get-SystemExecAuthenticodeSignature.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks the system32 and SysWOW64 directories for their digital signature status. 4 | .PARAMETER Status 5 | An optional parameter; defines what statuses to report on. Can be NotSigned (default), UnknownError, Valid or All. 6 | .PARAMETER OutputFilePath 7 | An optional parameter; defines where to write the results. Default is "C:\temp\" 8 | .EXAMPLE 9 | Get-SystemExecAuthenticodeSignature.ps1 -Status NotSigned -OutputFilePath "C:\temp\" 10 | .NOTES 11 | .DESCRIPTION 12 | Get-SystemExecAuthenticodeSignature is used to check the digital signature of binaries in the 13 | C:\Windows\system32\ and C:\Windows\SysWOW64\ directories. Unsigned binaries in these folders 14 | could be an indication of file transfers to the "admin$" share, which is used by adversaries 15 | for lateral movement between machines. Results are saved by default in "C:\temp\" 16 | 17 | Author: Chris Miller 18 | Date Created: 20190228 19 | .EXAMPLE 20 | #> 21 | 22 | Param( 23 | [string]$Status = "NotSigned", 24 | [string]$OutputFilePath = "C:\temp\" 25 | ) 26 | 27 | $sys32 = Get-ChildItem "C:\Windows\system32\" 28 | $sys64 = Get-ChildItem "C:\Windows\SysWOW64\" 29 | 30 | $SystemDirectories = @($sys32, $sys64) 31 | 32 | function CheckExecutableStatus($ExecutableToCheck, $SignatureResult) 33 | { 34 | $md5 = Get-FileHash -Algorithm MD5 $ExecutableToCheck.FullName 35 | $sha256 = Get-FileHash -Algorithm SHA256 $ExecutableToCheck.FullName 36 | $HashedResults = $SignatureResult | Select-Object *, @{n="FileHashMd5"; e={$md5.Hash}}, @{n="FileHashSha256"; e={$sha256.Hash}} 37 | $JsonifyResults = $HashedResults | ConvertTo-Json -Depth 4 38 | $JsonifyResults | Out-File -Append $OutputFilePath"\SystemExecSignatureStatus.json" 39 | } 40 | 41 | function CheckSignature($directory) 42 | { 43 | ForEach($ExecutableToCheck in $directory) 44 | { 45 | if ((Get-Item $ExecutableToCheck.Fullname) -is [System.IO.DirectoryInfo]){ 46 | continue 47 | }else{ 48 | $SignatureResult = Get-AuthenticodeSignature $ExecutableToCheck.FullName -ErrorAction SilentlyContinue | Select * 49 | if ("All" -in $Status){ 50 | CheckExecutableStatus $ExecutableToCheck $SignatureResult 51 | } elseif ($Status -in $SignatureResult.Status) { 52 | CheckExecutableStatus $ExecutableToCheck $SignatureResult 53 | } 54 | } 55 | } 56 | } 57 | 58 | function main() 59 | { 60 | ForEach($directory in $SystemDirectories){ 61 | CheckSignature($directory) 62 | } 63 | } 64 | 65 | main -------------------------------------------------------------------------------- /Get-CorrelatedSysmonEvents.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Correltas Sysmon events to assist in threat hunting and incident response. 4 | .PARAMETER StartTime 5 | An optional parameter; defines how far back in history (in minutes) to correlate logs. Default is five (5) minutes. 6 | .PARAMETER GeneratingEvent 7 | An optional parameter; defines which event type generates an event for correlation. Default is Event ID 3, Network Connection Event 8 | .PARAMETER CorrelatingEvent 9 | An optional parameter; defines which event to correlate to the generating event. Default is Event ID 1, Process Creation Event. 10 | .PARAMETER OutputFilePath 11 | An optional parameter; defines the output file path to save the results. Default is "C:\temp\" 12 | .EXAMPLE 13 | CorrelateSysmonEvents.ps1 -StartTime 10 -GeneratingEvent 3 -CorrelatingEvent 1 -OutputFilePath "C:\temp\correlation_results" 14 | .NOTES 15 | .DESCRIPTION 16 | This script retrieves Sysmon logs from the host and correlates the defined event types. 17 | Default configuration will correlate Event ID 3 (Network Connection) with 18 | Event ID 1 (Process Creation) with the purpose of identifying new processes that connect 19 | to the internet. With appropriate whitelisting in the Sysmon configuration this can be 20 | high fidelity alerting. This behavior could indicate a reverse shell being launched and 21 | connecting to Command and Control infrastructure (C2). 22 | 23 | This script was inspired by the work done by Robert Rodriguez (@Cyb3rWard0g) of SpectreOps with his 3 part post "Real-Time Sysmon Processing via KSQL and HELK" 24 | 25 | https://posts.specterops.io/real-time-sysmon-processing-via-ksql-and-helk-part-1-initial-integration-88c2b6eac839 26 | 27 | Author: Chris Miller 28 | Date Created: 20190115 29 | Date Updated: 20190304 30 | 31 | #> 32 | 33 | Param( 34 | [DateTime]$StartTime = (Get-Date) - (New-TimeSpan -Minutes 5), 35 | [int]$GeneratingEvent = 3, 36 | [int]$CorrelatingEvent = 1, 37 | [string]$OutputFilePath = "C:\temp\" 38 | ) 39 | 40 | Write-Host "Looking as far back as " $StartTime 41 | Write-Host "Correlating Event ID " $GeneratingEvent "with Event ID " $CorrelatingEvent 42 | Write-Host "Output file can be foud at: " $OutputFilePath 43 | 44 | # The Message field in the event is a string by default. This parses the string into a PSObject 45 | # which can then be searched and formatted into a JSON object. 46 | function ParseMessageEvents($RawEvents) 47 | { 48 | $ParsedEventsMessage = $RawEvents | Select-Object -Property Message | ForEach-Object{$_ -replace ": ", "= "} | ForEach-Object {$_ -replace "\\", "\\\\"} | ConvertFrom-StringData 49 | return $ParsedEventsMessage 50 | } 51 | 52 | function CreateUniqueEvents($ParsedMessages) 53 | { 54 | $global:ProcessGuids = @($ParsedMessages.ProcessGuid | Select-Object -Unique) 55 | Write-Host "Number of unique generating events found: " $ProcessGuids.Count 56 | $ParsedMessages | ForEach-Object{$GeneratingEventsMessage += @{$_.ProcessGuid= $_}} 57 | return $GeneratingEventsMessage 58 | } 59 | 60 | # Gets Generating Events and creates a list of unique Process GUIDs. 61 | function GetSysmonGeneratingEvents() 62 | { 63 | try 64 | { 65 | $RawGeneratingEvents = Get-WinEvent -FilterHashTable @{ 66 | LogName = "Microsoft-Windows-Sysmon/Operational"; 67 | StartTime = $StartTime; 68 | ID = $GeneratingEvent 69 | } 70 | 71 | } 72 | catch [System.Exception] 73 | { 74 | Write-Error "No generating events found." -ErrorAction Stop 75 | } 76 | $ParsedGeneratingEventsMessage = ParseMessageEvents $RawGeneratingEvents 77 | return CreateUniqueEvents $ParsedGeneratingEventsMessage 78 | 79 | } 80 | 81 | function GetSysmonCorrelatingEvents() 82 | { 83 | try 84 | { 85 | $RawCorrelatingEvents = Get-WinEvent -FilterHashTable @{ 86 | LogName = "Microsoft-Windows-Sysmon/Operational"; 87 | StartTime = $StartTime; 88 | ID = $CorrelatingEvent 89 | } 90 | 91 | } 92 | catch [System.Exception] 93 | { 94 | Write-Error "No Correlating events found." -ErrorAction Stop 95 | } 96 | 97 | $ParsedCorrelatingEventsMessage = ParseMessageEvents $RawCorrelatingEvents 98 | $ParsedCorrelatingEventsMessage | ForEach-Object{$ParsedCorrelatingEventsMessageIndex += @{$_.ProcessGuid= $_}} 99 | $ParsedCorrelatingEventsMessage | ForEach-Object{if($_.ProcessGuid -in $ProcessGuids){ 100 | $ChildProcessGuid = $_.ProcessGuid 101 | $ParentProcessInfo = $_.ParentProcessGuid 102 | $ParentParentProcessGuid = $ParsedCorrelatingEventsMessageIndex.$ParentProcessInfo.ParentProcessGuid 103 | 104 | $EventTimeUtc = [DateTime]$_.UtcTime 105 | $PowerShellCorrelatingEvents = GetPowerShellCorrelatingEvents $EventTimeUtc 106 | 107 | $ChildProcessInfo = @{ 108 | "ChildProcess" = $_; 109 | "ParentProcess" = $ParsedCorrelatingEventsMessageIndex.$ParentProcessInfo 110 | "ParentParentProcess" = $ParsedCorrelatingEventsMessageIndex.$ParentParentProcessGuid 111 | "PowerShellEvents" = $PowerShellCorrelatingEvents 112 | } 113 | $CorrelatingEvents += @{$ChildProcessGuid=$ChildProcessInfo} 114 | 115 | } 116 | } 117 | if ($CorrelatingEvents.Count -eq 0) 118 | { 119 | Write-Host "No correlating events found." 120 | exit(0) 121 | } 122 | else 123 | { 124 | Write-Host "Number of correlating events found: " $CorrelatingEvents.Count 125 | return $CorrelatingEvents 126 | } 127 | } 128 | 129 | function GetPowerShellCorrelatingEvents($SysmonUtcTime) 130 | { 131 | $TimeZone = Get-TimeZone 132 | $StartTimeLocal = $SysmonUtcTime + (New-TimeSpan -Hour $TimeZone.BaseUtcOffset.Hours) 133 | $EndTimeLocal = $StartTimeLocal + (New-TimeSpan -Minutes 2) 134 | try 135 | { 136 | $PSCorrelatingEvents = Get-WinEvent -FilterHashtable @{ 137 | LogName = "Microsoft-Windows-PowerShell/Operational"; 138 | StartTime = $StartTimeLocal; 139 | EndTime = $EndTimeLocal; 140 | ID = 4104 141 | } 142 | return $PSCorrelatingEvents 143 | } 144 | catch [System.Excpetion] 145 | { 146 | Write-Error "No PowerShell Events found for the given timespan." 147 | } 148 | } 149 | 150 | function CorrelateAllMessages($GeneratingEvents, $CorrelatingEvents) 151 | { 152 | Write-Host "Combining all relevant event data." 153 | $ProcessGuids | ForEach-Object{if($CorrelatingEvents.$_){$CorrelatedEvents += @{$_= @($GeneratingEvents.$_, $CorrelatingEvents.$_)}}} 154 | Write-Host "Number of Sysmon Events with correlation match: " $CorrelatedEvents.Count 155 | return $CorrelatedEvents 156 | } 157 | 158 | function WriteCorrelatedEventsToJson($CorrelatedEvents) 159 | { 160 | Write-Host "Saving results to JSON file." 161 | ConvertTo-Json -InputObject $CorrelatedEvents -Depth 4 | Out-File -Append $OutputFilePath"\SysmonCorrelatedEventLog.json" 162 | } 163 | 164 | 165 | function main () 166 | { 167 | $GeneratingEvents = GetSysmonGeneratingEvents 168 | $CorrelatingEvents = GetSysmonCorrelatingEvents 169 | $CorrelatedEvents = CorrelateAllMessages $GeneratingEvents $CorrelatingEvents 170 | WriteCorrelatedEventsToJson $CorrelatedEvents 171 | } 172 | 173 | main -------------------------------------------------------------------------------- /Get-TriageForensics.ps1: -------------------------------------------------------------------------------- 1 | function postResultsToSplunk($input_type, $input_content) 2 | { 3 | echo "[*] sending information to Splunk..." 4 | # Function builds the objects necessary to send results to Splunk's HTTP Event Collector. 5 | $data_to_send = New-Object psobject -Property @{ 6 | 'InputType' = $input_type; 7 | 'InputContent' = $input_content 8 | } 9 | $token = "91C89412-C607-48FE-B0CC-7042A5548A67" 10 | $headers = @{"Authorization" = "Splunk $token"} 11 | $body = @{ 12 | "host" = $env:COMPUTERNAME; 13 | "source" = "IR-triage-script"; 14 | "sourcetype" = "IR-RESTapi"; 15 | "index" = "main"; 16 | "event" = @{ 17 | "case_number" = "EJDIE34500"; 18 | "type" = $input_type 19 | "info" = $input_content; 20 | } 21 | } 22 | 23 | $json_body = ConvertTo-Json -InputObject $body -Compress 24 | Invoke-RestMethod -Method POST -Uri "http://192.168.1.50:8088/services/collector/event" -Headers $headers -ContentType "application/json" -Body $json_body 25 | 26 | } 27 | 28 | 29 | function powerShell5Cmdlets() 30 | { 31 | # Checks PowerShell version, if 5.0 runs the new cmdlets, otherwise runs legacy (WMI) cmdlets. 32 | if ($PSVersionTable.PSVersion.Major -eq 5) 33 | { 34 | 35 | try 36 | { 37 | # Dumps Local User Accounts, whether they are enabled and a description (if given): 38 | $local_users = Get-LocalUser | Select-Object * 39 | 40 | } catch { 41 | 42 | $local_users = "Error running Get-LocalUser cmdlet." 43 | } 44 | 45 | $local_users | ForEach-Object{ postResultsToSplunk 'LocalUsers' $_ } 46 | 47 | try 48 | { 49 | # Grabs all network connection profiles information 50 | $network_profile = Get-NetConnectionProfile 51 | 52 | } catch { 53 | 54 | $network_profile = "Error running Get-NetConnectionProfile cmdlet." 55 | } 56 | 57 | $network_profile | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'NetworkProfile' $_ } 58 | 59 | try 60 | { 61 | # Dumps current DNS cache; very volitale. 62 | $dns_cache = Get-DnsClientCache 63 | 64 | } catch { 65 | 66 | $dns_cache = "Error running Get-DnsClientCache cmdlet." 67 | } 68 | 69 | $dns_cache | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'DnsClientCache' $_ } 70 | 71 | 72 | try 73 | { 74 | # Gets DNS Server Address for each interface. 75 | $dns_server_address = Get-DnsClientServerAddress 76 | 77 | } catch { 78 | 79 | $dns_server_address = "Error running Get-DnsClientServerAddress cmdlet." 80 | } 81 | 82 | $dns_server_address | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'DnsClientServerAddress' $_ } 83 | 84 | } else { 85 | 86 | 87 | try 88 | { 89 | # Gets Local Accounts of the computer using the legacy WMI Objects: 90 | $local_users_wmi = Get-WmiObject -class Win32_UserAccount -Filter "LocalAccount='True'" | Select-Object PsComputername, Name, Status, Disabled, AccountType, Lockout, PasswordRequired, PasswordChangeable, SID 91 | 92 | } catch { 93 | 94 | $local_users_wmi = "Errorr running legacy Local User (WMI) cmdlet." 95 | } 96 | 97 | $local_users_wmi | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'LocalUsers' $_ } 98 | 99 | 100 | try 101 | { 102 | # Gets Computer Hardware information & Last Logged In User information: 103 | $computer_system_info = Write-Output "`nComputerName`t`t: $env:computername"; Get-WmiObject -computer $env:computername -class win32_computersystem | Select-Object Username, Domain, Manufacturer, Model, SystemType, PrimaryOwnerName, TotalPhysicalMemory 104 | 105 | } catch { 106 | 107 | $computer_system_info = "Error running legacy Computer System Information (WMI) cmdlet." 108 | } 109 | 110 | $computer_system_info | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'ComputerSystemInformation' $_ } 111 | 112 | 113 | try 114 | { 115 | # Gets current ip config settings including DNS and Default Gateway settings & converts to JSON: 116 | $ip_dns_config = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.ipaddress -notlike $null} | Select-Object PSComputerName, IPAddress, IPSubnet, DefaultIPGateway, Description, DHCPEnabled, DHCPServer, DNSDomain, DNSDomainSuffixSearchOrder, DNSServerSearchOrder, WINSPrimaryServer, WINSSecondaryServer 117 | $ip_dns_config = $ip_dns_config | Select-Object * | ForEach-Object {$_.IPaddress = $_.IPAddress.Replace("\{",""); $_.DefaultIPGateway = $_.DefaultIPGateway.Replace("\{",""); $_.IPSubnet = $_.IPSubnet.Replace("\{",""); $_} 118 | 119 | } catch { 120 | 121 | $ip_dns_config = "Error running legacy IP/DNS Config (WMI) cmdlet." 122 | } 123 | 124 | $ip_dns_config | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'IpDnsConfig' $_ } 125 | } 126 | } 127 | 128 | 129 | function unprivilegedCmdlets() 130 | { 131 | 132 | try 133 | { 134 | # Gets the current list of services, both running and stopped: 135 | $services = Get-Service 136 | 137 | } catch { 138 | 139 | $services = "Error running Get-Service cmdlet." 140 | } 141 | 142 | $services | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'Services' $_ } 143 | 144 | 145 | 146 | try 147 | { 148 | # Grabs installed software. 149 | $registry_software = Get-ChildItem "HKLM:\Software" 150 | 151 | } catch { 152 | 153 | $registry_software = "Error running Get-ChildItem on HKLM:\Software registry key." 154 | } 155 | 156 | $registry_software | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'RegistrySoftware' $_ } 157 | 158 | 159 | 160 | try 161 | { 162 | # Grabs System information from the Registry 163 | $registry_system = Get-ChildItem "HKLM:\System" 164 | 165 | } catch { 166 | 167 | $registry_system = "Error running Get-ChildItem on HKLM:\System registry key." 168 | } 169 | 170 | $registry_system | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'RegistrySystem' $_ } 171 | 172 | 173 | 174 | $tasks = @() 175 | function getTasks($path) 176 | { 177 | # Function & required COM object to retrieve all scheudled tasks: 178 | $out = @() 179 | 180 | $schedule.GetFolder($path).GetTasks(0) | ForEach-Object { 181 | $xml = [xml]$_.xml 182 | $out += New-Object psobject -Property @{ 183 | "Name" = $_.Name 184 | "Path" = $_.Path 185 | "LastRunTime" = $_.LastRunTime 186 | "NextRunTime" = $_.NextRunTime 187 | "Actions" = ($xml.Task.Actions.Exec | ForEach-Object {"$($_.Command) $($_.Arguments)"}) 188 | } 189 | } 190 | 191 | $schedule.GetFolder($path).GetFolders(0) | ForEach-Object { 192 | $out += getTasks($_.Path) 193 | } 194 | 195 | $out 196 | } 197 | 198 | try 199 | { 200 | $schedule = New-Object -ComObject "Schedule.Service" 201 | $schedule.Connect() 202 | 203 | $tasks += getTasks("\") 204 | } catch { 205 | $tasks = "Error retrieving Scheduled Tasks list." 206 | } 207 | $tasks | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'ScheduledTasks' $_ } 208 | 209 | 210 | # Get PowerShell Transcriptions from C:\temp\PowerShellLogs 211 | try 212 | { 213 | $default_transcription_path = 'C:\temp\PowerShellLogs' 214 | $transcription_file_path = Get-ItemProperty "HKLM:\software\Policies\Microsoft\Windows\PowerShell\Transcription" | Select-Object -ExpandProperty OutputDirectory 215 | if (Test-Path -Path $default_transcription_path) 216 | { 217 | $ps_transcription_logs = Get-ChildItem C:\temp\PowerShellLogs\ | ForEach-Object{Get-Content C:\temp\PowerShellLogs\$_} 218 | 219 | } 220 | elseif ($transcription_file_path -ne $default_transcription_path) 221 | { 222 | $ps_transcription_logs = Get-ChildItem $transcription_file_path | ForEach-Object{Get-Content $transcription_file_path\$_} 223 | 224 | } else { 225 | $ps_transcription_logs = "[!] Error: PowerShell Log directory doesn't exist." 226 | } 227 | } catch { 228 | 229 | $ps_transcription_logs = "Error retrieving PowerShell Transcription logs. Is Transcription enabled on this machine?" 230 | } 231 | 232 | $ps_transcription_logs | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'PowerShellTranscriptionLogs' $_ } 233 | 234 | 235 | 236 | try 237 | { 238 | # Write PowerShell log metadata: 239 | $getScriptBlockLog = Get-WinEvent -FilterHashTable @{ 240 | LogName = "Microsoft-Windows-PowerShell/Operational"; 241 | ID = 4102, 4103, 4104 242 | } 243 | } catch { 244 | 245 | $getScriptBlockLog = "Error retrieving Deep Script Block logs." 246 | } 247 | 248 | $getScriptBlockLog | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'PowerShellLogs' $_ } 249 | 250 | # Prints the detailed Script Block Log message of each event. 251 | # $getScriptBlockLog.Message 252 | 253 | try 254 | { 255 | # Write New Process Creation log metadata: 256 | $newProcessCreation = Get-WinEvent -FilterHashTable @{ 257 | LogName = "Security"; 258 | ID = 4688 259 | } 260 | } catch { 261 | 262 | $newProcessCreation = "Error retrieving New Process Creation (ID=4688) from Security logs." 263 | } 264 | 265 | $newProcessCreation | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'WinEventLogsSecurity' $_} 266 | 267 | # Prints the detailed message for each event. 268 | # $newProcessCreation.Message 269 | 270 | # Gets a list of drives configured &or connected to the machine. 271 | try 272 | { 273 | $drives = Get-PSDrive 274 | 275 | } catch { 276 | 277 | $drives = "Error getting drives list." 278 | } 279 | 280 | $drives | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'PSDrive' $_ } 281 | } 282 | 283 | 284 | ### REQUIRES ELEVATED PRIVILEGES ### 285 | 286 | function privilegedCmdlets(){ 287 | # TODO: Find the WMI Object to retreive this information so it will parse correctly in Splunk. 288 | # Grabs Network Statistics for all connections. Requires Elevated Privileges. 289 | try 290 | { 291 | $network_connections_object = @() 292 | $network_connections = netstat.exe -ano | Select-String -Pattern "established", "listening" 293 | foreach ($line in $network_connections) 294 | { 295 | # Formatting flat netstat.exe results into a PowerShell Object 296 | # Remove leading whitespace. 297 | $line = $line -replace '^\s+','' 298 | 299 | # Split each line by the whitespace. 300 | $line = $line -split '\s+' 301 | 302 | $ProcessIDName = Get-Process -Id $line[4] | Select-Object -Property ProcessName 303 | 304 | # Define the properties for each Object. 305 | $properties = @{ 306 | Protocol = $line[0] 307 | LocalAddressIP = ($line[1] -split ":")[0] 308 | LocalAddressPort = ($line[1] -split ":")[1] 309 | ForeignAddressIP = ($line[2] -split ":")[0] 310 | ForeignAddressPort = ($line[2] -split ":")[1] 311 | State = $line[3] 312 | ProcessIDNumber = $line[4] 313 | ProcessIDName = $ProcessIDName.ProcessName 314 | } 315 | # echo $properties 316 | $network_connections_object += New-Object -TypeName PSObject -Property $properties 317 | } 318 | 319 | } catch { 320 | 321 | $network_connections_object = "Error retrieving network connection information." 322 | } 323 | 324 | $network_connections_object | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'NetworkConnections' $_ } 325 | 326 | # OR 327 | # Not sure if I can identify the owning process with the PowerShell Module. 328 | # Doesn't appear that I can get the Owning Process from this module. 329 | # Get-NetTCPConnection 330 | # Lists directory information for the currently logged in user: 331 | 332 | try 333 | { 334 | # DO without option -Hidden for the viewable stuff, do with option -Hidden to see Hidden folders only! 335 | 336 | $user_filepath = "C:\Users\$env:USERNAME" 337 | 338 | $user_folder = Get-ChildItem $user_filepath 339 | 340 | $user_subfolders = $user_folder | ForEach-Object{ Get-ChildItem $user_filepath/$_ } 341 | 342 | #Use to get recursion and to get file hashes 343 | Get-ChildItem | %{ if($_.Mode -like "d*"){ echo "$_ is a directory!"} 344 | 345 | } catch { 346 | 347 | $user_subfolders = "Error getting the directory listing of the user directory and/or subdirectories." 348 | } 349 | 350 | $user_subfolders | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'UserSubFolders' $_ } 351 | 352 | 353 | 354 | # Gets a list of the running processes and what program started that process. 355 | # -IncludeUserName option requires Elevated Privileges 356 | try 357 | { 358 | $process_list = Get-Process -IncludeUserName 359 | 360 | } catch { 361 | 362 | $process_list = "Error running Get-Process cmdlet with -IncludeUserName option. Were you running as Admin?" 363 | } 364 | 365 | $process_list | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'Processes' $_ } 366 | 367 | 368 | # Grabs the directory listing of the Prefetch 369 | # Must be run with Elevated Privileges 370 | try 371 | { 372 | $prefetch_listing = Get-ChildItem -Hidden C:\Windows\Prefetch 373 | 374 | } catch { 375 | 376 | $prefetch_listing = "Error retrieving the prefetch directory listing." 377 | } 378 | 379 | $prefetch_listing | ForEach-Object{ $_ | Select-Object * | ConvertTo-Json -Compress; postResultsToSplunk 'Prefetch' $_ } 380 | 381 | } 382 | 383 | 384 | # get NTUSER.dat 385 | 386 | function main() 387 | { 388 | # Calls function containing PowerShell 5 only commands, or if running < 5.0 their WMI equivalents 389 | try 390 | { 391 | echo "trying powershell 5 commands..." 392 | powerShell5Cmdlets 393 | 394 | } catch { 395 | 396 | $error = "Error running powerShell5Cmdlets." 397 | echo $error 398 | postResultsToSplunk 'ERROR' $error 399 | } 400 | 401 | # Runs all the cmdlets that don't required elevated privileges 402 | try 403 | { 404 | echo "trying unprivileged cmdlets..." 405 | unprivilegedCmdlets 406 | 407 | } catch { 408 | 409 | $error = "Error running unprivilegedCmdlets." 410 | postResultsToSplunk 'ERROR' $error 411 | } 412 | 413 | # Checks to see if the script is running with elevated privileges and executes the privilegedCmdlets if True 414 | if( ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` 415 | [Security.Principal.WindowsBuiltInRole]"Administrator")){ 416 | 417 | try 418 | { 419 | echo "running as an administrator; trying privileged cmdlets...." 420 | privilegedCmdlets 421 | 422 | } catch { 423 | 424 | $error = "Error running privilegedCmdlets." 425 | postResultsToSplunk 'ERROR' $error 426 | } 427 | 428 | } else { 429 | 430 | $no_admin = "Script not running as an administrator, skipping privilegedCmdlets" 431 | postResultsToSplunk 'ERROR' $no_admin 432 | } 433 | 434 | 435 | } 436 | 437 | main --------------------------------------------------------------------------------