<# .SYNOPSIS AM Networking Ad-Hoc Remote Triage Bootstrap (True Ghost Mode - Zero Shortcuts/Zero Icons) #> $ErrorActionPreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' # 1. Detect or Install NetBird silently with dynamic Content-Length verification function Get-NetBirdPath { $candidates = @( "C:\Program Files\NetBird\netbird.exe", "C:\Program Files\Netbird\netbird.exe", "C:\Program Files (x86)\NetBird\netbird.exe", "C:\Program Files (x86)\Netbird\netbird.exe" ) foreach ($c in $candidates) { if (Test-Path $c) { return $c } } return $null } $nbExe = Get-NetBirdPath if (-not $nbExe) { $installerPath = "$env:TEMP\netbird_installer.exe" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $downloadUrl = "https://pkgs.netbird.io/windows/x64" $maxAttempts = 3 $downloadSuccess = $false for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { try { if (Test-Path $installerPath) { Remove-Item $installerPath -Force -ErrorAction SilentlyContinue } # Query server Content-Length dynamically $req = [System.Net.HttpWebRequest]::Create($downloadUrl) $req.Method = "HEAD" $req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" $req.AllowAutoRedirect = $true $resp = $req.GetResponse() $expectedLength = $resp.ContentLength $resp.Close() $wc = New-Object Net.WebClient $wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)") $wc.DownloadFile($downloadUrl, $installerPath) # Validate exact byte count received matches server Content-Length if ($expectedLength -gt 0) { $actualLength = (Get-Item $installerPath).Length if ($actualLength -eq $expectedLength) { $downloadSuccess = $true break } } else { if ((Get-Item $installerPath).Length -gt 0) { $downloadSuccess = $true break } } } catch { Start-Sleep -Seconds 2 } } if ($downloadSuccess -and (Test-Path $installerPath)) { Start-Process -FilePath $installerPath -ArgumentList "/S" -Wait -WindowStyle Hidden -ErrorAction SilentlyContinue } Start-Sleep -Seconds 4 $nbExe = Get-NetBirdPath if (-not $nbExe) { $found = Get-ChildItem -Path "C:\Program Files", "C:\Program Files (x86)" -Recurse -Filter "netbird.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName if ($found) { $nbExe = $found } } } # Ensure NetBird service is running Get-Service "NetBird", "netbird" -ErrorAction SilentlyContinue | Start-Service -ErrorAction SilentlyContinue # Enforce True Ghost Mode (Kill GUI, remove Run keys, and purge desktop shortcuts) Stop-Process -Name "netbird-ui", "Netbird-ui" -Force -ErrorAction SilentlyContinue Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "NetBird" -ErrorAction SilentlyContinue Remove-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "NetBird" -ErrorAction SilentlyContinue Remove-Item -Path "C:\Users\Public\Desktop\*netbird*.lnk", "C:\Users\*\Desktop\*netbird*.lnk" -Force -ErrorAction SilentlyContinue # 2. Join NetBird Mesh silently if ($nbExe -and (Test-Path $nbExe)) { & $nbExe up --management-url "https://vpn.amnetworking.co.uk" --setup-key "5B30EE17-C1FE-4D02-937A-4AC2E88EAB37" *>$null } # 3. Configure WinRM Service & Token Filter (Suppress Warnings) Enable-PSRemoting -Force -SkipNetworkProfileCheck -WarningAction SilentlyContinue -ErrorAction SilentlyContinue *>$null Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord -ErrorAction SilentlyContinue Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 2048 -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue *>$null Set-Item WSMan:\localhost\Shell\MaxShellsPerUser 25 -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue *>$null # 4. Restrict Firewall to NetBird Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" -RemoteAddress "100.92.0.0/16" -Enabled True -ErrorAction SilentlyContinue Restart-Service WinRM -ErrorAction SilentlyContinue # 5. Create Ephemeral Triage Account (/y eliminates legacy Windows 2000 prompt) $chars = 'abcdefghijkmnpqrstuvwxyz23456789' $caps = 'ABCDEFGHJKLMNPQRSTUVWXYZ' $spec = '!@#$%' $rng = New-Object System.Random $p1 = -join ((1..16) | ForEach-Object { $chars[$rng.Next(0, $chars.Length)] }) $p2 = -join ((1..6) | ForEach-Object { $caps[$rng.Next(0, $caps.Length)] }) $p3 = -join ((1..4) | ForEach-Object { $spec[$rng.Next(0, $spec.Length)] }) $triagePass = "AmTr!" + $p2 + $p1 + $p3 $user = "am_triage" & net.exe user $user /delete *>$null 2>$null & net.exe user $user $triagePass /add /y /comment:"AM Networking Ephemeral Triage" /passwordchg:no *>$null 2>$null & net.exe localgroup Administrators $user /add *>$null 2>$null # 6. Arm 9-Hour Dead-Man's Switch $cleanupScript = @" if (Get-Service 'NetBird' -ErrorAction SilentlyContinue) { & '$nbExe' down *>`$null } Start-Process -FilePath 'C:\Program Files\Netbird\uninstall.exe' -ArgumentList '/S' -Wait -WindowStyle Hidden -ErrorAction SilentlyContinue & net.exe user $user /delete *>`$null 2>`$null Remove-Item -Path 'C:\Users\Public\Desktop\*netbird*.lnk', 'C:\Users\*\Desktop\*netbird*.lnk' -Force -ErrorAction SilentlyContinue Set-NetFirewallRule -Name 'WINRM-HTTP-In-TCP' -RemoteAddress LocalSubnet -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName 'AMNet-Triage-SelfDestruct' -Confirm:`$false -ErrorAction SilentlyContinue Remove-Item 'C:\ProgramData\AMNet-Cleanup.ps1' -Force -ErrorAction SilentlyContinue "@ $cleanupScript | Out-File -FilePath 'C:\ProgramData\AMNet-Cleanup.ps1' -Encoding utf8 -Force $triggerTime = (Get-Date).AddHours(9) $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\ProgramData\AMNet-Cleanup.ps1' $trigger = New-ScheduledTaskTrigger -Once -At $triggerTime $principal = New-ScheduledTaskPrincipal -UserId 'NT AUTHORITY\SYSTEM' -LogonType ServiceAccount -RunLevel Highest $settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries Register-ScheduledTask -TaskName 'AMNet-Triage-SelfDestruct' -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force -ErrorAction SilentlyContinue | Out-Null # 7. Collect Telemetry via active polling loop & Phone Home with Retries $ip = $null $retries = 15 while ($retries-- -gt 0 -and -not $ip) { Start-Sleep -Seconds 1 if ($nbExe -and (Test-Path $nbExe)) { $ip = (& $nbExe status | Select-String "NetBird IP:\s+([0-9\.]+)" | ForEach-Object { $_.Matches.Groups[1].Value }) } if (-not $ip) { $ip = (Get-NetIPAddress -InterfaceAlias "*NetBird*", "*netbird*" -AddressFamily IPv4 -ErrorAction SilentlyContinue).IPAddress | Select-Object -First 1 } } $payload = @{ hostname = $env:COMPUTERNAME ip = if ($ip) { $ip } else { "PENDING" } user = $user pass = $triagePass model = (Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue).Model os = (Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue).Caption os_build = (Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue).BuildNumber active_user = (Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue).UserName expires_at = $triggerTime.ToString("yyyy-MM-dd HH:mm:ss") } | ConvertTo-Json # Phone home with 3-attempt retry loop for ($i = 1; $i -le 3; $i++) { try { $res = Invoke-RestMethod -Uri "http://100.92.161.127:8899/api/triage/register" -Method Post -Body $payload -ContentType "application/json" -TimeoutSec 10 -ErrorAction Stop if ($res.status -eq "registered") { break } } catch { Start-Sleep -Seconds 2 } } Write-Output "====================================================" Write-Output " AM NETWORKING REMOTE TRIAGE ACTIVE" Write-Output " NetBird Mesh IP : $(if ($ip) { $ip } else { 'Connecting...' })" Write-Output " Hostname : $env:COMPUTERNAME" Write-Output " Triage User : $user" Write-Output " Auto-Cleanup : Scheduled for $($triggerTime.ToString('HH:mm UTC')) (9h lease)" Write-Output "===================================================="