Forensic Investigation Operations — Windows Base I

Baris Dincer
18 min readJul 17, 2024

--

In this series of articles, we will show you in a laboratory environment what kind of analysis you should perform against Windows machines that have been hacked or are somehow compromised in the system. In the scenario in the lab environment, we will be showing the threat intelligence capabilities and some DFIR methods we have.

You may see that the IPs change from time to time, do not care, we will be using different machines as we progress. The entire methodology is the same.

The machine we will use in this scenario was hacked by a hacker, this is the only fact we know. We must discover the evidence in the system and the attacker’s mentality.

First, let’s get a general insight and information about the system.

Get system information: Get-ComputerInfo

output
output
output

Based on the output, we have some useful information about the system.

  • Operating System: Windows Server 2016 Datacenter
  • Build Information: 14393.2791.amd64fre.rs1_release.190205–1511
  • Installation Date: March 2, 2019
  • Product ID: 00376–40000–00000-AA753
  • Registered Organization: Amazon.com
  • Registered Owner: EC2 (indicating it’s likely an AWS EC2 instance)
  • BIOS Version: Default System BIOS by Amazon

Get operating system details: Get-WmiObject -Class Win32_OperatingSystem

output

You get a summary with the above command.

Get hardware information: Get-WmiObject -Class Win32_ComputerSystem

output

Based on this additional information, we know:

  • Domain: WORKGROUP (not joined to a domain)
  • Manufacturer: Amazon EC2
  • Model: t3.small (instance type)
  • System Name: EC2AMAZ-I8UHO76
  • Primary Owner Name: EC2
  • Total Physical Memory: Approximately 2 GB

Get installed softwares: Get-WmiObject -Class Win32_Product

The list you get from here may be long. However, if there is a software or application that catches your eye and should not normally be there, you should take note.

output

Amazon SSM Agent:

  • Vendor: Amazon Web Services
  • Version: 2.3.444.0
  • Purpose: Amazon SSM Agent is used for managing and configuring AWS instances via AWS Systems Manager.

AWS Tools for Windows:

  • Vendor: Amazon Web Services
  • Version: 3.15.666
  • Purpose: A set of tools and utilities to interact with AWS services from Windows environments.

AWS PV Drivers:

  • Vendor: Amazon Web Services
  • Version: 8.2.6
  • Purpose: Paravirtual drivers for better performance of AWS instances.

aws-cfn-bootstrap:

  • Vendor: Amazon Web Services
  • Version: 1.4.31
  • Purpose: Utilities for AWS CloudFormation to bootstrap instances.

Now let’s check the information of existing users: Get-LocalUser

output

We have users:

  • Administrator
  • DefaultAccount
  • Guest
  • Jenny
  • John

The cyber attack may have been carried out through one of these users.

Get the last logon time for the user “John” by using net user command: net user John | Select-String “Last logon”

output

To retrieve information about users and their last logon times, you can use the following PowerShell commands: Get-LocalUser | Select-Object Name, Enabled, LastLogon

output

John logged in in the evening of 3/2/2019, which matches the time period of the attack.

To get more detailed information, including last logon times, you can use the NetUser command:

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 -AutoSize
output

John is a suspicious user here, we need to investigate this. Retrieve detailed information about the user “John”: Get-LocalUser -Name John | Format-List *

output

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
}

It retrieves nothing.

  • Enabled: True (The account is active)
  • PasswordRequired: True (A password is required for the account)
  • UserMayChangePassword: True (The user is allowed to change their password)
  • PasswordLastSet: 3/2/2019 5:48:19 PM (This seems to be an incomplete date; we need to verify this information)
  • LastLogon: 3/2/2019 5:48:32 PM (This also appears incomplete and needs verification)
  • SID: S-1–5–21–3685962493–259677494–3116396707–1009 (A unique identifier for the user account)
  • PrincipalSource: Local (The account is local to this machine)

Password setting and change dates are critical. There is still a doubt here. Make a note of these.

We will get back to analyzing this user in detail. Before that let’s continue with our general forensics approaches.

Get network configuration: Get-NetIPConfiguration

output

Get active network connections: Get-NetTCPConnection

output

Here we discovered a connection to an external IP, which could be an internal IP or the attacker’s C2 server. For this reason, you should learn the network structure of the system you will analyze. Other IPs:

  • 20.12.23.50
  • 23.72.36.34
  • 10.34.2.3
  • 10.100.2.58

Now use Get-NetIPAddress:

output
output

Check the values, network interface and IP information defined here carefully. If you see anything suspicious, make a note of it.

Let’s try to get DNS information: Get-DnsClientServerAddress

output

Check if there is a record defined with the Resolve-DnsName command.

output

We captured the records of those defined in the internal structure, but there are also values ​​that are not defined. You can also do this manually by accessing the following file: C:\ > Windows > System32 > drivers > etc

