Tag: powershell

  • Check Logging Status of Palo Alto Firewalls

    UPDATE 2020-12-28: After my initial post, I found out that the 7x and 52xx models have a different format for the ‘show logging-status’ command. I have updated the code to take those into account. In addition, I have modified the input to take a CSV value pair of firewall,apiKey.

    Logs are at the heart of any firewall. So making sure that logs are available to query at all times is important.

    One of the features of the Palo Alto firewalls is the ability to forward logs to a Panorama or the Cortex Data Lake service. But it’s important to confirm that the firewall is actually forwarding logs and that some error hasn’t stopped log forwarding.

    The easiest way to manually check this on individual firewalls is the “show logging-status” command. It will display the last time logs were forwarded.

    But this can be very tedious in an environment with many firewalls. To help automate this process, I created a Powershell script to check the results of “show logging-status” on a given list of firewalls. If any of the firewalls have not forwarded logs in 2+ hours, the list is displayed and (optionally) an email can be sent with the results.

    Get-LoggingStatus Powershell script

    The script below uses the Palo Alto API to query a list of firewalls. So an API key needs to be configured on the firewalls for this script to work.

    See this article to configure an API key on your firewalls.

    param
    (
        [Parameter(Mandatory=$True,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage='CSV file with list of Palo Alto firewalls and their API key.  Format: fw,apiKey')]
        [string]$list,
        [Parameter(Mandatory=$False,
        ValueFromPipeline=$False,
        HelpMessage='If used, email will be sent.  If excluded, no email will be sent.')]
        [switch]$sendEmail = $false
    )
    
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    
    if (-Not ("TrustAllCertsPolicy" -as [type]))
    {
    add-type @"
        using System.Net;
        using System.Security.Cryptography.X509Certificates;
        public class TrustAllCertsPolicy : ICertificatePolicy
        {
            public bool CheckValidationResult
            (
                ServicePoint srvPoint, X509Certificate certificate,
                WebRequest request, int certificateProblem
            )
            {
                return true;
            }
        }
    "@
    
    
        [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
    }
    
    $emailFrom = "<YourEmailAddress"
    $emailTo = '<YourEmailAddress>'
    $emailSubject = "Palo Alto FW Logging Issues"
    $smtpServer = "<YourEmailServer>"
    
    # How many hours the firewall's last log forward can be behind the current time.
    $hourOffset = "2"
    
    $fwLIst = Get-Content $list
    
    $apiStem = "api/?type=op&cmd=%3Cshow%3E%3Clogging-status%3E%3C%2Flogging-status%3E%3C%2Fshow%3E"
    
    $fwNotSendingLogs = $null
    
    $htmlMessage = New-Object System.Text.StringBuilder
    $textMessage = New-Object System.Text.StringBuilder
    
    foreach ($listItem in $fwLIst)
    {
        $fw,$apiKey = $listItem -split ","
    
        $url = "https://$($fw.trim())/$apiStem&key=$($apiKey.trim())"
    
        $WebRequestContent = $null
        $ErrResp = $null
        [xml]$WebResponse = $null
    
        try
        {
            $WebRequestContent = Invoke-WebRequest -Uri "$url" -Method Get
        }
        catch
        {
            $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
            $ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
            $streamReader.Close()
        }
    
        if ($WebRequestContent -ne $null)
        {
            [xml]$WebResponse = $WebRequestContent.Content
        }
    
        if (($ErrResp) -or ($WebResponse -eq $null))
        {
            Write-Host "There was an error!" -ForegroundColor Red
            Write-Host $ErrResp -ForegroundColor Yellow
        }
        elseif($WebResponse.response.status -ne "success")
        {
            Write-Host "There was an error!" -ForegroundColor Red
            Write-Host $WebResponse.response.result -ForegroundColor Yellow
            Write-Host $WebResponse.response.status -ForegroundColor Yellow
        }
        else
        {
    
            $ConnStatus = $WebResponse.response.result | Select-String -Pattern 'Connection Status.*' -AllMatches | ForEach-Object{$_.Matches}
    
            $LogCollectors = $WebResponse.response.result | Select-String -Pattern 'Log Collector.*' -AllMatches | ForEach-Object{$_.Matches}
            
            $trafficString = $WebResponse.response.result | Select-String -Pattern 'traffic.*' -AllMatches | ForEach-Object{$_.Matches}
    
            $i=0
            
            if ($ConnStatus)
            {
                foreach ($ConnStringMatch in $ConnStatus)
                {                                                                                                       
                    if ($ConnStringMatch -match "lr - Active")
                    {
    
                        $logType,$logLastCreated,$logLastFwd,$seqNumFwd,$seqNumAck,$totalLogsFwd = $trafficString[$i] -split "\s{2,}"
                        $lcLabel,$lcValue = $LogCollectors[$i] -split ":"
                        $lcValue = $lcValue.Trim()
    
                        # Add offset hours to the Last Log Fwred datetime.  If this is less than the current datetime, logs are not being fowarded.  Add the firewall to the list.
                        if ($logLastFwd -as [DateTime])
                        {
                            if ((Get-Date $logLastFwd).AddHours($hourOffset) -lt (Get-Date))
                            {
                                $fwNotSendingLogs += $fw
                                $null = $htmlMessage.AppendLine("<tr><td>$fw</td><td>$lcValue</td><td>$logLastFwd</td></tr>")
                                $null = $textMessage.AppendLine("$fw using Log Collector $lcValue last forwarded logs on $logLastFwd")
                            }
                        }
                        else
                        {
                            $fwNotSendingLogs += $fw
                            $null = $htmlMessage.AppendLine("<tr><td>$fw</td><td>$lcValue</td><td>$logLastFwd</td></tr>")
                            $null = $textMessage.AppendLine("$fw using Log Collector $lcValue last forwarded logs on $logLastFwd")
                        }
                    }
                
                    $i++
                }
            }
            elseif ($trafficString)
            {
    
                $trafficString = $WebResponse.response.result | Where {$_ -match "traffic.*"} | Foreach {$Matches[0]}
    
                $logType,$logLastCreated,$logLastFwd,$seqNumFwd,$seqNumAck,$totalLogsFwd = $trafficString -split "\s{2,}"
    
                # Add offset hours to the Last Log Fwred datetime.  If this is less than the current datetime, logs are not being fowarded.  Add the firewall to the list.
                if ((Get-Date $logLastFwd).AddHours($hourOffset) -lt (Get-Date))
                {
                    $fwNotSendingLogs += $fw
                    $null = $htmlMessage.AppendLine("<tr><td>$fw</td><td>$logLastFwd</td></tr>")
                    $null = $textMessage.AppendLine("$fw last forwarded logs on $logLastFwd")
                }
            }
        }
    }
    
    if ($fwNotSendingLogs)
    {
        $htmlhead = "<html>
                    <style>
                    BODY{font-family: Consolas; font-size: 10pt;}
                    H1{font-size: 22px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                    H2{font-size: 18px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                    H3{font-size: 16px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}
                    TABLE{border: 1px solid black; border-collapse: collapse; font-size: 9pt;}
                    TH{border: 1px solid #969595; background: #dddddd; padding: 5px; color: #000000;}
                    TD{border: 1px solid #969595; padding: 5px; }
                    td.pass{background: #B7EB83;}
                    td.warn{background: #FFF275;}
                    td.fail{background: #FF2626; color: #ffffff;}
                    td.info{background: #85D4FF;}
    				tr:hover {background-color: #85D4FF}
                    </style>
                    <body>
                    <p>The following Palo Alto firewalls have stopped forwarding logs:</p>
                    <table>
                    <tr><th>Firewall</th><th>Log Collector Name</th><th>Last Log Fowarded</th></tr>"
        
        $htmltail = "</table></body></html>"
    
        $body = $htmlhead + $htmlMessage + $htmltail
    
        If ($sendEmail)
        {
            Send-MailMessage -To $emailTo -body $body -BodyAsHtml -From $emailFrom -Subject $emailSubject -Priority High -smtpServer $smtpServer
        }
    
        Write-Host $textMessage -ForegroundColor Yellow
    }
    else
    {
        Write-Host "All firewalls are forwarding logs."
    }
    
    
    
    

    Make sure to edit the highlighted lines to add your email settings.

    To use the script, save it as “Get-LoggingStatus.ps1” and run it with these command line parameters.

    Get-LoggingStatus.ps1 -list "C:\PathTo\firewall.txt" [-sendEmail]
    

    The “-list” parameter takes a CSV formatted file with the list of firewalls and their associated API key.

    The “-sendEmail” parameter is optional. If used and any firewalls are not sending logs, it will send an email.

    The variable “$hourOffset” sets a threshold on how many hours the firewall can be behind for log forwarding.

    If you want to test the functionality of the script, set the “$hourOffset” variable to a negative number, like -2. The script will think that all firewalls are failing to forward logs and cause the script to display a list of results similar to the following.

    firewall01 last forwarded logs on YYYY/MM/DD HH:MM:SS
    firewall02 last forwarded logs on YYYY/MM/DD HH:MM:SS
    ...
    

    Just make sure to change the variable back to 2 or whatever threshold you want to set before using the script.

    If one or more firewalls are NOT forwarding logs, the best solution is probably to open a case with support. But at least the problem can be detected quickly before logs are lost.

  • Detecting WINS Service Status With PowerShell

    To slightly modify something that Edwin Starr sang in the 1970 hit “War“

    WINS!

    What is it good for?

    Absolutely NOTHING!

    In most environments, the WINS service is no longer necessary as the Netbios protocol is no longer needed for name lookups (now handled by DNS).

    Netbios can (and should) be disabled on all endpoints (servers and workstations). Windows OS Hub has a great article on how to do that. But that still might leave the WINS service running on servers in the environment.

    To detect the state of the WINS service on all Domain Controllers, I created the PowerShell script below. It gets a list of all DCs, then determines if the WINS service is installed or not, then gets the state of the WINS service.

    $Servers = @(Get-ADDomainController -filter *).name
    
    Foreach ($Server in $Servers)
    {
        $WINSService = Get-Service -ComputerName $Server -Name WINS -ErrorAction SilentlyContinue
    
        if ($WINSService)
        {
            Write-Host "$Server,installed,$($WINSService.status)"
        }
        else
        {
            Write-Host "$Server,not installed,"
        }
    }
    
    

    This script needs to be run as a user with the ability to query services on Domain Controllers.

    It will write its output is CSV format similar to what is below:

    SERVER1,installed,running
    SERVER2,installed,stopped
    SERVER3,not installed,
    

    This should help identify Domain Controllers that are still running WINs or that have the service installed, but stopped.

  • Tenable.SC – Adding an email alert when a ticket is assigned (manually and PowerShell)

    Tenable.SC has a basic ticketing system built into their product.  But, by default, there’s no way to notify someone that a ticket has been assigned to them.  To notify someone that a ticket has been assigned to them, an alert needs to be generated that is based on a query.

    The first step is to configure a query. Within Tenable.SC, navigate to Analysis → Queries and Add a query.  In the Query Builder section, select “Ticket” for Type and “Ticket List” for Tool.

    (more…)
  • Using Powershell and the Nexpose API to create Exceptions

    Nexpose, like other vulnerability management platforms, has the ability to create exceptions for the vulnerabilities it finds. You might need to issue exceptions because the vulnerability is a false positive, a compensating control is in place, or the risk is acceptable to the business.

    Unfortunately, you sometimes have to create exceptions for hundreds, if not thousands, of vulnerabilities within Nexpose. It’s far too time consuming to create those manually.

    The good news is that Nexpose has a well documented API. I’ve used this API to create a Powershell module that can help automate the submission of vulnerability exceptions.

    (more…)
  • Auditing Passwords with Active Directory Properties

    Have you ever been looking through Active Directory and notice something strange in one of the fields?  Maybe the Organization or Description field has a weird string of letters, numbers, and characters.  You think, “Huh, that kind of looks like a password.”

    Ding! Ding! Ding!

    Yes, it happens.  Either through lack of understanding or just laziness, sometimes passwords get put into the plain text fields in AD.  This is dangerous because those fields are readable by everyone on the domain.

    So how do you know if any of these fields are being used to store passwords?  I managed to cobble together a PowerShell script that can help. (more…)

  • NS Change PowerShell Script – Updated!

    Some time ago, I posted a PowerShell script to detect changes in external NS records for domains.  I’ve made some modifications to the script to reduce false positives.  Additionally, the script now emails the “before” and “after” results of the NSLookup command for easy comparison.

    Updated script is below: (more…)

  • PowerShell script to alert for changes in NS records

    UPDATE: A newer version of this script is here.

    Last week, Johannes Ullrich shared a Bash script that would check for changes in NS records.  This was in a blog post about the google.com.my DNS hijack.  I wanted to create a version of the this script that would be usable on Windows machines.  So I created the PowerShell script below that does pretty much the same thing as the Bash script.  The script runs nslookup.exe instead of DIG and queries the DNS server for all NS records for a domain.  This is saved in file named domain.new and compared with a previous query of the NS records stored in domain.old.  If there are any differences, an email is sent and an entry is made in the Application Event Log. (more…)