Sophos Firewall: Laziness at your service!: Automated load of object through API from CSV!

Disclaimer: This information is provided as-is for the benefit of the Community. Please contact Sophos Professional Services if you require assistance with your specific environment.


Table Of Contents

Introduction

I'm not a programmer, and I'm not even close; everything here is self-taught and might contain errors. Test it in your environment before using it in real life. Always make backups, TEST the backups, and export full configurations.

I think laziness its the mother of inventive. I prefer 1 hour to create automated things to view more cats memes study more than doing manual stuff. That's why I did a little script to help load mostly IPHosts and FQDN. Helped me a lot when migrating firewalls from other brands since objects it's the more boring stuff to migrate.

What do you need?

  • One computer in which you can run a Powershell script
  • A list of things to upload to your firewall
  • A firewall (duh!). Ideally Sophos, but it works for Palo Alto (!!)
  • API Enabled for the computer

What can you do with this?

In IPHost "mode":

You can feed a CSV file with the following format:

Object name,IP addres,netmask

Examples

Gateway IP,192.168.0.254,/27
Printer,172.31.0.15,255.255.255.255
Office AP,172.16.0.10
Web Server,10.10.17.45,24

And he'll feed the firewall and create the appropriate objects. It can read the mask in the following formats:

  • /XX (Slash and a number, /24, /16, /30, etc)
  • XX (just two numbers, 24, 16, 30, etc)
  • xxx.xxx.xxx.xx (normal representation like 255.255.255.0)
  • No mask at all (it will assume that its a host ip with /32 mask)

In FQDN "mode":

You can feed a CSV file with the following format:

Object name, FQDN

You can choose to omit the FQDN, and in that case, it will use the name as the FQDN.

Examples

Google,*.google.com
*.amazon.com
www.ebay.com,*.ebay.com

In Automode (TM) BETA AF

You can feed a CSV file with a mix of IPHost/FQDN, and the script will interpret (99,9% of the time) the appropriate object.

Examples

*.amazon.com
Gateway IP,192.168.0.254,/27
85.1.56.7
Printer,172.31.0.15,255.255.255.255
Office AP,172.16.0.10
*.microsoft.com
NASA Website,90.43.1.65

domain.localhost.com
172.16.14.250
NASA Site FQDN,*.nasa.gov

