Posted On September 25, 2020

Domain Controller Vulnerability Scan for ZeroLogon VCE-2000-1472

kimconnect 0 comments
blog.KimConnect.com >> Windows >> Domain Controller Vulnerability Scan for ZeroLogon VCE-2000-1472
function vce2020-1472{
    # Source: 
    # Original script has been modified to fix a couple of bugs with connection error detection
    # Create output directory on executiong user's desktop
    $date = get-date -Format MMddyyyy
    $rootPath = $env:USERPROFILE + '\Desktop\CISA'
    $fullPath = $rootPath + '\' + $date
    $UpdateList = $fullPath + '\complianceReport.csv'
    if (Test-Path $rootPath){
        if (!(test-path $fullPath)){
                mkdir $fullPath
            }
    }else{
        mkdir $fullPath
        }

        function checkPort{
            Param(
                [string]$server,
                [int]$port=135,
                [bool]$verbose=$true
                )
         
                function importPortQry{
                    if (!(Get-Command portqry.exe -ErrorAction SilentlyContinue)){
                        if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                        Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))}
                        choco install portqry -y
                        if (Get-Command portqry.exe -ErrorAction SilentlyContinue){return $true}else{return $false}
                    }else{
                        return $true
                    }
                }
                 function Check-NetConnection($server, $port) {
                    $session = New-Object System.Net.Sockets.TcpClient;
                    $result=$false
                    try {
                        $session.Connect($server, $port);
                        $result=$true;
                    } catch {
                        $result=$false;
                    } finally {
                        $session.Close();
                        
                    }
                    return $result;
                }        
        
            function testPortArray {
                # Casting parameters is better than passing arguments as that allows for switches that can be arranged in any order
                param ([string]$targetServer,[array]$arrPorts,$verbose=$false)
                $source = $env:computername
                $destination=$targetServer.toUpper()
                $portsCount=$arrPorts.count
                $portsSuccess=0
        
                foreach ($port in $arrPorts){        
                    $testResult = Check-NetConnection -server $targetServer -port $port;
                    If ($testResult){
                        if($verbose){Write-Output "$port`: reachable"}
                        $portsSuccess++
                        }
                    Else{
                        if($verbose){Write-Output "$port`: unreachable"}
                        }
                }
        
                if($portsCount -eq $portsSuccess){
                    return $true
                }else{
                    return $false
                }
        
            }
             
            if($verbose){write-host "Checking for existence of PortQry.exe..."}
            do {
                $portQryExists=Get-Command "PortQry.exe" -ErrorAction SilentlyContinue
                if(!$portQryExists){
                    importPortQry;
                    sleep 1;
                }
            }while(!$portQryExists)
        
            $portReachable=Check-NetConnection -server $server -port $port     
            if ($portReachable){
                if($verbose){write-host "$env:computername is able to reach $server on the primary port of $port."}
                $strInvokeCommand = "PortQry.exe -e $port -n $server";
                $arrQuryResult = Invoke-Expression $strInvokeCommand;
             
                $arrPorts = @();    #Initiates and clears the collection of ports array
                ForEach ($strResult in $arrQuryResult)
                {
                  If ($strResult.Contains("ip_tcp"))
                  {
                  $arrSplt = $strResult.Split("[");
                  $strPort = $arrSplt[1];
                  $strPort = $strPort.Replace("]","");
                  $arrPorts += $strPort;
                  }
                }
         
                #  Remove duplicate port records from within the array
                $arrPorts = $arrPorts | select -uniq
                if ($arrPorts){            
                    if($verbose){write-host "These are the detected dynamic ephemeral ports being used:`r`n$arrPorts"  }      
                    $result=testPortArray -targetServer $server -arrPorts $arrPorts #  Pass the ports array into the workflow as a parameter
                    return $result
                }else{
                    if($verbose){write-host "Ephemeral ports were NOT detected.`r`n"}
                        return $portReachable
                        }
            }else{
                if($verbose){write-host "$env:computername is NOT able to reach $server on port: $port`r`n"}
                return $false
                }
        }

    ## Get all DCs in forest
    $allDCs = ($((Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ })).hostname
    $validHotFixes=@(
        'KB4571729',
        'KB4571719',
        'KB4571736',
        'KB4571702',
        'KB4571703',
        'KB4571723',
        'KB4571694',
        'KB4565349',
        'KB4565351',
        'KB4566782',
        'KB4577051',
        'KB4577038',
        'KB4577066',
        'KB4577015',
        'KB4577069',
        'KB4574727',
        'KB4577062',
        'KB4571744',
        'KB4571756',
        'KB4571748',
        'KB4570333'
    )
    Write-Host -ForegroundColor White ("There are $($allDcs.count) DCs")

    ## Foreach DC, get Component Based Servicing provided updates and MSI installed updates. Then dump to a common CSV
    foreach ($dc in $allDCs) {
        $winRmIsAvailable=Test-NetConnection $dc -commonTCPPort WinRm -informationlevel Quiet
        $rpcIsAvailable=checkPort $dc -port 135 -verbose $false
        
        if($rpcIsAvailable){
            $OS = $(Get-WmiObject -ComputerName $DC -Class Win32_OperatingSystem).caption
            Write-Host -ForegroundColor White ("Getting updates for $DC")
            Write-Host -ForegroundColor White ("Checking CBS Updates...")
            try{
                $quickFixes=Get-WmiObject Win32_quickfixengineering -ComputerName $dc | Select-Object *
            }catch{
                write-warning $_
            }
            if($quickFixes){
                $quickFixes|%{
                    $hotfix=$_.HotFixID 
                    if($hotfix -in $validHotFixes){
                        $hotfixFound=$true
                        $CBSObj = New-Object -TypeName psobject
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $OS
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $hotfix
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $hotfixFound
                        $CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation                
                        #break;
                    }
                }
            }
        }elseif($winRmIsAvailable){
            Write-Host -ForegroundColor White ("Getting updates for $dc`r`nChecking MSI Updates...")
            $session=new-pssession -ComputerName $dc
            if($session){
                $x=Invoke-Command -session $session -ScriptBlock { 
                        $updatesession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session",$env:computername))
                        $UpdateSearcher = $updatesession.CreateUpdateSearcher()
                        $searchresult = $updatesearcher.Search("IsInstalled=1").Updates|select Title
                        #$updatesSession = New-Object -ComObject Microsoft.Update.Session ;
                        #$updateSearch = $updatesSession.CreateUpdateSearcher();
                        #$hotfixes=$updateSearch.Search("IsInstalled=1").Updates | Select Title;
                        <#
                        Exception calling "Search" with "1" argument(s): "Exception from HRESULT: 0x8024401C"
                        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
                        + FullyQualifiedErrorId : ComMethodTargetInvocation
                        + PSComputerName        : TESTSERVER
                        #>
                        $os=(Get-WmiObject -Class Win32_OperatingSystem).caption;
                        return @($os,$searchresult)
                    }
                remove-pssession $session
                $hotfixCount=0
                $x[1] | ForEach-Object {
                    $Title = $_.Title
                    $kb=switch -Wildcard ($Title){
                        "*4571729*" {"KB4571729"}
                        "*4571719*" {"KB4571719"}
                        "*4571736*" {"KB4571736"}
                        "*4571702*" {"KB4571702"}
                        "*4571703*" {"KB4571703"}
                        "*4571723*" {"KB4571723"}
                        "*4571694*" {"KB4571694"}
                        "*4565349*" {"KB4565349"}
                        "*4565351*" {"KB4565351"}
                        "*4566782*" {"KB4566782"}
                        "*4577051*" {"KB4577051"}
                        "*4577038*" {"KB4577038"}
                        "*4577066*" {"KB4577066"}
                        "*4577015*" {"KB4577015"}
                        "*4577069*" {"KB4577069"}
                        "*4574727*" {"B4574727"}
                        "*4577062*" {"KB4577062"}
                        "*4571744*" {"KB4571744"}
                        "*4571756*" {"KB4571756"}
                        "*4571748*" {"KB4571748"}
                        "*4570333*" {"KB4570333"}                
                    }
                    if($kb){
                        $hotfixCount++
                        $CBSObj = New-Object -TypeName psobject
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Update" -Value $kb
                        $CBSObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $True
                        $CBSObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
                        #break
                    }
                }
                if($hotfixCount -eq 0){
                    $MSIObj = New-Object -TypeName psobject
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $x[0]
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'Missing'
                    $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value $false
                    $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
                }            
            }else{
                write-warning "Unable to connect to $dc via WinRM"
                $MSIObj = New-Object -TypeName psobject
                $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
                $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
                $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
                $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
                $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
            }
        }else{
            write-warning "Unable to connect to $dc via RPC nor WinRM"
            $MSIObj = New-Object -TypeName psobject
            $MSIObj | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $dc
            $MSIObj | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value 'unknown'
            $MSIObj | Add-Member -MemberType NoteProperty -Name "Update" -Value 'unknown'
            $MSIObj | Add-Member -MemberType NoteProperty -Name "Compliance" -Value 'unknown'
            $MSIObj | Export-Csv -path $UpdateList -Append -NoTypeInformation
        }
    }
    Write-Host -ForegroundColor White ("INFORMATION: DONE!")
}

vce2020-1472

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Post

How To Fix History Disabled in Task Scheduler

Issue: When checking certain tasks, one may find that the 'History' tab is appended with…

User Account Creation Script

1. Create Account in AD a. Select the correct container b. copy memberships of another…

Use DISM To Install Windows Features

Deployment Image Servicing and Management (DISM.exe) is a command-line tool that can be used to…