Use: type C:\Windows\System32\drivers\etc\hosts

output

What google.com

The /etc/hosts file is used to map hostnames to IP addresses locally, bypassing DNS resolution. If an entry for google.com or www.google.com exists in the /etc/hosts file, it could potentially be used to redirect traffic intended for Google to a malicious server.

Just ping it.

output

This is not a real IP of google.com. For this reason, it may be a C2 server.

List network routes now: Get-NetRoute

output

We 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, OwningProcess

And:

Get-NetTCPConnection | Where-Object { $_.RemoteAddress -eq “10.34.2.3” -and $_.LocalPort -eq 139 } | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess

You probably won’t get any answers.

We made these queries over an IP that we exposed. You can try to write our own machine IP value and try it.

The following 10.34.2.3 IP connects remotely to ports 139 and 445.

Port 139 (NetBIOS Session Service)

  • Protocol: NetBIOS (Network Basic Input/Output System)
  • Description: Port 139 was originally used by the NetBIOS Session Service for communication between machines on a LAN. It facilitates the establishment of sessions for communication, such as file sharing and printer sharing.
  • Usage: In modern environments, Port 139 is typically used for legacy SMB operations and NetBIOS over TCP/IP (NetBT).

Port 445 (SMB over TCP)

  • Protocol: SMB (Server Message Block)
  • Description: Port 445 is used by SMB to provide file and printer sharing services over TCP/IP. It supports more efficient and secure operations compared to the older NetBIOS-based methods using Port 139.
  • Usage: Port 445 is the default port for SMB operations in modern Windows operating systems and is used for various tasks including file sharing, remote administration, and communication between Windows machines.

To 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 }

output

Yes. They are active.

To inspect firewall rules related to ports 139 and 445: Get-NetFirewallRule | Where-Object { $_.LocalPort -eq 139 -or $_.LocalPort -eq 445 }

Nothing to show. A security layer may not have been specified for these.

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 }

This command lists processes and their associated users that have active TCP connections on ports 139 or 445. We couldn’t get anything from here either.

To verify SMB configuration and settings:

Get-SmbServerConfiguration
Get-SmbClientConfiguration
output
output

You should check whether there is a general security hole in such outputs. These settings govern various aspects of how the SMB client interacts with servers, manages caches, handles file operations, and maintains connections. Understanding and configuring these parameters appropriately can optimize performance and security in SMB environments.

For example, EnableInsecureGuestLogons: Allows , parameter is a very risky approach.

To fix this, you can use the following command: Set-SmbClientConfiguration -EnableInsecureGuestLogons $false

EnableInsecureGuestLogons:

  • Risk: Enabling insecure guest logons (where authentication is not required) can lead to unauthorized access and security breaches, especially if sensitive data or resources are accessible via SMB shares.

EnableSecuritySignature and RequireSecuritySignature:

  • Risk: Disabling or improperly configuring SMB signing (security signatures) can expose the system to man-in-the-middle attacks and unauthorized data tampering.

EnableMultiChannel:

  • Risk: While multi-channel can improve performance by using multiple network connections, improper configuration or lack of authentication across channels can be exploited by attackers.

OplocksDisabled:

  • Risk: Opportunistic locks (oplocks) improve performance by caching data locally, but disabling them can increase the risk of data corruption and concurrency issues.

EnableLargeMtu:

  • Risk: Enabling large MTU (Maximum Transmission Unit) sizes without appropriate network infrastructure support can lead to fragmentation issues and potential denial-of-service (DoS) attacks.

EnableLoadBalanceScaleOut:

  • Risk: Load balancing across multiple connections can enhance performance, but improper configuration or lack of authentication and authorization controls can introduce security vulnerabilities.

EnableByteRangeLockingOnReadOnlyFiles:

  • Risk: Allowing byte range locking on read-only files might expose files to unintended modifications or access.

EnableBandwidthThrottling:

  • Risk: Inappropriate or misconfigured bandwidth throttling settings can impact performance or lead to ineffective traffic management, affecting overall network stability and security.

You should think about all these parameters.

To determine if the machine is part of an Active Directory (AD) domain, you can use the following PowerShell command: (Get-WmiObject Win32_ComputerSystem).PartOfDomain

output

We may not be in AD.

Additionally, you can retrieve more detailed information about the domain membership: Get-WmiObject Win32_ComputerSystem | Select-Object Domain, DomainRole

output
  • Domain: The computer is currently not joined to a domain (WORKGROUP).
  • DomainRole: The domain role code 2 typically corresponds to a standalone workstation or member server in a workgroup environment.

Domain parameter indicates the domain name to which the computer is joined. In this case, WORKGROUP suggests that the computer is not part of an Active Directory domain but rather is in a workgroup configuration.

Inspect user accounts and groups now:

