Private/Logging/Protect-LogMessage.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Log message security and sanitization for Find-UnknownSID operations .DESCRIPTION Provides comprehensive log message sanitization to prevent log injection attacks, log forging, and other security vulnerabilities. Focuses solely on message security and content protection without formatting or output concerns. .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ Last Updated: 2025-07-05 Version: 2.0.0 TROUBLESHOOTING: - For sanitization issues: .\Troubleshooting\Security\Log-Sanitization.md - For security concerns: .\Troubleshooting\Security\Log-Injection-Prevention.md .LINK https://owasp.org/www-community/attacks/Log_Injection #> function Protect-LogMessage { <# .SYNOPSIS Sanitizes log messages to prevent log injection attacks and security vulnerabilities .DESCRIPTION Implements enterprise-grade log sanitization to protect against various attack vectors including log injection, log forging, CRLF injection, and terminal escape sequence attacks. Maintains message readability while ensuring comprehensive security protection. This function focuses solely on security sanitization and should be called before message formatting or output operations. .PARAMETER Message The log message to sanitize .PARAMETER PreserveNewlines Whether to preserve legitimate newlines in the message (use with caution) .PARAMETER MaxLength Maximum allowed message length before truncation (default: 2000) .EXAMPLE PS> Protect-LogMessage -Message "User input: `nmalicious`r`ninjection" Returns: "User input: malicious injection" (Control characters removed to prevent log injection) .EXAMPLE PS> Protect-LogMessage -Message "Multi-line error`nwith details" -PreserveNewlines Returns: "Multi-line error\nwith details" (Preserves legitimate newlines while sanitizing other control characters) .INPUTS [string] Log message content via pipeline .OUTPUTS [string] Sanitized log message safe for output .NOTES Implements multiple security controls to prevent: - Log injection attacks via control characters - Log forging through line breaks and carriage returns - CRLF injection vulnerabilities - Terminal escape sequence injection - Unicode control character attacks - Log flooding through excessively long messages SECURITY CONTROLS: - Removes dangerous control characters (0x00-0x1F, 0x7F-0x9F) - Strips ANSI escape sequences - Normalizes whitespace to prevent formatting attacks - Enforces maximum message length limits - Validates Unicode character ranges PERFORMANCE CHARACTERISTICS: - Execution time: 1-5ms depending on message length - Memory usage: Single string copy for processing - Regex operations: Optimized for security over raw performance TROUBLESHOOTING: - Empty or null messages are handled gracefully - Truncation is clearly indicated with ellipsis - Whitespace normalization prevents parsing issues #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory, ValueFromPipeline)] [AllowEmptyString()] [string]$Message, [Parameter()] [switch]$PreserveNewlines, [Parameter()] [ValidateRange(100, 10000)] [int]$MaxLength = 2000 ) process { # Handle null or empty messages if ([string]::IsNullOrEmpty($Message)) { return $Message } Write-Verbose "Sanitizing log message (Length: $($Message.Length))" try { # Start with the original message $sanitizedMessage = $Message # Remove dangerous control characters for log injection prevention $sanitizedMessage = Remove-ControlCharacters -Message $sanitizedMessage -PreserveNewlines:$PreserveNewlines # Remove terminal escape sequences to prevent terminal manipulation $sanitizedMessage = Remove-EscapeSequences -Message $sanitizedMessage # Remove Unicode control characters $sanitizedMessage = Remove-UnicodeControlCharacters -Message $sanitizedMessage # Normalize whitespace to prevent formatting attacks $sanitizedMessage = ConvertTo-NormalizedWhitespace -Message $sanitizedMessage # Enforce maximum length to prevent log flooding $sanitizedMessage = Limit-MessageLength -Message $sanitizedMessage -MaxLength $MaxLength Write-Verbose "Message sanitization completed (Final length: $($sanitizedMessage.Length))" return $sanitizedMessage } catch { Write-Warning "Failed to sanitize log message: $($_.Exception.Message)" # Return a safe fallback message return "[SANITIZATION_ERROR] Message could not be safely processed" } } } function Remove-ControlCharacters { <# .SYNOPSIS Removes dangerous control characters from log messages .DESCRIPTION Strips control characters that could be used for log injection attacks while optionally preserving legitimate newlines. .PARAMETER Message Message to process .PARAMETER PreserveNewlines Whether to preserve CR/LF characters .EXAMPLE PS> Remove-ControlCharacters -Message "Text with`0null`bbyte" Returns: "Text with nullbyte" .INPUTS None. This function does not accept pipeline input. .OUTPUTS [string] Message with control characters removed .NOTES Targets specific control character ranges that pose security risks. CR (0x0D) and LF (0x0A) are primary log injection vectors. #> [CmdletBinding()] [OutputType([string])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'The noun names a class of characters that is removed as a set')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Transforms a string, nothing on the system')] param( [Parameter(Mandatory)] [string]$Message, [Parameter()] [switch]$PreserveNewlines ) $processedMessage = $Message # Handle CR (0x0D) and LF (0x0A) - primary log injection vectors if (-not $PreserveNewlines) { $processedMessage = $processedMessage -replace '[\r\n]', ' ' } # Remove other dangerous control characters (excluding CR/LF if preserving) # 0x00-0x08: Null, Bell, Backspace, etc. # 0x0B: Vertical Tab # 0x0C: Form Feed # 0x0E-0x1F: Shift Out through Unit Separator # 0x7F: Delete $processedMessage = $processedMessage -replace '[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '' return $processedMessage } function Remove-EscapeSequences { <# .SYNOPSIS Removes ANSI escape sequences to prevent terminal manipulation .DESCRIPTION Strips ANSI escape sequences that could be used to manipulate terminal output or inject malicious formatting commands. .PARAMETER Message Message to process .EXAMPLE PS> Remove-EscapeSequences -Message "Text with `e[31mred color`e[0m" Returns: "Text with red color" .INPUTS None. This function does not accept pipeline input. .OUTPUTS [string] Message with escape sequences removed .NOTES Targets common ANSI escape sequence patterns for color and cursor control. Prevents terminal manipulation attacks through log output. #> [CmdletBinding()] [OutputType([string])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'The noun names a class of characters that is removed as a set')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Transforms a string, nothing on the system')] param( [Parameter(Mandatory)] [string]$Message ) # Remove ANSI escape sequences (prevent terminal manipulation) # Pattern matches: ESC [ <numbers and semicolons> <letter> $processedMessage = $Message -replace '\x1B\[[0-9;]*[mK]', '' # Remove other common escape sequences $processedMessage = $processedMessage -replace '\x1B\[[0-9;]*[ABCDEFGHJKSTfhlmnsu]', '' return $processedMessage } function Remove-UnicodeControlCharacters { <# .SYNOPSIS Removes Unicode control characters that could pose security risks .DESCRIPTION Strips Unicode control characters in the C0 and C1 control ranges that could be used for various injection or manipulation attacks. .PARAMETER Message Message to process .EXAMPLE PS> Remove-UnicodeControlCharacters -Message "Text with unicode controls" Returns message with Unicode control characters removed .INPUTS None. This function does not accept pipeline input. .OUTPUTS [string] Message with Unicode control characters removed .NOTES Targets Unicode ranges U+0000-U+001F and U+007F-U+009F. Prevents attacks using Unicode control characters. #> [CmdletBinding()] [OutputType([string])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'The noun names a class of characters that is removed as a set')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Transforms a string, nothing on the system')] param( [Parameter(Mandatory)] [string]$Message ) # Remove Unicode control characters # U+0000-U+001F: C0 controls # U+007F-U+009F: C1 controls $processedMessage = $Message -replace '[\u0000-\u001F\u007F-\u009F]', '' return $processedMessage } function ConvertTo-NormalizedWhitespace { <# .SYNOPSIS Normalizes whitespace to prevent formatting-based attacks .DESCRIPTION Converts multiple consecutive whitespace characters to single spaces and trims leading/trailing whitespace to prevent log parsing issues. .PARAMETER Message Message to process .EXAMPLE PS> ConvertTo-NormalizedWhitespace -Message "Text with multiple spaces" Returns: "Text with multiple spaces" .INPUTS None. This function does not accept pipeline input. .OUTPUTS [string] Message with normalized whitespace .NOTES Prevents whitespace-based log parsing attacks and improves readability. Maintains single spaces for legitimate formatting. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [string]$Message ) # Normalize multiple spaces to single space $processedMessage = $Message -replace '\s+', ' ' # Trim leading and trailing whitespace $processedMessage = $processedMessage.Trim() return $processedMessage } function Limit-MessageLength { <# .SYNOPSIS Enforces maximum message length to prevent log flooding attacks .DESCRIPTION Truncates messages that exceed the specified maximum length and adds a clear truncation indicator to maintain log integrity. .PARAMETER Message Message to process .PARAMETER MaxLength Maximum allowed message length .EXAMPLE PS> Limit-MessageLength -Message "Very long message..." -MaxLength 50 Returns truncated message with ellipsis indicator .INPUTS None. This function does not accept pipeline input. .OUTPUTS [string] Message truncated to maximum length if necessary .NOTES Prevents log flooding attacks while clearly indicating truncation. Reserves 3 characters for truncation indicator (...). #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [string]$Message, [Parameter(Mandatory)] [ValidateRange(10, 10000)] [int]$MaxLength ) if ($Message.Length -le $MaxLength) { return $Message } # Truncate and add indicator (reserve 3 characters for ellipsis) $truncatedMessage = $Message.Substring(0, $MaxLength - 3) + '...' Write-Verbose "Message truncated from $($Message.Length) to $($truncatedMessage.Length) characters" return $truncatedMessage } function Test-LogMessageSafety { <# .SYNOPSIS Validates that a log message is safe for output .DESCRIPTION Performs security validation on log messages to detect potential injection attempts or unsafe content before logging. .PARAMETER Message Message to validate .EXAMPLE PS> Test-LogMessageSafety -Message "Safe log message" Returns: $true .INPUTS None. This function does not accept pipeline input. .OUTPUTS [bool] True if message is safe, false if potentially dangerous .NOTES Used for additional security validation in high-security environments. Complements sanitization with detection capabilities. #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory)] [AllowEmptyString()] [string]$Message ) if ([string]::IsNullOrEmpty($Message)) { return $true } # Check for potential injection patterns $dangerousPatterns = @( '[\r\n].*[\r\n]', # Multiple line breaks (log forging) '\x1B\[', # ANSI escape sequences '[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', # Control characters '[\u0000-\u001F\u007F-\u009F]' # Unicode controls ) foreach ($pattern in $dangerousPatterns) { if ($Message -match $pattern) { Write-Verbose "Potentially dangerous pattern detected: $pattern" return $false } } return $true } |