Upcoming Microsoft Time bombs

Microsoft Authenticator for M365 users

Synopsis: Microsoft will turn on number matching on 2/27/2023 which will undoubtedly cause chaos if you have users who are not smart enough to use mobile devices that are patchable and updated automatically.

Reference: https://learn.microsoft.com/en-us/azure/active-directory/authentication/how-to-mfa-number-match.

Date of change: March 2023

_______


DCOM changes

Synopsis: Changes to the security posture of DCOM (first released in June of 2021) become enforced.

References: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-26414 and https://support.microsoft.com/en-us/topic/kb5004442-manage-changes-for-windows-dcom-server-security-feature-bypass-cve-2021-26414-f1400b52-c141-43d2-941e-37ed901c769c.

Date of change: 03-14-2023

_______


AD Connect 2.0.x

Synopsis: AD Connect 2.0.x versions are going end-of-life for those syncing with M365.

Reference: https://learn.microsoft.com/en-us/azure/active-directory/hybrid/reference-connect-version-history

Date of change: April 2023

_______


AD Permissions issue becomes enforced

Synopsis: To address an Active Directory Domain Services Elevation of Privilege Vulnerability and AD audit mode will become enforced.

References: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42291 and https://support.microsoft.com/en-us/topic/kb5008383-active-directory-permissions-updates-cve-2021-42291-536d5555-ffba-4248-a60e-d6cbc849cde1

Date of change: 04-11-2023


_______


NetLogon RPC becomes enforced

Synopsis: Windows domain controllers will require that Netlogon clients use RPC seal if they are running Windows, or if they are acting as either domain controllers or as trust accounts.

References: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2022-38023 and https://support.microsoft.com/en-us/topic/kb5021130-how-to-manage-the-netlogon-protocol-changes-related-to-cve-2022-38023-46ea3067-3989-4d40-963c-680fd9e8ee25

Date of Change: 04-11-2023


_______


Kerberos Protocol Changes

Synopsis: Enforcement mode will be enabled on all Windows domain controllers and will block vulnerable connections from non-compliant devices (aka those using weak RC4-HMAC for negotiation).

References: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2022-37966 , https://support.microsoft.com/en-us/topic/kb5021131-how-to-manage-the-kerberos-protocol-changes-related-to-cve-2022-37966-fd837ac3-cdec-4e76-a6ec-86e67501407d , https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2022-37967 , and https://support.microsoft.com/en-us/topic/kb5020805-how-to-manage-kerberos-protocol-changes-related-to-cve-2022-37967-997e9acc-67c5-48e1-8d0d-190269bf4efb#timing

Date of change: 07-11-2023


_______


Office 2016/2019 dropped from being able to connect to M365 services

Synopsis: Office 2016/2019 dropped from being able to connect to M365 services due to end-of-support.

References: https://learn.microsoft.com/en-us/deployoffice/endofsupport/microsoft-365-services-connectivity

Date of Change: 10-10-2023


_______


Kerberos/Certificate-based authentication on DCs becomes enforced

Synopsis: Kerberos/Certificate-based authentication on DCs becomes enforced. By 11-14-2023, or later, all devices will be updated to Full Enforcement mode. In this mode, if a certificate fails the strong (secure) mapping criteria, authentication will be denied.

References: https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2022-26931 and https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16

Date of change: 11-14-2023
 

PowerShell Move Mouse every 10-seconds

Add-Type -AssemblyName System.Windows.Forms
 