Assumptions the script does in this mode:

  • If it has 1 field (ex: *.amazon.com or 172.16.100.100), it will check if it matches an IP address format (xxx.xxx.xxx.xxx)
    • If it does, its considered an IP address with mask /32
    • If it doesn't its considered an FQDN (working to improve detection for more cases)
  • If it has 2 or more fields, it will check if the second field matches an IP address format (xxx.xxx.xxx.xxx), if it does, its considers an IPHost and same rules for IPHost applies here (if it doesn't have netmask, its assumed an IPHost /32). If the second field doesnt match that, its considered a FQDN host.

In Splitter mode

This method is very simple: It takes existing objects in Sophos XML format and imports them one by one. This is better than the "all at once way" with import, since it will give you instant feedback about what works (and what doesn't) without waiting for the full import.

Specify the XML tag (objects) that you want to import (IPHost, FQDNHost, Services, MACAddress, whatever) and just let the script upload them for you.

Example of XML data:

<IPHost transactionid="">
<Name>172.22.122.142/32</Name>
<IPFamily>IPv4</IPFamily>
<HostType>IP</HostType>
<IPAddress>172.22.122.142</IPAddress>
</IPHost>
<IPHost transactionid="">
<Name>172.22.18.145/32</Name>
<IPFamily>IPv4</IPFamily>
<HostType>IP</HostType>
<IPAddress>172.22.18.145</IPAddress>
</IPHost>
<IPHost transactionid="">
<Name>192.168.10.6/32</Name>
<IPFamily>IPv4</IPFamily>
<HostType>IP</HostType>
<IPAddress>192.168.10.6</IPAddress>
</IPHost>

How can I use it?

# ---------------------
# ImportMan - XG
# ---------------------
# Versions
#
# 1.0 - Version original
# 1.1 - Added code to allow different masks in CSV
# 1.2 - Translated to English from Spanish
# 1.3 - Multi version - works with fqdn too
# 1.4 - Improved iphost detection, fqdn detection. Added automode TM
# 1.5 - Improved FQDN detection and cases available. Validation of credentials prior to creationg of objects. Minor translations.
# 1.6 - Little bug in reporting folder location. Added some context help on the script code.
# 1.7 - Updated with better single object detection. Added prefixes if you want to
# 1.8 - Added XML splitter, in case you already have an xml that needs to be imported one by one to Sophos XG.
# ---------------------

param ($_OPERATION)

# Global variable declaration
# ------------------------------
# You are required to adjust the following variables for correct working of the script
# $_FIREWALL_IP = IP address of the firewall you want to upload API request
# $_FIREWALL_PORT = Port on which the HTTPS interface of the firewall is working (normally 4444)
# $_API_USER = User that will be used for API calls (normally "admin")
# $_API_PASSWORD = Password for the account defined in the previous step
# $_WORK_FOLDER = Folder on which the script will work and leave logs/data. Needs to be writable for the user running the script. Needs to end with \ (ex: C:\API\)
# $_DATA_FILE_NAME = Name of the file which has the data to be uploaded to the firewall
# $_ADD_PREFIXES_TO_OBJECTS = Add a prefix to objects to diferentiate between them. IPs get an "HOST_" prefix, networks gets a "NET_" and FQDN an "FQDN_". You can select "Yes" or "No"
# ------------------------------

# Variables you need to adjust for your environment
# -------------------------------------------------
$_FIREWALL_IP = "192.168.1.210"
$_FIREWALL_PORT = "4444"
$_API_USER = "admin"
$_API_PASSWORD = 'correcthorsebatterystaple'
$_WORK_FOLDER = "D:\OneDrive\Scripts\XG\PowerShell\ImportMan\1.8\"
$_DATA_FILE_NAME = "ips.txt"
$_ADD_PREFIXES_TO_OBJECTS = "Yes"

# Variables that SHOULDN'T be modified by the user
# ------------------------------------------------
$_LOGS_FOLDER = ([String](Get-Date -Format 'ddMMyyyy_HHmm'))
$_AUTOMODE = 0


# -------------------------------------------------------------------------------------------------------------------------
# NOTHING BELOW THIS POINT IS REQUIRED TO BE UPDATED BY THE USER (UNLESS THEY WANT TO IMPROVE THE CODE WHICH IS APPRECIATED
# MODIFIYING ANYTHING FROM THIS POINT MIGHT CAUSE THE SCRIPT TO NOT WORK
# -------------------------------------------------------------------------------------------------------------------------



New-Item -ItemType "directory" -Path $_WORK_FOLDER -Name $_LOGS_FOLDER | Out-Null

# HTTPutility addon
# -------------------------
Add-Type -AssemblyName System.Web

# Convert variable to URI compatible format
# -----------------------
$_CODIFIED_API_PASSWORD = [System.Web.HttpUtility]::UrlEncode($_API_PASSWORD)

# Allow SSL connections
# -----------------------
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
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 

# Check operation to be performed
# -------------------------------
if ($_OPERATION -eq $null) 
    {
    Write-Host ""
    Write-Host ""
    Write-Host "ImportMAN! 1.8"
    Write-Host "--------------"
    Write-Host ""
    Write-Host "Helping YOU stay lazy."
    Write-Host ""
    Write-Host ""
    Write-Host "Type:"
    Write-Host ""
    Write-Host "1 for IPHost mode"
    Write-Host "2 for FQDN mode"
    Write-Host "3 for Auto-Mode(TM) BETA AF mode"
    Write-Host "4 for Sophos XG XML Splitter"
    Write-Host ""
    Write-Host ""
    $_OPERATION = read-host -Prompt "Please select operation mode: "
    switch ($_OPERATION)
        {
        1 { $_OPERATION = "IP_Mode" }
        2 { $_OPERATION = "FQDN_Mode" }
        3 { $_AUTOMODE = "On" }
        4 { $_OPERATION = "Splitter_Mode" }
        }
    Write-Host ""
    Write-Host ""
    }

# Testing credentials prior to upload objects
# -------------------------------------------
Write-Host "[INFO] Validating connection to appliance..."
$_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login></Request>"
$_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
[xml] $_API_QUERY_CONNECTIVITY_TEST_RESULT = $_API_QUERY_RESULT.Content

if ($_API_QUERY_CONNECTIVITY_TEST_RESULT.Response.Login.Status -ne "Authentication Successful")
    {
    Write-Host "[WARN] A problem have occur connecting to the firewall or credentials are not valid. Check and try again later."
    break
    } else {
    Write-Host "[ OK ] Connection to firewall succesful. Starting object creation."
    Write-Host ""
    }

# Main functions 
# --------------


# IP Host, FQDN and Auto mode.
# ----------------------------
if ($_OPERATION -eq "IP_Mode" -or $_OPERATION -eq "FQDN_Mode" -or $_AUTOMODE -eq "On")
{
foreach($line in [System.IO.File]::ReadLines("$_WORK_FOLDER$_DATA_FILE_NAME"))
    {
    # Obtain and split CSV data
    # ------------------------
    $_ITEM_NAME = ($line -split ',')[0]
    $_SECOND_FIELD =  ($line -split ',')[1]
    $_THIRD_FIELD =  ($line -split ',')[2]  

    # Checking for empty line
    # ------------------------
    if ($_ITEM_NAME -eq $nul)
        {
        Write-Host "[INFO] Skipping empty line."
        Continue
        }
 
    # Detection of type of object for AutoMode
    # ------------------------
	if ($_AUTOMODE -eq "On")
		{
		if ($_SECOND_FIELD -eq $nul) 
			{
            if ($_ITEM_NAME -match '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
                {
                $_OPERATION = "IP_Mode"
                } else {
                $_OPERATION = "FQDN_Mode"
                }
			} else {
            if ($_SECOND_FIELD -match '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
                {
                $_OPERATION = "IP_Mode"
                } else {
                $_OPERATION = "FQDN_Mode"
                }
			}
		}
		
    # Netsmak conversion from CSV data
    # ------------------------

    if ($_OPERATION -eq "IP_Mode" -and $_SECOND_FIELD -ne $nul)
        {     
        if ($_THIRD_FIELD -eq $nul)
            {
            $_THIRD_FIELD = "255.255.255.255"
            } else {
	        if (($_THIRD_FIELD -eq "/32") -or ($_THIRD_FIELD -eq "32")){ $_THIRD_FIELD = "255.255.255.255" }
	        if (($_THIRD_FIELD -eq "/31") -or ($_THIRD_FIELD -eq "31")){ $_THIRD_FIELD = "255.255.255.254" }
	        if (($_THIRD_FIELD -eq "/30") -or ($_THIRD_FIELD -eq "30")){ $_THIRD_FIELD = "255.255.255.252" }
	        if (($_THIRD_FIELD -eq "/29") -or ($_THIRD_FIELD -eq "29")){ $_THIRD_FIELD = "255.255.255.248" }
	        if (($_THIRD_FIELD -eq "/28") -or ($_THIRD_FIELD -eq "28")){ $_THIRD_FIELD = "255.255.255.240" }
	        if (($_THIRD_FIELD -eq "/27") -or ($_THIRD_FIELD -eq "27")){ $_THIRD_FIELD = "255.255.255.224" }
	        if (($_THIRD_FIELD -eq "/26") -or ($_THIRD_FIELD -eq "26")){ $_THIRD_FIELD = "255.255.255.192" }
	        if (($_THIRD_FIELD -eq "/25") -or ($_THIRD_FIELD -eq "25")){ $_THIRD_FIELD = "255.255.255.128" }
	        if (($_THIRD_FIELD -eq "/24") -or ($_THIRD_FIELD -eq "24")){ $_THIRD_FIELD = "255.255.255.0" }
	        if (($_THIRD_FIELD -eq "/23") -or ($_THIRD_FIELD -eq "23")){ $_THIRD_FIELD = "255.255.254.0" }
	        if (($_THIRD_FIELD -eq "/22") -or ($_THIRD_FIELD -eq "22")){ $_THIRD_FIELD = "255.255.252.0" }
	        if (($_THIRD_FIELD -eq "/21") -or ($_THIRD_FIELD -eq "21")){ $_THIRD_FIELD = "255.255.248.0" }
	        if (($_THIRD_FIELD -eq "/20") -or ($_THIRD_FIELD -eq "20")){ $_THIRD_FIELD = "255.255.240.0" }
	        if (($_THIRD_FIELD -eq "/19") -or ($_THIRD_FIELD -eq "19")){ $_THIRD_FIELD = "255.255.224.0" }
	        if (($_THIRD_FIELD -eq "/18") -or ($_THIRD_FIELD -eq "18")){ $_THIRD_FIELD = "255.255.192.0" }
	        if (($_THIRD_FIELD -eq "/17") -or ($_THIRD_FIELD -eq "17")){ $_THIRD_FIELD = "255.255.128.0" }
	        if (($_THIRD_FIELD -eq "/16") -or ($_THIRD_FIELD -eq "16")){ $_THIRD_FIELD = "255.255.0.0" }
	        if (($_THIRD_FIELD -eq "/15") -or ($_THIRD_FIELD -eq "15")){ $_THIRD_FIELD = "255.254.0.0" }
	        if (($_THIRD_FIELD -eq "/14") -or ($_THIRD_FIELD -eq "14")){ $_THIRD_FIELD = "255.252.0.0" }
	        if (($_THIRD_FIELD -eq "/13") -or ($_THIRD_FIELD -eq "13")){ $_THIRD_FIELD = "255.248.0.0" }
	        if (($_THIRD_FIELD -eq "/12") -or ($_THIRD_FIELD -eq "12")){ $_THIRD_FIELD = "255.240.0.0" }
	        if (($_THIRD_FIELD -eq "/11") -or ($_THIRD_FIELD -eq "11")){ $_THIRD_FIELD = "255.224.0.0" }
	        if (($_THIRD_FIELD -eq "/10") -or ($_THIRD_FIELD -eq "10")){ $_THIRD_FIELD = "255.192.0.0" }
	        if (($_THIRD_FIELD -eq "/9") -or ($_THIRD_FIELD -eq "9")){ $_THIRD_FIELD = "255.128.0.0" }
	        if (($_THIRD_FIELD -eq "/8") -or ($_THIRD_FIELD -eq "8")){ $_THIRD_FIELD = "255.0.0.0" }
	        if (($_THIRD_FIELD -eq "/7") -or ($_THIRD_FIELD -eq "7")){ $_THIRD_FIELD = "254.0.0.0" }
	        if (($_THIRD_FIELD -eq "/6") -or ($_THIRD_FIELD -eq "6")){ $_THIRD_FIELD = "252.0.0.0" }
	        if (($_THIRD_FIELD -eq "/5") -or ($_THIRD_FIELD -eq "5")){ $_THIRD_FIELD = "248.0.0.0" }
	        if (($_THIRD_FIELD -eq "/4") -or ($_THIRD_FIELD -eq "4")){ $_THIRD_FIELD = "240.0.0.0" }
	        if (($_THIRD_FIELD -eq "/3") -or ($_THIRD_FIELD -eq "3")){ $_THIRD_FIELD = "224.0.0.0" }
	        if (($_THIRD_FIELD -eq "/2") -or ($_THIRD_FIELD -eq "2")){ $_THIRD_FIELD = "192.0.0.0" }
	        if (($_THIRD_FIELD -eq "/1") -or ($_THIRD_FIELD -eq "1")){ $_THIRD_FIELD = "128.0.0.0" }
	        if (($_THIRD_FIELD -eq "/0") -or ($_THIRD_FIELD -eq "0")){ $_THIRD_FIELD = "0.0.0.0" }
            }
        }

    if ($_OPERATION -eq "IP_Mode" -and $_SECOND_FIELD -eq $nul)
        {
        $_SECOND_FIELD = $_ITEM_NAME
        $_THIRD_FIELD = "255.255.255.255"
        }

	
    # Operations for FQDN selection
	# -----------------------------
    
    if ($_OPERATION -eq "FQDN_Mode")
        {
        if ($_SECOND_FIELD -eq $nul)
            {
            $_SECOND_FIELD = $_ITEM_NAME
            }
	    }

    # Prefix for name of object
	# -------------------------

    if ($_ADD_PREFIXES_TO_OBJECTS -eq "Yes")
        {
        if ($_OPERATION -eq "FQDN_Mode")
            {
            $_ITEM_NAME = "FQDN_" + $_ITEM_NAME
            } else {
            if ($_THIRD_FIELD -eq "255.255.255.255")
                {
                $_ITEM_NAME = "HOST_" + $_ITEM_NAME
                } else {
                $_ITEM_NAME = "NET_" + $_ITEM_NAME
                }
            }
        }
    
	
    # Convert CSV variable to URI compatible format
    # ---------------------------------------------
    $_CODIFIED_ITEM_NAME = [System.Web.HttpUtility]::UrlEncode($_ITEM_NAME)
    $_CODIFIED_ITEM_NAME = ($_CODIFIED_ITEM_NAME -replace "%26","%26amp;")
        
    # API Query
    # ---------
	
	# For IPHost item
	# ----------------
	if ($_OPERATION -eq "IP_Mode")
	    {
		if($_THIRD_FIELD -eq "255.255.255.255")
			{
			$_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Set><IPHost><Name>$($_CODIFIED_ITEM_NAME)</Name><IPFamily>IPv4</IPFamily><HostType>IP</HostType><IPAddress>$($_SECOND_FIELD)</IPAddress></IPHost></Set></Request>"
			$_TYPE_OBJECT = "Host"
			} else {
			$_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Set><IPHost><Name>$($_CODIFIED_ITEM_NAME)</Name><IPFamily>IPv4</IPFamily><HostType>Network</HostType><IPAddress>$($_SECOND_FIELD)</IPAddress><Subnet>$($_THIRD_FIELD)</Subnet></IPHost></Set></Request>"
			$_TYPE_OBJECT = "Network"
			}  
	    }
	
	# For FQDN item
	# --------------
	if ($_OPERATION -eq "FQDN_Mode")
	    {
		$_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Set><FQDNHost><Name>$($_CODIFIED_ITEM_NAME)</Name><FQDN>$($_SECOND_FIELD)</FQDN></FQDNHost></Set></Request>"
        $_TYPE_OBJECT = "FQDN"		
	    }

    Write-Host ""
	Write-Host "[INFO] Processing $($_TYPE_OBJECT)"
    Write-Host "[INFO] Name: $($_ITEM_NAME)"
    Write-Host "[INFO] Value: $($_SECOND_FIELD)" 
    
    $_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
    [xml] $_API_QUERY_RESULT_PARSED = $_API_QUERY_RESULT.Content


    # Check result
    # ------------
    $_LINE_LOG = [String](Get-Date) + "," + "[$($_TYPE_OBJECT)]" + "," + $_ITEM_NAME

    if ($_OPERATION -eq "IP_Mode")
        {
        $_API_OPERATION_RESULT = $_API_QUERY_RESULT_PARSED.Response.IPHost.Status
        }
    if ($_OPERATION -eq "FQDN_Mode")
        {
        $_API_OPERATION_RESULT = $_API_QUERY_RESULT_PARSED.Response.FQDNHost.Status
        }


    if ($_API_OPERATION_RESULT.code -eq 200)
        {
        echo "[ OK ] CODE: $($_API_OPERATION_RESULT.code) - Processed OK"
        $_LINE_LOG | Out-File -Append -Encoding utf8 -FilePath "$($_WORK_FOLDER)$($_LOGS_FOLDER)\OK.txt"
        } else {
        echo "[WARN] CODE: $($_API_OPERATION_RESULT.code) - Error in execution $($_API_OPERATION_RESULT.'#text')"
        $_LINE_LOG | Out-File -Append -Encoding utf8 -FilePath "$($_WORK_FOLDER)$($_LOGS_FOLDER)\NO_OK.txt"
        }        
	}
}

# FIN IP Host, FQDN and Auto mode.
# --------------------------------


# XML Splitter
# ------------
if ($_OPERATION -eq "Splitter_Mode")
    {
    rv _API_XML_URL  | Out-Null
    Write-Host "Splitter Mode allows to take an existing Sophos XG XML export and load it"
    Write-Host "one by one, having visual feedback when each object loads without waiting for"
    Write-Host "the whole result to come."
    Write-Host ""
    Write-Host "Example of normal XML object: "
    Write-Host ""
    Write-Host '<IPHost transactionid="">'
    Write-Host '    <Name>172.20.1.16/32</Name>'
    Write-Host '    <IPFamily>IPv4</IPFamily>'
    Write-Host '    <HostType>IP</HostType>'
    Write-Host '    <IPAddress>172.20.1.16</IPAddress>'
    Write-Host '</IPHost>'
    Write-Host ""
    Write-Host "In this example, the tag for this object is IPHost. If you have many of this, just"
    Write-Host "put the XML in the file, indicate the tag to look for and wait for the automated"
    Write-Host "loading."
    Write-Host ""
    $_TAG_TO_IMPORT = read-host -Prompt "Please write the tag to search for: "
    Write-Host ""
    Write-Host ""

    foreach($line in [System.IO.File]::ReadLines("$_WORK_FOLDER$_DATA_FILE_NAME"))
        {
        $_API_XML_URL = $_API_XML_URL + $line
        if($line -match '<Name>')
            {
            $_ITEM_NAME = $line -replace '<[/]?Name>',''            
            }    

        if ($line -match "</$($_TAG_TO_IMPORT)>")
            {
            Write-Host "[INFO] Processing $($_ITEM_NAME)"
            $_API_XML_URL_CLEANED = $_API_XML_URL -replace "> *<","><"
            $_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Set>$($_API_XML_URL_CLEANED)</Set></Request>"
			$_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
            [xml] $_API_QUERY_RESULT_PARSED = $_API_QUERY_RESULT.Content
            if ($_API_QUERY_RESULT.Content -match "<Status code=`"200`"")
                {
                Write-Host "[ OK ] Processed OK"
                } else {
                Write-Host "[WARN] Error in execution"
                }
            rv _API_XML_URL  | Out-Null
            Write-Host ""
            }
        }
    }

# FIN XML Splitter
# ------------

You need to download this code and put in somewhere your Windows computer as a .ps1 Powershell file. Then you have to open "Windows Powershell ISE" in administrator mode and open the script in there.

Now, go to your firewall and allow API usage from the IP that will have the script running:

  1. Enable API
  2. Type the IP address of the computer hosting the script
  3. Add it
  4. Apply

Once you have opened the script, you need to supply the parameters for your firewall:

  1. The IP of your firewall
  2. The admin port of your firewall
  3. The admin user (normally "admin")
  4. The password for the account
  5. The name of the file including the objects (needs to be inside the "work folder")
  6. The work folder (any folder as long as the script can write there)
  7. If you want to add prefixes to objects created by script (HOST_, NET_, FQDN_ - Have to put "Yes" or "No")

Run It

And then, run it!

You'll be prompted with the execution mode as explained before. Be careful, if you select "IPHost" but you have FQDN in your file, it might cause problems or errors. 

Choose your mode and press ENTER. The program will start checking every object and proceed to create it in the firewall and provide output about that operation. If the code is 200, everything is ok. Otherwise, check the code in the Sophos API documentation.

The script also creates a log file in the working folder for future references about what failed and what ended up OK.

Whats next?

There're some know issues:

  • If you mess up the password, it will fail every item in the file instead of saying it at the beginning, working on it.
  • Trying to add more ways for automode to accept FQDN (check for *?, check for 255?, etc).
  • Lacking some arguments to run it in non interactive mode (faster?)
  • Will try to add more things that it can automate (services?, iphostgroups?)

And yeah, basically this is a hobby for fun but if you have doubts, requests, bugs, let me know. I'll try to address them.

Take care, stay safe!

----

Updated 21 November, Version 1.5:

  • Fixed some things (FQDN detection)
  • Added credential validation

Updated March 5th, Version 1.6:

  • Fixed log folder problem
  • Added context help on code

Updated May 11th, Version 1.7:

  • Added case for single IP detection on auto mode
  • Added option to add prefixes to objects while adding them

Updated May 15th, Version 1.8:

    • Added splitter mode
    • Some code cleanup.

Updated April 8th:

  • This will be no longer be updated or monitored.




Added horizontal line at the end of RR, Edited Grammer, Added Table of Contents, Corrected Title
[edited by: Raphael Alganes at 3:26 PM (GMT -8) on 24 Nov 2023]
  • Hello,

    Thank you for your contribution to the Sophos Community.

    I have moved this to the Recommended Read section.

    Regards,


     
    Emmanuel (EmmoSophos)
    Technical Team Lead, Global Community Support
    Sophos Support VideosProduct Documentation  |  @SophosSupport  | Sign up for SMS Alerts
    If a post solves your question use the 'Verify Answer' link.
  • Hello,

    I can read the IP addresses detected in brute force attacks on MS SQL Server in the Windows Server event log.
    I want to automatically add the IP information here to the IP'list object in Sophos FW. Can you assist with this?

    This object will be configured as deny based on a rule.

  • # Variables you need to adjust for your environment
    # -------------------------------------------------
    $_FIREWALL_IP = "192.168.1.152"
    $_FIREWALL_PORT = "4444"
    $_API_USER = "admin"
    $_API_PASSWORD = 'passwordhere'
    $_WORK_FOLDER = "D:\OneDrive\Scripts\XG\PowerShell\ImportMan\1.8\"
    $_OBJECT_NAME = "Bad-IPs"
    $_FILE_WITH_IPS = "D:\BadIPs.txt"
    
    # Variables that SHOULDN'T be modified by the user
    # ------------------------------------------------
    $_LOGS_FOLDER = ([String](Get-Date -Format 'ddMMyyyy_HHmm'))
    
    # -------------------------------------------------------------------------------------------------------------------------
    # NOTHING BELOW THIS POINT IS REQUIRED TO BE UPDATED BY THE USER (UNLESS THEY WANT TO IMPROVE THE CODE WHICH IS APPRECIATED
    # MODIFIYING ANYTHING FROM THIS POINT MIGHT CAUSE THE SCRIPT TO NOT WORK
    # -------------------------------------------------------------------------------------------------------------------------
    
    
    New-Item -ItemType "directory" -Path $_WORK_FOLDER -Name $_LOGS_FOLDER | Out-Null
    
    # HTTPutility addon
    # -------------------------
    Add-Type -AssemblyName System.Web
    
    # Convert variable to URI compatible format
    # -----------------------
    $_CODIFIED_API_PASSWORD = [System.Web.HttpUtility]::UrlEncode($_API_PASSWORD)
    
    # Allow SSL connections
    # -----------------------
    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
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
    
    # Testing credentials prior to upload objects
    # -------------------------------------------
    Write-Host "[INFO] Validating connection to appliance..."
    $_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login></Request>"
    $_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
    [xml] $_API_QUERY_CONNECTIVITY_TEST_RESULT = $_API_QUERY_RESULT.Content
    
    if ($_API_QUERY_CONNECTIVITY_TEST_RESULT.Response.Login.Status -ne "Authentication Successful")
        {
        Write-Host "[WARN] A problem have occur connecting to the firewall or credentials are not valid. Check and try again later."
        break
        } else {
        Write-Host "[ OK ] Connection to firewall succesful. Starting object creation."
        Write-Host ""
        }
    
    Remove-Variable _IPS_TO_ADD
    Remove-Variable _NEW_IPS
    Remove-Variable _NEW_CONTENT_IPLIST
    Remove-Variable _CURRENT_IP_ADDRESSES
    
    # Getting current object
    # -------------------------------------------   
    $_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Get><IPHost><Filter><key name=`"Name`" criteria=`"like`">$($_OBJECT_NAME)</key></Filter></IPHost></Get></Request>"
    $_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
    [xml] $_API_QUERY_IP_LIST_OBJECT = $_API_QUERY_RESULT.Content
    $_CURRENT_IP_ADDRESSES = $_API_QUERY_IP_LIST_OBJECT.Response.IPHost.ListOfIPAddresses
    
    
    $_IPS_TO_ADD = Get-Content -Path $_FILE_WITH_IPS
    foreach ($_IP_ADDRESS in $_IPS_TO_ADD) {
        $_NEW_IPS = $_NEW_IPS + "," + $_IP_ADDRESS
    }
    
    $_NEW_CONTENT_IPLIST = $_CURRENT_IP_ADDRESSES + $_NEW_IPS
    
    $_API_QUERY_URL = "https://$($_FIREWALL_IP):$($_FIREWALL_PORT)/webconsole/APIController?reqxml=<Request><Login><UserName>$($_API_USER)</UserName><Password>$($_CODIFIED_API_PASSWORD)</Password></Login><Set><IPHost><Name>$($_OBJECT_NAME)</Name><IPFamily>IPv4</IPFamily><HostType>IPList</HostType><ListOfIPAddresses>$($_NEW_CONTENT_IPLIST)</ListOfIPAddresses></IPHost></Set></Request>"
    $_API_QUERY_RESULT = Invoke-WebRequest -Uri "$_API_QUERY_URL"
    [xml] $_API_QUERY_RESULT_PARSED = $_API_QUERY_RESULT.Content

    Hey, did a quick script for your needs. It will update the object that you define in the variables.

    In Point 1, put the name of the IPList object that you want to update with new IPs

    In Point 2, write the file (and his path) which includes the new IPs to add to the IPlist object. The file should be 1 IP per line.

    And then you can just run this script with a scheduled task.

    Hope it helps.

  • You are great! I will try this. Isn't all I need to do to print the threads in the security log to a txt file?

  • Basically, the scripts expects 1 IP for each line, multiple lines.

    So for example: 

    192.168.1.100

    192.168.1.200

    172.16.12.20

    ...

    Its a valid file content. How will you do to get that format is something you need to check. You can use any method or way you want, as long as the file has the format indicated before.

    Best of lucks!

    PD: I did this in a quick time window, didnt test it exhaustively nor do I have Windows Server. It would be wise to test it fine prior to have it on production. Did a quick test with my personal Sophos XG and it updated the IP List just fine.