The Grid (PowerShell)
Challenge
- Event: SANS NetWars — PowerShell
- Category: PowerShell / DFIR
- Setting: a restricted PowerShell terminal on “The Grid” laser-research host
(
Ctrl+Cand endless loops are blocked)
Writeup
Process triage
The first task is to identify and stop a set of suspect processes, capturing the owning user of each before terminating them in order:
$processNames = @('circuitrix', 'byteflow', 'glowpath', 'netrider')
# Resolve each process to its owner via WMI
Get-Process |
Where-Object { $processNames -contains $_.Name } |
Select-Object Name, @{
Name = "Username";
Expression = { (Get-WmiObject Win32_Process -Filter "ProcessId = $($_.Id)" |
Select-Object -ExpandProperty GetOwner).User }
} | Format-Table -AutoSize
# Stop them in the specified order
foreach ($name in $processNames) {
Stop-Process -Name $name -Force -ErrorAction SilentlyContinue
}
Event-log analysis
A serialized event log (EventLog.xml, CLIXML from Export-Clixml) holds Sysmon
records. The goal is the event that appears exactly once — found by grouping on
the Id property and keeping the singleton:
$xml = [xml](Get-Content -Path "/etc/systemd/system/timers.target.wants/EventLog.xml")
$xml.Objs.Obj |
ForEach-Object { $_.Props.I32 | Where-Object { $_.N -eq "Id" } } |
Group-Object -Property InnerText |
Where-Object { $_.Count -eq 1 } |
ForEach-Object {
$uniqueId = $_.Name
$xml.Objs.Obj |
Where-Object { $_.Props.I32.InnerText -eq $uniqueId } |
Select-Object -First 1 -ExpandProperty Props
}
The records are Microsoft-Windows-Sysmon/Operational events (e.g. Network
connection detected) running as S-1-5-18 (SYSTEM) on host gridresearch.
The laser Web API
The final stage is a local Flask service (Werkzeug/3.0.3) controlling the
“Laser Power Supply.” The terminal’s MOTD points at it:
(Invoke-WebRequest -Uri http://localhost:1225/).RawContent # API help
(Invoke-WebRequest -Uri http://localhost:1225/api/on).RawContent # -> "Laser Power Supply Turned On"
An attacker had altered the laser settings through this API and left a calling
card at /home/callingcard.txt. Following those clues, the correct settings are
re-applied via the API to drive the laser back to the target output of
5 Mega-Megajoules per liter, completing the mission.