Public/Helpers/Invoke-StealthOperation.ps1
function Invoke-StealthOperation { [CmdletBinding()] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)] [object]$InputObject, [Parameter(Mandatory = $false)] [ValidateSet("Random", "Progressive", "BusinessHours", "Exponential")] [string]$DelayType = "Random", [Parameter(Mandatory = $false)] [ValidateRange(0, 600)] [int]$MinDelay = 1, [Parameter(Mandatory = $false)] [ValidateRange(1, 3600)] [int]$MaxDelay = 5, [Parameter(Mandatory = $false)] [switch]$Silent, [Parameter(Mandatory = $false)] [ValidateSet("US", "UK", "EU", "JP", "AU", "ES", "IT", "FR", "MX", "CN", "BR", "IN", "KR")] [string]$Country = "EU", [Parameter(Mandatory = $false)] [string]$TimeZone = $null, [Parameter(Mandatory = $false)] [ValidateRange(0.0, 1.0)] [double]$Jitter = 0.2 ) begin { Write-Verbose "🚀 Starting stealth pipeline with $DelayType timing" $itemCount = 0 # Business hours mapping for different countries with cultural patterns $businessHours = @{ "US" = @{ Start = 9; End = 17; TimeZone = "Eastern Standard Time"; LunchBreak = $false } "UK" = @{ Start = 9; End = 17; TimeZone = "GMT Standard Time"; LunchBreak = $false } "EU" = @{ Start = 9; End = 17; TimeZone = "W. Europe Standard Time"; LunchBreak = $false } "JP" = @{ Start = 9; End = 18; TimeZone = "Tokyo Standard Time"; LunchBreak = $false } "AU" = @{ Start = 9; End = 17; TimeZone = "AUS Eastern Standard Time"; LunchBreak = $false } "ES" = @{ Start = 9; End = 14; End2 = 17; End2Close = 20; TimeZone = "Romance Standard Time"; LunchBreak = $true; LunchStart = 14; LunchEnd = 17; SiestaPattern = $true } "IT" = @{ Start = 9; End = 13; End2 = 14; End2Close = 18; TimeZone = "W. Europe Standard Time"; LunchBreak = $true; LunchStart = 13; LunchEnd = 14; SiestaPattern = $true } "FR" = @{ Start = 9; End = 12; End2 = 14; End2Close = 17; TimeZone = "Romance Standard Time"; LunchBreak = $true; LunchStart = 12; LunchEnd = 14; WorkWeekHours = 35 } "MX" = @{ Start = 9; End = 14; End2 = 16; End2Close = 19; TimeZone = "Central Standard Time (Mexico)"; LunchBreak = $true; LunchStart = 14; LunchEnd = 16; SiestaPattern = $true } "CN" = @{ Start = 9; End = 12; End2 = 14; End2Close = 18; TimeZone = "China Standard Time"; LunchBreak = $true; LunchStart = 12; LunchEnd = 14; NoonNap = $true } "BR" = @{ Start = 8; End = 12; End2 = 13; End2Close = 17; TimeZone = "E. South America Standard Time"; LunchBreak = $true; LunchStart = 12; LunchEnd = 13 } "IN" = @{ Start = 9; End = 18; TimeZone = "India Standard Time"; LunchBreak = $false; ExtendedHours = $true } "KR" = @{ Start = 9; End = 18; TimeZone = "Korea Standard Time"; LunchBreak = $false; LongWorkCulture = $true } } } process { # Calculate stealth delay based on type $calculatedDelay = 0 $businessConfigDescription = $null # Store for delay message switch ($DelayType) { "Random" { $calculatedDelay = Get-Random -Minimum $MinDelay -Maximum $MaxDelay } "Progressive" { $step = $itemCount + 1 $calculatedDelay = $MinDelay + ($step * 0.5) if ($calculatedDelay -gt $MaxDelay) { $calculatedDelay = $MaxDelay } } "BusinessHours" { # Determine timezone and business hours configuration $targetTimeZone = $null $businessConfig = $null if ($TimeZone) { # When TimeZone is specified, use generic business hours pattern $businessConfig = @{ Start = 9; End = 17; LunchBreak = $false; Description = "Generic" } # Check if TimeZone is UTC offset format (+2, -5, +5.5, etc.) if ($TimeZone -match '^[+-]\d+(?:\.\d+)?$') { try { $offsetHours = [double]$TimeZone $offsetTimeSpan = [TimeSpan]::FromHours($offsetHours) $targetTimeZone = [System.TimeZoneInfo]::CreateCustomTimeZone( "Custom_UTC$TimeZone", $offsetTimeSpan, "Custom UTC$TimeZone", "Custom UTC$TimeZone" ) $businessConfig.Description = "UTC$TimeZone" $businessConfigDescription = $businessConfig.Description Write-Verbose "🌍 Using custom UTC offset: $TimeZone with generic business hours" } catch { Write-Warning "⚠️ Invalid UTC offset format '$TimeZone'. Using country default." $businessConfig = $businessHours[$Country] if (-not $businessConfig) { $businessConfig = $businessHours["US"] $businessConfigDescription = "US" } else { $businessConfigDescription = $Country } $targetTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($businessConfig.TimeZone) } } else { # Try to use as timezone name try { $targetTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($TimeZone) $businessConfig.Description = $TimeZone $businessConfigDescription = $businessConfig.Description Write-Verbose "🕐 Using specified timezone: $TimeZone with generic business hours" } catch { Write-Warning "⚠️ Timezone '$TimeZone' not found. Using country default." $businessConfig = $businessHours[$Country] if (-not $businessConfig) { $businessConfig = $businessHours["US"] $businessConfigDescription = "US" } else { $businessConfigDescription = $Country } $targetTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($businessConfig.TimeZone) } } } else { # Use country-specific business hours and timezone $businessConfig = $businessHours[$Country] if (-not $businessConfig) { $businessConfig = $businessHours["US"] # Default fallback $businessConfigDescription = "US" } else { $businessConfigDescription = $Country } $targetTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($businessConfig.TimeZone) Write-Verbose "🏢 Using country-specific configuration: $Country" } try { $localTime = [System.TimeZoneInfo]::ConvertTimeFromUtc((Get-Date).ToUniversalTime(), $targetTimeZone) } catch { $localTime = Get-Date # Fallback to system time } $currentHour = $localTime.Hour $isWeekday = $localTime.DayOfWeek -notin @([DayOfWeek]::Saturday, [DayOfWeek]::Sunday) # Determine if currently in business hours based on configuration $isBusinessHours = $false if ($businessConfig.LunchBreak) { # Countries with lunch break/siesta patterns (ES, IT, FR, MX, CN, BR) $morningHours = $currentHour -ge $businessConfig.Start -and $currentHour -lt $businessConfig.End if ($businessConfig.End2 -and $businessConfig.End2Close) { $afternoonHours = $currentHour -ge $businessConfig.End2 -and $currentHour -lt $businessConfig.End2Close $isBusinessHours = $morningHours -or $afternoonHours } else { $isBusinessHours = $morningHours } # Check if currently in lunch/siesta break $isLunchBreak = $currentHour -ge $businessConfig.LunchStart -and $currentHour -lt $businessConfig.LunchEnd } else { # Standard business hours (US, UK, DE, JP, AU, IN, KR, or generic) $isBusinessHours = $currentHour -ge $businessConfig.Start -and $currentHour -lt $businessConfig.End } # Check if we need to wait for business hours (default behavior for BusinessHours timing) if (-not $isBusinessHours -or -not $isWeekday) { $waitSeconds = 0 if (-not $isWeekday) { # Calculate time until next Monday $daysUntilMonday = (8 - [int]$localTime.DayOfWeek) % 7 if ($daysUntilMonday -eq 0) { $daysUntilMonday = 1 } # If it's Sunday, wait until Monday $nextBusinessDay = $localTime.Date.AddDays($daysUntilMonday).AddHours($businessConfig.Start) $waitSeconds = ($nextBusinessDay - $localTime).TotalSeconds } elseif ($businessConfig.LunchBreak -and $isLunchBreak) { # Currently in lunch break - wait until afternoon session if ($businessConfig.End2) { $afternoonStart = $localTime.Date.AddHours($businessConfig.End2) $waitSeconds = ($afternoonStart - $localTime).TotalSeconds } } elseif ($currentHour -lt $businessConfig.Start) { # Wait until business hours start today $businessStart = $localTime.Date.AddHours($businessConfig.Start) $waitSeconds = ($businessStart - $localTime).TotalSeconds } elseif ($businessConfig.LunchBreak -and $businessConfig.End2Close -and $currentHour -ge $businessConfig.End2Close) { # After business hours for lunch break countries $nextDay = $localTime.Date.AddDays(1) if ($nextDay.DayOfWeek -eq [DayOfWeek]::Saturday) { $nextDay = $nextDay.AddDays(2) # Skip to Monday } elseif ($nextDay.DayOfWeek -eq [DayOfWeek]::Sunday) { $nextDay = $nextDay.AddDays(1) # Skip to Monday } $nextBusinessStart = $nextDay.AddHours($businessConfig.Start) $waitSeconds = ($nextBusinessStart - $localTime).TotalSeconds } elseif (-not $businessConfig.LunchBreak -and $currentHour -ge $businessConfig.End) { # After standard business hours $nextDay = $localTime.Date.AddDays(1) if ($nextDay.DayOfWeek -eq [DayOfWeek]::Saturday) { $nextDay = $nextDay.AddDays(2) # Skip to Monday } elseif ($nextDay.DayOfWeek -eq [DayOfWeek]::Sunday) { $nextDay = $nextDay.AddDays(1) # Skip to Monday } $nextBusinessStart = $nextDay.AddHours($businessConfig.Start) $waitSeconds = ($nextBusinessStart - $localTime).TotalSeconds } if ($waitSeconds -gt 0) { $waitHours = [Math]::Floor($waitSeconds / 3600) $waitMinutes = [Math]::Floor(($waitSeconds % 3600) / 60) if (-not $Silent) { $configDescription = if ($TimeZone) { $businessConfig.Description } else { $Country } $waitMessage = if ($isLunchBreak -and $businessConfig.SiestaPattern) { if ($waitHours -gt 0) { "🌅 Waiting {0}h {1}m until {2} siesta/lunch break ends..." -f $waitHours, $waitMinutes, $configDescription } else { "🌅 Waiting {0}m until {1} siesta/lunch break ends..." -f $waitMinutes, $configDescription } } elseif ($waitHours -gt 0) { "🌙 Waiting {0}h {1}m until {2} business hours begin..." -f $waitHours, $waitMinutes, $configDescription } else { "⏰ Waiting {0}m until {1} business hours begin..." -f $waitMinutes, $configDescription } Write-Host " $waitMessage" -ForegroundColor Magenta } Start-Sleep -Seconds $waitSeconds # Recalculate current time after waiting using the same timezone logic $localTime = [System.TimeZoneInfo]::ConvertTimeFromUtc((Get-Date).ToUniversalTime(), $targetTimeZone) $currentHour = $localTime.Hour $isWeekday = $localTime.DayOfWeek -notin @([DayOfWeek]::Saturday, [DayOfWeek]::Sunday) # Recalculate business hours status if ($businessConfig.LunchBreak) { $morningHours = $currentHour -ge $businessConfig.Start -and $currentHour -lt $businessConfig.End if ($businessConfig.End2 -and $businessConfig.End2Close) { $afternoonHours = $currentHour -ge $businessConfig.End2 -and $currentHour -lt $businessConfig.End2Close $isBusinessHours = $morningHours -or $afternoonHours } else { $isBusinessHours = $morningHours } } else { $isBusinessHours = $currentHour -ge $businessConfig.Start -and $currentHour -lt $businessConfig.End } } } # Apply appropriate delays based on activity level if ($isBusinessHours -and $isWeekday) { # Active business hours - shorter delays $calculatedDelay = Get-Random -Minimum $MinDelay -Maximum ([Math]::Min($MaxDelay, $MinDelay + 3)) } elseif ($businessConfig.LunchBreak -and $isLunchBreak -and $isWeekday) { # Lunch/siesta time - moderate delays (some reduced activity) $lunchMin = [Math]::Max($MinDelay, 5) $lunchMax = [Math]::Max([Math]::Min($MaxDelay, 15), $lunchMin + 1) $calculatedDelay = Get-Random -Minimum $lunchMin -Maximum $lunchMax } else { # Outside business hours - longer delays to simulate reduced activity $outsideHoursMin = [Math]::Max($MinDelay, 10) $outsideHoursMax = [Math]::Max($MaxDelay, $outsideHoursMin + 1) $calculatedDelay = Get-Random -Minimum $outsideHoursMin -Maximum $outsideHoursMax } } "Exponential" { $retryCount = $itemCount + 1 $baseDelay = [Math]::Max($MinDelay, 1) $calculatedDelay = $baseDelay * [Math]::Pow(2, [Math]::Min($retryCount - 1, 6)) # Cap at 2^6 if ($calculatedDelay -gt $MaxDelay) { $calculatedDelay = $MaxDelay } } } # Apply jitter to prevent pattern detection if ($Jitter -gt 0) { $jitterAmount = $calculatedDelay * $Jitter * (Get-Random -Minimum -1.0 -Maximum 1.0) $calculatedDelay = [Math]::Max(0, $calculatedDelay + $jitterAmount) } # Round to reasonable precision $calculatedDelay = [Math]::Round($calculatedDelay, 1) # Apply the delay if ($calculatedDelay -gt 0) { if (-not $Silent) { $delayMessage = switch ($DelayType) { "BusinessHours" { $timeInfo = " ($businessConfigDescription)" # Context-aware emoji based on configuration $emoji = if ($TimeZone) { "🌍" } else { "🏢" } "$emoji Stealth delay: {0}s (BusinessHours{1})" -f $calculatedDelay, $timeInfo } "Progressive" { "📈 Stealth delay: {0}s (Progressive - Step {1})" -f $calculatedDelay, ($itemCount + 1) } "Exponential" { "🚀 Stealth delay: {0}s (Exponential - Level {1})" -f $calculatedDelay, ($itemCount + 1) } default { "🎲 Stealth delay: {0}s ({1})" -f $calculatedDelay, $DelayType } } Write-Host " $delayMessage" -ForegroundColor DarkYellow } Start-Sleep -Seconds $calculatedDelay } # Pass through the input object if ($PSBoundParameters.ContainsKey('InputObject')) { Write-Output $InputObject } $itemCount++ } end { Write-Verbose "✅ Stealth pipeline completed for $itemCount items" } <# .SYNOPSIS Executes operations with configurable stealth timing delays. .DESCRIPTION Invoke-StealthOperation processes input objects through a pipeline while applying intelligent timing delays to avoid detection patterns. The function supports multiple delay strategies including random intervals, progressive timing, business hours simulation, and exponential backoff patterns. Ideal for scenarios requiring rate limiting, anti-detection measures, or simulating human-like interaction patterns in automated operations. .PARAMETER InputObject Objects to process through the stealth pipeline. Accepts pipeline input. .PARAMETER DelayType Specifies the delay pattern strategy: - Random: Random delays between min and max values - Progressive: Incrementally increasing delays per item - BusinessHours: Simulates activity during business hours (automatically waits for business hours) - Exponential: Exponential backoff pattern for each item Default: Random .PARAMETER MinDelay Minimum delay duration in seconds (0-600). Default: 1 .PARAMETER MaxDelay Maximum delay duration in seconds (1-3600). Default: 5 .PARAMETER Silent Suppresses delay notification messages when specified. .PARAMETER Country Two-letter country code for business hours timing. Valid values: US, UK, EU, JP, AU, ES, IT, FR, MX, CN, BR, IN, KR. Only used when DelayType is BusinessHours. Default: "US" .PARAMETER TimeZone Override timezone for business hours calculation. Supports timezone names (e.g., "Pacific Standard Time") or UTC offset notation (e.g., "+2", "-5", "+5.5"). Only used when DelayType is BusinessHours. .PARAMETER Jitter Random jitter percentage to add to delays (0.0-1.0). Adds randomness to prevent pattern detection. Default: 0.2 .EXAMPLE Invoke-StealthOperation | Find-PublicStorageContainer -StorageAccountName "test" Executes storage discovery with default random stealth timing. .EXAMPLE "example.com", "test.com" | Invoke-StealthOperation -DelayType BusinessHours -Country "UK" | ForEach-Object { Find-DnsRecords -Domain $_ } Processes domains with UK business hours timing simulation. .EXAMPLE Get-Content domains.txt | Invoke-StealthOperation -MinDelay 30 -MaxDelay 180 -Silent | ForEach-Object { Find-SubDomain -Domain $_ } Performs subdomain enumeration with extended delays (30-180 seconds) without status messages. .EXAMPLE 1..10 | Invoke-StealthOperation -DelayType Exponential | ForEach-Object { Test-Connection -Count 1 -ComputerName "server$_" } Tests multiple servers with exponentially increasing delays between operations. .EXAMPLE "target.com" | Invoke-StealthOperation -DelayType BusinessHours -Country "UK" | ForEach-Object { Find-DnsRecords -Domain $_ } Automatically waits until UK business hours before executing DNS reconnaissance. .EXAMPLE "target.com" | Invoke-StealthOperation -DelayType BusinessHours -Country "EU" -TimeZone "+2" | ForEach-Object { Find-DnsRecords -Domain $_ } Uses German business culture with UTC+2 timezone offset for precise timing. .NOTES Built-in stealth delay implementation eliminates dependency on external functions. Consider network policies and rate limits when configuring delay parameters. #> } |