Get-LocalUser | Select-Object Name, Enabled, LastLogon
Get-LocalGroup | Select-Object Name, Description
output
output

There are many group definitions. We can see which user we suspect belongs to. User is John.

Check membership for user “John” in each group:

Get-LocalGroupMember -Group "Administrators"
Get-LocalGroupMember -Group "Users"
Get-LocalGroupMember -Group "Remote Desktop Users"
output

Jenny? This user appeared before us.

output

John is only in the “Users” group.

Specifically, you can follow the steps below to control privilege:

# 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, Actions

Check if the user “Jenny” has any scheduled tasks: Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq “Jenny” } | Select-Object TaskName, State, Actions

output

There is no defined output. Interesting…

Get general information about tasks then:

output

Pay attention to the first 6 definitions… This is quite suspicious. You can get a general detail about these: Get-ScheduledTask | Get-ScheduledTaskInfo | Select-Object TaskName, Actions

output

To 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, Actions

Use: Get-ScheduledTask -TaskName “falshupdate22” | Get-ScheduledTaskInfo | Select-Object TaskName, Actions

output

Now we need to specifically look at the Clean file system entry. This is highly suspicious and attempts to destroy evidence or something like that. To gather detailed information about a scheduled task, including its properties and actions, you can use PowerShell commands effectively.

Use:

$task = Get-ScheduledTask | Where TaskName -EQ “Clean file system”
$task
$task.Actions
output

We found nc.ps1. There is a task buried here that probably belongs to Netcat. Control it.

output

This is real proof.

Display all properties for detailed analysis about 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 task
output

We see a script that allows you to get a reverse shell hidden under the task name Clean File System. This attempt is likely to bypass security protocols.

Monitor network activity using tools like netstat or PowerShell commands to check for any suspicious connections established by nc.ps1:

Get-NetTCPConnection | Where-Object { $_.OwningProcess -eq (Get-Process -Id $pid).Id }

We could not find any output.

You can perform a detailed analysis of a task by running the following commands one by one. Note these.

# 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.Version
output
output

It’s quite dangerous. There is a task token opened under Administrator authority.

The MSFT_TaskDailyTrigger is a specific type of trigger used in Windows Task Scheduler that specifies a task should run daily. It is part of the Windows Management Instrumentation (WMI) classes used to manage and configure scheduled tasks.

The 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:

  • Id: A unique identifier for the trigger.
  • StartBoundary: The date and time when the trigger is activated.
  • EndBoundary: The date and time when the trigger is deactivated.
  • Enabled: Indicates whether the trigger is enabled or not.
  • DaysInterval: Specifies the interval in days between each run of the task. For example, a value of 1 means the task runs every day.
  • RandomDelay: Specifies a random delay time for the task to run after the trigger is activated.

Then use it:

$trigger = Get-ScheduledTask -TaskName "Clean file system" | Select-Object -ExpandProperty Triggers | Where-Object { $_.GetType().Name -eq 'MSFT_TaskDailyTrigger' }
$trigger | Format-List *

This is a general example for you.

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 *

The HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run registry key is used to specify programs that run when a user logs on. This key is often used to ensure that certain applications or services start automatically when the system boots up or a user logs in. This can be legitimate software like antivirus programs, but it is also a common location for malware to set itself to run automatically on system startup.

To access and display the values under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run registry key using PowerShell, you can use the Get-ItemProperty cmdlet:

# Define the path to the registry key
$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"

# Get the registry key properties
Get-ItemProperty -Path $registryPath
output

Wow! We saw an IP that we previously identified as suspicious interacting. What is p.exe? You can also subject the .exe file you find here to external forensic analysis.

output

Now get firewall rules: Get-NetFirewallRule

output

If you can discover a change here that is not normally present, you should investigate.

Now get processes: Get-Process

output

Analyze questionable approaches here.

Review 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, Message
output

We have accessed the log record of the login activity.

Investigate if the user “John” and “Jenny” has any scheduled tasks:

Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "John" } | Select-Object TaskName, State, Actions
Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq "Jenny" } | Select-Object TaskName, State, Actions

Check for processes currently running under the user “John”:

Get-Process | Where-Object { $_.StartInfo.UserName -eq "John" } | Select-Object Name, Id, CPU, Path

Look 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, Message

There is no clear evidence so far. Now let’s get a general detail: Get-WinEvent -FilterHashtable @{LogName=’System’; Level=2}

output

We discovered some interesting interactions.

Now let’s do this manually. Follow the order below.

Go to EventViewer.

output

Then create custom view.

output

Pick a custom range.

output

In the From: section click where it says First Event, and then click Events On from the drop down menu.

output

Give the suspicious date range for John.

output

Pick log type as security.

output

Then just follow.

output

You will see an output-page like this.

output

You can review these logs manually. Below we found an security state change.

output

