PowerShell Intrusion Analysis
Introduction
PowerShell has become an indispensable tool in Digital Forensics and Incident Response (DFIR), offering unparalleled flexibility and efficiency for investigating and responding to cyber incidents. As a robust command-line shell and scripting language, PowerShell is built into Windows operating systems, making it readily accessible for both system administrators and DFIR analysts.
Its importance lies in its ability to query, interact with, and manipulate nearly every aspect of a Windows system. PowerShell provides analysts with powerful cmdlets and scripts to gather forensic artefacts, analyse logs, investigate execution activity, and automate repetitive tasks. Furthermore, its deep integration with Windows APIs and system internals allows for rapid data collection and analysis during an active investigation.
In addition to its forensic capabilities, PowerShell is a critical tool for incident response. It can be used to identify active threats, terminate malicious processes, block network connections, and remediate compromised systems in real-time. However, its power also makes it a favourite tool of attackers, emphasising the need for DFIR professionals to understand its capabilities fully—not only to leverage it for defence but also to detect its misuse.
Mastering PowerShell equips DFIR practitioners with the skills to efficiently analyse systems, respond to threats, and bolster an organisation\u2019s cybersecurity posture in today\u2019s fast-paced and complex threat landscape.
Get General insight and System Information
Get System Information:
Get-ComputerInfoGet Operating System Details:
Get-WmiObject -Class Win32_OperatingSystemGet Hardware Information:
Get-WmiObject -Class Win32_ComputerSystemGet Installed Software:
Get-WmiObject -Class Win32_ProductCheck For Local User Accounts:
Get-LocalUserGet the last logon time for the user “John” by using
net user
net user John | Select-String "Last logon"Retrieve information about users and their last logon times:
Get-LocalUser | Select-Object Name, Enabled, LastLogonGet more detailed information, including last logon times
Get-LocalUser | ForEach-Object {
$user = $_.Name
$details = net user $user
[PSCustomObject]@{
UserName = $user
Enabled = $_.Enabled
FullName = ($details | Select-String "Full Name" | ForEach-Object { $_ -replace ".*Full Name *" })
LastLogon = ($details | Select-String "Last logon" | ForEach-Object { $_ -replace ".*Last logon *" })
}
} | Format-Table -AutoSizeLet's say John is a suspicious user here, and we need to investigate this. Retrieve detailed information about the user John:
Get-LocalUser -Name John | Format-List *List the groups that the user John is a member of
Get-LocalGroup | ForEach-Object {
$group = $_.Name
$members = Get-LocalGroupMember -Group $group
$members | Where-Object { $_.Name -eq "John" } | Select-Object @{Name="GroupName";Expression={$group}}, Name }Networking Information Gathering
Get network configuration
Get-NetIPConfiguration
# Search for select properties:
Get-NetIPConfiguration | Select-Object -Property InterfaceAlias, IPv4Address, IPv6Address, DNServerGet active network connections
Get-NetTCPConnection
Get-NetIPAddress
# Search for specific port:
Get-NetTCPConnection | Where-Object { $_.LocalPort -eq 443 } | Select-Object OwningProcess, RemoteAddress, RemotePort | Sort-Object OwningProcess | Get-UniqueGet DNS information
Get-DnsClientServerAddressCheck if there is a record defined with
Resolve-DnsNameList network routes now
Get-NetRouteWe need to do some more detailed research
Get-NetTCPConnection | Where-Object { $_.RemoteAddress -eq "10.34.2.3" -and $_.LocalPort -eq 445 } | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcessAnd
Get-NetTCPConnection | Where-Object { $_.RemoteAddress -eq "10.34.2.3" -and $_.LocalPort -eq 139 } | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcessTo see if ports 139 and 445 are actively listening on your system
Get-NetTCPConnection | Where-Object { $_.LocalPort -eq 139 -or $_.LocalPort -eq 445 -or $_.RemotePort -eq 139 -or $_.RemotePort -eq 445 }To inspect firewall rules related to ports 139 and 445
Get-NetFirewallRule | Where-Object { $_.LocalPort -eq 139 -or $_.LocalPort -eq 445 }To identify which processes are using ports 139 or 445
Get-Process -IncludeUserName | Where-Object { $_.TCPConnections.LocalEndPoint.Port -eq 139 -or $_.TCPConnections.LocalEndPoint.Port -eq 445 }To verify SMB configuration and settings
Get-SmbServerConfiguration
Get-SmbClientConfigurationDetermine if the machine is part of an Active Directory (AD) domain
(Get-WmiObject Win32_ComputerSystem).PartOfDomainRetrieve more detailed information about the domain membership
Get-WmiObject Win32_ComputerSystem | Select-Object Domain, DomainRoleUser Accounts and Groups
Inspect user accounts and groups
Get-LocalUser | Select-Object Name, Enabled, LastLogon
Get-LocalGroup | Select-Object Name, DescriptionCheck membership for suspect user “John” in each group
Get-LocalGroupMember -Group "Administrators"
Get-LocalGroupMember -Group "Users"
Get-LocalGroupMember -Group "Remote Desktop Users"Check for the privilege of the suspect user
#Check for user "Jenny"
$UserName = "Jenny"
Get-LocalGroupMember -Group "Administrators" | Where-Object { $_.Name -eq $UserName }
Get-LocalGroupMember -Group "Users" | Where-Object { $_.Name -eq $UserName }
Get-LocalGroupMember -Group "Remote Desktop Users" | Where-Object { $_.Name -eq $UserName }Check if the user “John” has any scheduled tasks:
Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "John" } | Select-Object TaskName, State, ActionsCheck if the user “Jenny” has any scheduled tasks:
Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "Jenny" } | Select-Object TaskName, State, ActionsGet Schedule Task Information
Get general information about tasks:
Get-ScheduledTaskGet some general details about scheduled tasks
Get-ScheduledTask | Get-ScheduledTaskInfo | Select-Object TaskName, ActionsTo determine if a scheduled task is suspicious, focus on understanding its purpose, verifying its actions, and comparing it against known legitimate tasks in your environment.
Use:
Get-ScheduledTask -TaskName "GameOver" | Get-ScheduledTaskInfo | Select-Object TaskName, ActionsUse:
Get-ScheduledTask -TaskName "falshupdate22" | Get-ScheduledTaskInfo | Select-Object TaskName, Actions"You need to specifically look at the Clean file system entry. This is highly suspicious and attempts to destroy evidence or something like that. You can use PowerShell commands effectively to gather detailed information about a scheduled task, including its properties and actions.
Use:
$task = Get-ScheduledTask | Where TaskName -EQ "Clean file system"
$task
$task.ActionsDisplay all properties for a detailed analysis of the task now
$task = Get-ScheduledTask | Where-Object { $_.TaskName -eq "NameOfSuspiciousTask" }
$task | Format-List * # Display all properties for detailed analysis
$task.Actions # Display actions configured for the task
$task.Triggers # Display triggers configured for the taskYou can perform a detailed analysis of a task by running the following
# Retrieve the scheduled task object
$task = Get-ScheduledTask -TaskName "Clean file system"
# Display all properties of the scheduled task
$task | Format-List *
# Display actions configured for the task
$task.Actions
# Display triggers configured for the task
$task.Triggers
# Display settings and security descriptor
$task.Settings
$task.SecurityDescriptor
# Display task principal and version
$task.Principal
$task.VersionThe MSFT_TaskDailyTrigger class provides properties that define how often the task runs, at what time, and any intervals or repetitions required. Here are some key properties of MSFT_TaskDailyTrigger
Then use it:
$trigger = Get-ScheduledTask -TaskName "Clean file system" | Select-Object -ExpandProperty Triggers | Where-Object { $_.GetType().Name -eq 'MSFT_TaskDailyTrigger' }
$trigger | Format-List *Or you can use:
# Retrieve the scheduled task object
$task = Get-ScheduledTask -TaskName "Clean file system"
# Display triggers configured for the task
$task.Triggers | Where-Object { $_.GetType().Name -eq 'MSFT_TaskDailyTrigger' } | Format-List *Check Startup Programs
To access and display the values under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
# Define the path to the registry key
$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
# Get the registry key properties
Get-ItemProperty -Path $registryPathGet Processes
Get-ProcessReview the security event logs for login activities related to the user “John”:
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624} | Where-Object { $_.Properties[5].Value -eq "John" } | Select-Object TimeCreated, Id, MessageInvestigate if the user “John” and “Jenny” has any scheduled tasks:
Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "John" } | Select-Object TaskName, State, ActionsGet-ScheduledTask | Where-Object { $_.Principal.UserId -eq "Jenny" } | Select-Object TaskName, State, ActionsCheck for processes currently running under the user “John”:
Get-Process | Where-Object { $_.StartInfo.UserName -eq "John" } | Select-Object Name, Id, CPU, PathLook for activities performed by the user “John” in the system and application event logs:
Get-WinEvent -FilterHashtable @{LogName='System'; Level=2} | Where-Object { $_.Properties[1].Value -eq "John" } | Select-Object TimeCreated, Id, MessageNow let’s get general details via System logs:
Get-WinEvent -FilterHashtable @{LogName=’System’; Level=2}Get the scheduled tasks:
Get-ScheduledTask | Format-Table -AutoSizeDouble-check the daily running task:
(Get-ScheduledTask -TaskName "Clean file system").ActionsGet more detailed information about this:
Get-ScheduledTask -TaskName "Clean file system" | Select-Object *We have witnessed suspicious scripts and activities found in the TMP location.
Check the contents of the Temp file location:
Get-ChildItem C:\Temp | Select-Object Name, CreationTimeIdentify if any running processes are executing from the TMP directory:
Get-Process | Where-Object { $_.Path -like "$env:TEMP*" } | Select-Object Id, ProcessName, PathLook at the contents of some files in TMP:
Get-Content C:\Temp\mim-out.txtTake a look at the startup entries again:
Get-CimInstance -ClassName Win32_StartupCommandLook at the security logs again:
Get-WinEvent -LogName "Security"Look for logs signed with 4672 or other Eventlog
Create a detailed query:
$Specials = Get-WinEvent -LogName "Security" | Where-Object {$_.Id -eq "4672"}Check for any suspicious registry entries that might point to Temp:
Get-ChildItem -Path HKLM:\Software\Microsoft\Windows\CurrentVersion | Get-ItemPropertyGet a registry entry associated with a suspect file, for instance, mim.exe
Get-ItemProperty -Path "HKCU:\Environment" -Name UserInitMprLogonScriptCheck the properties of mim.exe to gather more information about it:
$mimPath = Get-ItemProperty -Path "HKCU:\Environment" -Name UserInitMprLogonScript | Select-Object -ExpandProperty UserInitMprLogonScript
Get-Item -Path $mimPath | Select-Object FullName, LastWriteTime, Length
# Or just define manually
$mimPath = 'C:\TMP\mim.exe'
Get-Item -Path $mimPath | Select-Object FullName, LastWriteTime, LengthCheck digital signatures to verify if mim.exe is digitally signed:
Get-AuthenticodeSignature -FilePath $mimPathCompute the hash of the file and check it against known malware databases like VirusTotal
Get-FileHash -Path $mimPath -Algorithm SHA256Check if there are any scheduled tasks related to mim.exe.
Get-ScheduledTask | Where-Object { $_.Actions.Exec.Path -eq $mimPath }Check for other startup entries that might reference mim.exe.
Get-CimInstance -ClassName Win32_StartupCommand | Where-Object { $_.Command -like "*mim.exe*" }Below, we can write two more queries that you can use for log files.
Get-WinEvent -LogName Security | Where-Object { $_.Message -like "*mim.exe*" }
Get-WinEvent -LogName Application | Where-Object { $_.Message -like "*mim.exe*" }Determine the system information and user details
Get-ComputerInfo
Get-LocalUser
Get-LocalUser | Select-Object Name, Enabled, LastLogonCheck group memberships for a user
Get-LocalGroupMember -Group "Administrators"
Get-LocalGroupMember -Group "Users"Check the profile path and home directory for the user, for instance, "sam"
Get-LocalUser -Name sam | Select-Object Name, PrincipalSource, Enabled, LastLogon, Description, SIDGet the system event log
Get-WinEvent -LogName System | Sort-Object TimeCreated
Get-WinEvent -LogName Security | Sort-Object TimeCreated
Get-WinEvent -LogName Application | Sort-Object TimeCreatedTo reveal registry added or changing activity using Get-WinEvent for the System log, you can filter for specific Event IDs related to registry changes. Common Event IDs for registry changes include:
4656: A handle to an object was requested.
4657: A registry value was modified.
4663: An attempt was made to access an object.
4659: A handle to an object was requested with the intent to delete. You can use:
$eventIds = @(4656, 4657, 4663, 4659)
Get-WinEvent -LogName System | Where-Object { $eventIds -contains $_.Id } | Select-Object -First 10For a word-based search, the following command is useful:
Get-WinEvent -LogName System | Select-Object TimeCreated, Id, Message | Where-Object { $_.Message -like "*registry*" } | Sort-Object TimeCreatedScheduled tasks might be used to execute the malicious scripts periodically or at specific events:
Get-ScheduledTask | Select-Object TaskName, State, Actions | Format-Table -AutoSizeIf PowerShell was used to execute commands, you can check the PowerShell history:
Get-Content -Path "$env:USERPROFILE\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt" | Select-Object -Last 50Startup programs could include the malicious payload or its components:
Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" | Format-Table -AutoSizeLet’s create a query for events:
Get-WinEvent -ListLog * | findstr "Print"Circular Log Type: This indicates that the log file is configured to overwrite old entries with new ones once the log reaches its maximum size. This is useful for logs that accumulate data continuously.
Size: The size of the log file in bytes.
Number of Entries: The number of events currently logged in that file. For example, We found events recorded as Admin and Operational. Investigate it:
Get-WinEvent -FilterHashtable @{logname="Microsoft-Windows-PrintService/Admin"} | fl -property *If you want to search for specific patterns in the log files, you can use Select-String as follows:
# Search for a specific pattern in the PrintService Operational log
Get-WinEvent -LogName "Microsoft-Windows-PrintService/Admin" | Select-Object -ExpandProperty Message | Select-String "Print"Verify that a file, for example, ualapi.dll is legitimate and hasn’t been tampered with:
Get-Item "C:\Windows\System32\ualapi.dll" | Get-AuthenticodeSignatureObtain the process information defined in the ualapi.dll file event:
Get-WinEvent -LogName Application | Where-Object { $_.Message -like "*ualapi.dll*" } | Select-Object TimeCreated, Id, Message | Format-Table -AutoSizeOr:
Get-WinEvent -LogName System -FilterXPath "*[System/EventID=13]" | Where-Object { $_.Message -like "*ualapi.dll*" } | Sort-Object TimeCreated | Format-List -Property *PowerShell Incident Response Resources
Powershell Digital Forensics & Incident Response (DFIR) - The repository contains multiple PowerShell scripts that can help you respond to cyber attacks on Windows Devices. (Credit Bert-JanP)
PowerShell Commands for Incident Response - Learn different PowerShell Commands that can be used in Incident Response to remediate the machine. (written by Ayush Anand)
How to Run PowerShell Script on Remote Computers - The article looks at several examples of how to use PowerShell Remoting interactive session mode and persistent connections to run PS1 a script on a remote computer. (written by Cyril Kardashevsky )
CyberRaiju - Digital Forensics and Incident Response (written by Jai Minton)
Last updated