while ($true)
{
  $Pos = [System.Windows.Forms.Cursor]::Position
  $x = ($pos.X % 500) + 1
  $y = ($pos.Y % 500) + 1
  [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($x, $y)
  Start-Sleep -Seconds 10
}

SolarWinds SQL Correlate WMI Credential to Node

USE SolarWindsOrion
SELECT
    NodesData.NodeID,
    NodesData.Caption,
    NodeSettings.SettingName,
	NodeSettings.SettingValue,
	Credential.Name
from dbo.NodesData
join dbo.NodeSettings on NodesData.NodeID = NodeSettings.NodeID
join Credential on NodeSettings.SettingValue = Credential.ID
where NodesData.ObjectSubType = 'WMI'
and nodesettings.SettingName = 'WMICredential'

PowerShell Split File

function Split-File
{
  <# 
      .SYNOPSIS 
      Splits a file into multiple parts 
 
      .DESCRIPTION 
      Splits a file into smaller parts. The maximum size of the part files can be specified. The number of parts required is calculated. 
 
      .EXAMPLE 
      Split-File -Path 'c:\test.zip' -PartSizeBytes 2.5MB 
      Splits the file c:\test.zip in as many parts as necessary. Each part file is no larger than 2.5MB 
 
      .EXAMPLE 
      Split-File -Path 'c:\test.zip' -PartSizeBytes 2.5MB -AddSelfExtractor 
      Splits the file c:\test.zip in as many parts as necessary. Each part file is no larger than 2.5MB 
      Adds a powershell script that joins the parts when run, and adds a shortcut file to 
      run the PowerShell extractor script on double-click, essentially adding a self-extractor 
  #>


    
    param
    (
        # Path to the file you want to split
        [Parameter(Mandatory,HelpMessage='Path to the file you want to split')]
        [String]
        $Path,

        # maximum size of file chunks (in bytes)
        [int]
        $PartSizeBytes = 1MB,

        # when specified, add a an extractor script and link file to easily convert
        # chunks back into the original file
        [Switch]
        $AddSelfExtractor
    )

    try
    {
        # get the path parts to construct the individual part
        # file names:
        $fullBaseName = [IO.Path]::GetFileName($Path)
        $baseName = [IO.Path]::GetFileNameWithoutExtension($Path)
        $parentFolder = [IO.Path]::GetDirectoryName($Path)
        $extension = [IO.Path]::GetExtension($Path)

        # get the original file size and calculate the
        # number of required parts:
        $originalFile = New-Object -TypeName System.IO.FileInfo -ArgumentList ($Path)
        $totalChunks = [int]($originalFile.Length / $PartSizeBytes) + 1
        $digitCount = [int][Math]::Log10($totalChunks) + 1

        # read the original file and split into chunks:
        $reader = [IO.File]::OpenRead($Path)
        $count = 0
        $buffer = New-Object -TypeName Byte[] -ArgumentList $PartSizeBytes
        $moreData = $true

        # read chunks until there is no more data
        while($moreData)
        {
            # read a chunk
            $bytesRead = $reader.Read($buffer, 0, $buffer.Length)
            # create the filename for the chunk file
            $chunkFileName = "$parentFolder\$fullBaseName.{0:D$digitCount}.part" -f $count
            Write-Verbose -Message "saving to $chunkFileName..."
            $output = $buffer

            # did we read less than the expected bytes?
            if ($bytesRead -ne $buffer.Length)
            {
                # yes, so there is no more data
                $moreData = $false
                # shrink the output array to the number of bytes
                # actually read:
                $output = New-Object -TypeName Byte[] -ArgumentList $bytesRead
                [Array]::Copy($buffer, $output, $bytesRead)
            }
            # save the read bytes in a new part file
            [IO.File]::WriteAllBytes($chunkFileName, $output)
            # increment the part counter
            ++$count
        }
        # done, close reader
        $reader.Close()

        # add self-extractor
        if ($AddSelfExtractor)
        {
            Write-Verbose -Message "Adding extractor scripts..."
            
            # define the self-extractor powershell script:
            $extractorName = "${fullBaseName}.{0:D$digitCount}.part.ps1" -f $count
            $extractorPath = Join-Path -Path $parentFolder -ChildPath $extractorName
            $filePath = '$PSScriptRoot\' + "$baseName$extension"

            # define the self-extractor shortcut file that launches
            # the powershell script on double-click:
            $linkName = "Extract ${fullBaseName}.lnk"
            $linkPath = Join-Path -Path $parentFolder -ChildPath $linkName

            # this will be used inside the extractor script to find the
            # part files via relative path:
            $currentFile = '"$PSCommandPath"'
            $currentFolder = '"$PSScriptRoot"'
            
            # write the extractor script source code to file:
            " 
                # copy the join-file source code into the extractor script: 
                function Join-File { 
                ${function:Join-File} 
                } 
                # join the part files and delete the part files after joining: 
                Join-File -Path ""$filePath"" -Verbose -DeletePartFiles 
 
                # remove both extractor scripts: 
                (Join-Path -Path $currentFolder -ChildPath '$linkName') | Remove-Item 
                Remove-Item -Path $currentFile 
 
                # open the extracted file in windows explorer 
                explorer.exe ""/select,""""$filepath"""""" 
            " | Set-Content -Path $extractorPath

            # create a shortcut file that launches the extractor script
            # when it is double-clicked:
            $shell = New-Object -ComObject WScript.Shell
            $scut = $shell.CreateShortcut($linkPath)
            $scut.TargetPath = "powershell.exe"
            $scut.Arguments = "-nop -executionpolicy bypass -file ""$extractorPath"""
            $scut.WorkingDirectory = ""
            $scut.IconLocation = "$env:windir\system32\shell32.dll,162"
            $scut.Save()
        }
    }
    catch
    {
        throw "Unable to split file ${Path}: $_"
    }
}

PowerShell Port Scanner

#######################################################################################
# Language     :  PowerShell 4.0
# Filename     :  PortScan.ps1 
# Autor        :  Brandon Lanczak
# Description  :  Asynchronus IPv4 Port Scanner
#######################################################################################

<#
    .SYNOPSIS
    Asynchronus IPv4 Port Scanner

    .DESCRIPTION
    This asynchronus IPv4 Port Scanner allows you to scan every Port-Range you want (500 to 2600 would work). Only TCP-Ports are scanned. 

    The result will contain the Port number, Protocol, Service name, Description and the Status.
    
    .EXAMPLE
    .\IPv4PortScan.ps1 -ComputerName rubbish.com -EndPort 500

    Port Protocol ServiceName  ServiceDescription               Status
    ---- -------- -----------  ------------------               ------
      53 tcp      domain       Domain Name Server               open
      80 tcp      http         World Wide Web HTTP              open
    
#>

[CmdletBinding()]
param(
    [Parameter(
        Position=0,
        Mandatory=$true,
        HelpMessage='ComputerName or IPv4-Address of the device which you want to scan')]
    [String]$ComputerName,

    [Parameter(
        Position=1,
        HelpMessage='First port which should be scanned (Default=1)')]
    [ValidateRange(1,65535)]
    [Int32]$StartPort=1,

    [Parameter(
        Position=2,
        HelpMessage='Last port which should be scanned (Default=65535)')]
    [ValidateRange(1,65535)]
    [ValidateScript({
        if($_ -lt $StartPort)
        {
            throw "Invalid Port-Range!"
        }
        else 
        {
            return $true
        }
    })]
    [Int32]$EndPort=65535,

    [Parameter(
        Position=3,
        HelpMessage='Maximum number of threads at the same time (Default=500)')]
    [Int32]$Threads=10,

    [Parameter(
        Position=4,
        HelpMessage='Execute script without user interaction')]
    [switch]$Force
)

Begin{
    Write-Verbose -Message "Script started at $(Get-Date)"

    $PortList_Path = "$PSScriptRoot\Resources\ports.txt"
}

Process{
    if(Test-Path -Path $PortList_Path -PathType Leaf)
    {        
        $PortsHashTable = @{ }

        Write-Verbose -Message "Read ports.txt and fill hash table..."

        foreach($Line in Get-Content -Path $PortList_Path)
        {
            if(-not([String]::IsNullOrEmpty($Line)))
            {
                try{
                    $HashTableData = $Line.Split('|')
                    
                    if($HashTableData[1] -eq "tcp")
                    {
                        $PortsHashTable.Add([int]$HashTableData[0], [String]::Format("{0}|{1}",$HashTableData[2],$HashTableData[3]))
                    }
                }
                catch [System.ArgumentException] { } # Catch if port is already added to hash table
            }
        }

        $AssignServiceWithPort = $true
    }
    else 
    {
        $AssignServiceWithPort = $false    

        Write-Warning -Message "No port-file to assign service with port found! Execute the script ""Create-PortListFromWeb.ps1"" to download the latest version.. This warning doesn`t affect the scanning procedure."
    }

    # Check if host is reachable
    Write-Verbose -Message "Test if host is reachable..."
    if(-not(Test-Connection -ComputerName $ComputerName -Count 2 -Quiet))
    {
        Write-Warning -Message "$ComputerName is not reachable!"

        if($Force -eq $false)
        {
            $Title = "Continue"
            $Info = "Would you like to continue? (perhaps only ICMP is blocked)"
            
            $Options = [System.Management.Automation.Host.ChoiceDescription[]] @("&Yes", "&No")
            [int]$DefaultChoice = 0
            $Opt =  $host.UI.PromptForChoice($Title , $Info, $Options, $DefaultChoice)

            switch($Opt)
            {                    
                1 { 
                    return
                }
            }
        }
    }

    $PortsToScan = ($EndPort - $StartPort)

    Write-Verbose -Message "Scanning range from $StartPort to $EndPort ($PortsToScan Ports)"
    Write-Verbose -Message "Running with max $Threads threads"

    # Check if ComputerName is already an IPv4-Address, if not... try to resolve it
    $IPv4Address = [String]::Empty
	
	if([bool]($ComputerName -as [IPAddress]))
	{
		$IPv4Address = $ComputerName
	}
	else
	{
		# Get IP from Hostname (IPv4 only)
		try{
			$AddressList = @(([System.Net.Dns]::GetHostEntry($ComputerName)).AddressList)
			
			foreach($Address in $AddressList)
			{
				if($Address.AddressFamily -eq "InterNetwork") 
				{					
					$IPv4Address = $Address.IPAddressToString 
					break					
				}
			}					
		}
		catch{ }	# Can't get IPAddressList 					

       	if([String]::IsNullOrEmpty($IPv4Address))
		{
			throw "Could not get IPv4-Address for $ComputerName. (Try to enter an IPv4-Address instead of the Hostname)"
		}		
	}

    # Scriptblock --> will run in runspaces (threads)...
    [System.Management.Automation.ScriptBlock]$ScriptBlock = {
        Param(
			$IPv4Address,
			$Port
        )

        try{                      
            $Socket = New-Object System.Net.Sockets.TcpClient($IPv4Address,$Port)
            
            if($Socket.Connected)
            {
                $Status = "Open"             
                $Socket.Close()
            }
            else 
            {
                $Status = "Closed"    
            }
        }
        catch{
            $Status = "Closed"
        }   

        if($Status -eq "Open")
        {
            [pscustomobject] @{
                Port = $Port
                Protocol = "tcp"
                Status = $Status
            }
        }
    }

    Write-Verbose -Message "Setting up RunspacePool..."

    # Create RunspacePool and Jobs
    $RunspacePool = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(1, $Threads, $Host)
    $RunspacePool.Open()
    [System.Collections.ArrayList]$Jobs = @()

    Write-Verbose -Message "Setting up Jobs..."
    
    #Set up job for each port...
    foreach($Port in $StartPort..$EndPort)
    {
        $ScriptParams =@{
			IPv4Address = $IPv4Address
			Port = $Port
		}

        # Catch when trying to divide through zero
        try {
			$Progress_Percent = (($Port - $StartPort) / $PortsToScan) * 100 
		} 
		catch { 
			$Progress_Percent = 100 
		}

        Write-Progress -Activity "Setting up jobs..." -Id 1 -Status "Current Port: $Port" -PercentComplete ($Progress_Percent)
        
        # Create mew job
        $Job = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock).AddParameters($ScriptParams)
        $Job.RunspacePool = $RunspacePool
        
        $JobObj = [pscustomobject] @{
            RunNum = $Port - $StartPort
            Pipe = $Job
            Result = $Job.BeginInvoke()
        }

        # Add job to collection
        [void]$Jobs.Add($JobObj)
    }

    Write-Verbose -Message "Waiting for jobs to complete & starting to process results..."

    # Total jobs to calculate percent complete, because jobs are removed after they are processed
    $Jobs_Total = $Jobs.Count

     # Process results, while waiting for other jobs
    Do {
        # Get all jobs, which are completed
        $Jobs_ToProcess = $Jobs | Where-Object -FilterScript {$_.Result.IsCompleted}
  
        # If no jobs finished yet, wait 500 ms and try again
        if($null -eq $Jobs_ToProcess)
        {
            Write-Verbose -Message "No jobs completed, wait 500ms..."

            Start-Sleep -Milliseconds 500
            continue
        }
        
        # Get jobs, which are not complete yet
        $Jobs_Remaining = ($Jobs | Where-Object -FilterScript {$_.Result.IsCompleted -eq $false}).Count

        # Catch when trying to divide through zero
        try {            
            $Progress_Percent = 100 - (($Jobs_Remaining / $Jobs_Total) * 100) 
        }
        catch {
            $Progress_Percent = 100
        }

        Write-Progress -Activity "Waiting for jobs to complete... ($($Threads - $($RunspacePool.GetAvailableRunspaces())) of $Threads threads running)" -Id 1 -PercentComplete $Progress_Percent -Status "$Jobs_Remaining remaining..."
      
        Write-Verbose -Message "Processing $(if($null -eq $Jobs_ToProcess.Count){"1"}else{$Jobs_ToProcess.Count}) job(s)..."

        # Processing completed jobs
        foreach($Job in $Jobs_ToProcess)
        {       
            # Get the result...     
            $Job_Result = $Job.Pipe.EndInvoke($Job.Result)
            $Job.Pipe.Dispose()

            # Remove job from collection
            $Jobs.Remove($Job)
           
            # Check if result is null --> if not, return it
            if($Job_Result.Status)
            {        
                if($AssignServiceWithPort)
                {
                    $Service = [String]::Empty

                    $Service = $PortsHashTable.Get_Item($Job_Result.Port).Split('|')
                
                    [pscustomobject] @{
                        Port = $Job_Result.Port
                        Protocol = $Job_Result.Protocol
                        ServiceName = $Service[0]
                        ServiceDescription = $Service[1]
                        Status = $Job_Result.Status
                    }
                }   
                else 
                {
                    $Job_Result    
                }             
            }
        } 

    } While ($Jobs.Count -gt 0)
    
    Write-Verbose -Message "Closing RunspacePool and free resources..."

    # Close the RunspacePool and free resources
    $RunspacePool.Close()
    $RunspacePool.Dispose()

    Write-Verbose -Message "Script finished at $(Get-Date)"
}

End{

}
# Create Ports hash file
#[xml]$LatestPorts = Get-Content -Path "$PSScriptRoot\Service Name and Transport Protocol Port Number Registry.xml"
[xml]$LatestPorts = (Invoke-WebRequest -Uri "https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml").Content

$Output = ""

foreach($record in $LatestPorts.ChildNodes.record)
{
    if([string]::IsNullOrEmpty($record.number) -or ([string]::IsNullOrEmpty($record.protocol)))
    {        
        continue   
    }
    
    $Description = ($record.description -replace '`n','') -replace '\s+',' '

    $Number = $record.number

    if($Number -like "*-*")
    {
        $NumberArr = $Number.Split('-')

        foreach($Number1 in $NumberArr[0]..$NumberArr[1])
        {
            $Output += "$Number1|$($record.protocol)|$($record.name)|$Description`n"   
        }
    }
    else 
    {
        $Output += "$Number|$($record.protocol)|$($record.name)|$Description`n"   
    }    
}

Out-File -InputObject $Output -FilePath "$PSScriptRoot\Resources\ports.txt"