Let’s try to get more details about remote connection. We need to go to the inetpub location.

The inetpub directory is a default directory for Microsoft Internet Information Services (IIS), which is a web server application and set of feature extension modules created by Microsoft for use with Windows. This directory is typically found on Windows servers where IIS is installed, and it serves as the root directory for hosting web content.

  • wwwroot: This is the default directory for web pages and site content. When you create a website or web application, the files for the site (HTML, CSS, JavaScript, images, etc.) are typically placed here. For example, C:\inetpub\wwwroot\index.html would be the path to the default home page of a website.
  • logs: This directory contains log files for IIS. These logs can include access logs, error logs, and other information that can be useful for troubleshooting and monitoring the web server's activity.
  • ftproot: If IIS FTP services are enabled, this directory serves as the root directory for FTP file transfers.
  • vdirs: Virtual directories can be configured in IIS to point to directories outside of the wwwroot folder. This allows you to serve content from other locations on the file system.
  • custerr: This directory holds custom error pages that IIS can serve in response to specific HTTP status codes, such as 404 Not Found or 500 Internal Server Error.

Check these.

output

What is .jsp? They shouldn’t be here. You can analyze these.

output
output

The files are full of commands used to get connections from the web server… Very suspicious…

Looks like we need to control some traffic. To check the inbound rules of the Windows Firewall using PowerShell, you can use the Get-NetFirewallRule cmdlet along with Get-NetFirewallPortFilter and Get-NetFirewallAddressFilter to retrieve detailed information about the rules, including ports and addresses.

# List all inbound firewall rules
Get-NetFirewallRule -Direction Inbound
output

Evaluate the evidence you find and capture any additional details.

Let’s give a more comprehensive code.

# Create a list to store the rule details
$ruleDetails = @()

# Get all inbound firewall rules
$inboundRules = Get-NetFirewallRule -Direction Inbound

# Loop through each rule to get detailed information
foreach ($rule in $inboundRules) {
$ruleName = $rule.Name
$ruleDisplayName = $rule.DisplayName
$ruleEnabled = $rule.Enabled
$ruleAction = $rule.Action
$ruleProfile = $rule.Profile
$ruleDescription = $rule.Description

# Get port filter details
$portFilter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule
$localPorts = $portFilter.LocalPort
$remotePorts = $portFilter.RemotePort

# Get address filter details
$addressFilter = Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $rule
$localAddresses = $addressFilter.LocalAddress
$remoteAddresses = $addressFilter.RemoteAddress

# Add the details to the list
$ruleDetails += [PSCustomObject]@{
Name = $ruleName
DisplayName = $ruleDisplayName
Enabled = $ruleEnabled
Action = $ruleAction
Profile = $ruleProfile
Description = $ruleDescription
LocalPorts = $localPorts
RemotePorts = $remotePorts
LocalAddresses = $localAddresses
RemoteAddresses = $remoteAddresses
}
}

# Export the details to a CSV file
$ruleDetails | Export-Csv -Path "InboundFirewallRules.csv" -NoTypeInformation

This script collects the detailed information and exports it to a CSV file named InboundFirewallRules.csv.

Port 1337 is often associated with unauthorized access or backdoor activities, as it’s commonly used in hacker culture (where “1337” or “leet” is slang for “elite”). To investigate activities related to this port on your system, you can take several steps using PowerShell and other built-in Windows tools.

First, verify if port 1337 is open on your system: Get-NetTCPConnection -LocalPort 1337

Review system event logs for unusual activities related to port 1337:

# Get system event logs related to network connections on port 1337
Get-WinEvent -LogName "Microsoft-Windows-Security-Auditing" | Where-Object { $_.Message -match "1337" }

To specifically check for rules related to port 1337 (or any other port), you can filter the results using Get-NetFirewallPortFilter:

# Get all inbound firewall rules
$inboundRules = Get-NetFirewallRule -Direction Inbound

# Loop through each rule to find those associated with port 1337
foreach ($rule in $inboundRules) {
$portFilter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule
if ($portFilter.LocalPort -eq 1337) {
$rule | Select-Object -Property Name, DisplayName, Enabled, Action, Profile, Description, Direction, @{Name="LocalPorts";Expression={$portFilter.LocalPort}}, @{Name="RemotePorts";Expression={$portFilter.RemotePort}}
}
}

You can also use a single command to find and display inbound firewall rules for port 1337:

# Find inbound firewall rules for port 1337
Get-NetFirewallRule -Direction Inbound | Where-Object {
$portFilter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $_
$portFilter.LocalPort -eq 1337
} | Select-Object -Property Name, DisplayName, Enabled, Action, Profile, Description

Don’t give up on hacking.

Code for good.

^-^

--

--

Baris Dincer

#freedomofinternet | Coder | Cyberpunk | Threat Intelligence Investigator & CIO @ LEX