Initiating a Vulnerability Scan with IP360 Rest API and PowerShell

One of the most common things I do with Tripwire's IP360 in Professional Services it automate workflows. Nearly everyone wants a way to quickly trigger a scan (be it on detection of a new machine or a request for further data in a security playbook) and it's nice and easy to do thanks to the REST API - here's an example I've put together in a PowerShell script (since a lot of sysadmins remain in the windows world!).

<#
.SYNOPSIS
 This script is designed to trigger ad hoc scans of networks
.DESCRIPTION
 This script is designed to trigger ad hoc scans of IP360 networks

 THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
 FITNESS FOR A PARTICULAR PURPOSE, AND/OR NONINFRINGEMENT.
 This script is not supported under any Tripwire standard support program or service.
 The script is provided AS IS without warranty of any kind. Tripwire further disclaims all
 implied warranties including, without limitation, any implied warranties of merchantability
 or of fitness for a particular purpose. The entire risk arising out of the use or performance
 of the sample and documentation remains with you. In no event shall Tripwire, its authors,
 or anyone else involved in the creation, production, or delivery of the script be liable for
 any damages whatsoever (including, without limitation, damages for loss of business profits,
 business interruption, loss of business information, or other pecuniary loss) arising out of
 the use of or inability to use the sample or documentation, even if Tripwire has been advised
 of the possibility of such damages.
 WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, TRIPWIRE HAS NO OBLIGATION TO INDEMNIFY OR
 DEFEND RECIPIENT AGAINST CLAIMS RELATED TO INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS.
.NOTES
 Version: 1.1 - Update to add new functionality
 Author: Tripwire Professional Services (Chris Hudson)
 Client Name: N/A
 Creation Date: Nov 2019
 Currently this script DISABLES SSL validation.
 This is not a recommended practice and is inherently insecure.
.EXAMPLE
 Invoke-IP360-Scan -startTime "2019-11-05 11:48:21Z" -endTime "2019-11-06 11:48:21Z" -NetworkName "My
Network" -AppliancePool "DP Pool UK" -ProfileName "API Scanning Profile" -ScanName "Adhoc API Scan"
 Starts a scan of the network "My Network" based on the time settings - watch your time formatting!
.EXAMPLE
 $adhoctimes = Get-IP360-ScanDateForAdhoc
 Invoke-IP360-Scan -startTime $adhoctimes.Starttime -endTime $adhoctimes.EndTime -NetworkName $NetworkName -
AppliancePool $AppliancePool -ProfileName $ProfileName -ScanName "Test"
.LINK
 www.tripwire.com
#>
<#
=========================================
CHANGELOG:
=========================================
1.0 Initial release
1.1 Added invoke function to run immediately
#>
#--------------------------------------------------------------[Params]
------------------------------------------------------------
Param(
# VNE IP address
[Parameter(Mandatory=$true,HelpMessage="VNE IP Address or hostname")]$VNE,
# VNE Username
[Parameter(Mandatory=$true,HelpMessage="VNE username")]$username,
# VNE Password
[Parameter(Mandatory=$true,HelpMessage="VNE password")]$password,
# Accepts either $true or $false to enable or disable ssl checks
[Parameter(Mandatory=$false,HelpMessage='Set to $true or $false to enable or disable ssl
checks')]$disableSSLcheck,
#The start scan date/time in the form of 2019-11-05 11:48:21Z - ensure this is in the future!
[Parameter(Mandatory=$true,HelpMessage="The start scan date/time in the form of 2019-11-05 11:48:
21Z")]$startTime,
# The end scan date/time in the form of 2019-11-05 11:48:21Z - ensure this is after your start date!
[Parameter(Mandatory=$true,HelpMessage="The end scan date/time in the form of 2019-11-05 11:48:21Z")]$endTime,
#Network name to scan - if uncertain, try using Get-IP360-Networks first
[Parameter(Mandatory=$true,HelpMessage="Network name to scan - if uncertain, try using Get-IP360-Networks
first")]$NetworkName,
# Appliance Pool to scan with - if uncertain, try using Get-IP360-AppliancePools first
[Parameter(Mandatory=$true,HelpMessage="Appliance Pool to scan with - if uncertain, try using Get-IP360-
AppliancePools first")]$AppliancePool,
# Profile to scan with - if uncertain, try using Get-IP360-ScanProfiles first
[Parameter(Mandatory=$true,HelpMessage="Profile to scan with - if uncertain, try using Get-IP360-ScanProfiles
first")]$ProfileName,
# The name you wish to give to the created scan
[Parameter(Mandatory=$true,HelpMessage="The name you wish to give to the created scan")]$ScanName
)
#---------------------------------------------------------[Initialisations]
--------------------------------------------------------
# None
#----------------------------------------------------------[Declarations]
----------------------------------------------------------
#Script Version
$ScriptVersion = "1.0"
#-----------------------------------------------------------[Functions]
------------------------------------------------------------
################ ********************* ####################
# Turn off SSL validation. (NOT RECOMMENDED FOR PRODUCTION):
################ ********************* ####################
function Disable-SSLValidation {
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
}
function Get-IP360-Network{
 param($NetworkName)
 $NetworkName = [System.Web.HttpUtility]::UrlEncode($NetworkName)
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"networks?name=$networkname") -WebSession $ip360session
 if($r.count -eq 0){Write-host "Error - object not found - check name"}else{return $r.results}
}
function Get-IP360-Networks{
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"networks") -WebSession $ip360session
 return $r.results
}
function Get-IP360-AppliancePool{
 param($AppliancePool)
 $AppliancePool = [System.Web.HttpUtility]::UrlEncode($AppliancePool)
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"appliance_pools?name=$AppliancePool") -WebSession
$ip360session
 if($r.count -eq 0){Write-host "Error - object not found - check name"}else{return $r.results}
}
function Get-IP360-AppliancePools{
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"appliance_pools") -WebSession $ip360session
 return $r.results
}
function Get-IP360-ScanProfile{
 param($ProfileName)
 $ProfileName = [System.Web.HttpUtility]::UrlEncode($ProfileName)
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"scan_profiles?name=$ProfileName") -WebSession $ip360session
 if($r.count -eq 0){Write-host "Error - object not found - check name"}else{return $r.results}
}
function Get-IP360-ScanProfiles{
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"scan_profiles") -WebSession $ip360session
 return $r.results
}
function Get-IP360-ScanDateForAdhoc{
 $Temp = (Get-Date).AddMinutes(5)
 $startTime = Get-Date $Temp -Format u
 $Temp = (Get-date).AddDays(1)
 $endTime = Get-Date $Temp -Format u
 $daterange = @{'Starttime'=$startTime;'EndTime'=$endTime}
 return $daterange
}
function Invoke-IP360-Scan{
 param($startTime,$endTime,$NetworkName,$AppliancePool,$ProfileName,$ScanName)
 if(!$ScanName){$ScanName = ("API-Invoked-Scan-" + (New-Guid))}
 $appliancepooltouse = Get-IP360-AppliancePool -AppliancePool $AppliancePool
 $appliancepooltouse = $appliancepooltouse.url
 $networktouse = Get-IP360-Network -NetworkName $NetworkName
 $networktouse = $networktouse.url
 $profiletouse = Get-IP360-ScanProfile -ProfileName $ProfileName
 $profiletouse = $profiletouse.url
 $payload = @{name="$ScanName";scan_profile="$profiletouse";is_debug=$false;scan_end_datetime= $endTime;
scan_start_datetime= $startTime;pool="$appliancepooltouse";network= "$networktouse"
 } | ConvertTo-Json
 Write-debug $payload
 $r = Invoke-RestMethod -Method Post -Uri ($uri+"scan_schedules") -WebSession $ip360session -ContentType
"application/json" -Body $payload
}
function Get-IP360-ScanSchedules{
 param($ScanScheduleName)
 $ScanScheduleName = [System.Web.HttpUtility]::UrlEncode($ScanScheduleName)
 $r = Invoke-RestMethod -Method Get -Uri ($uri+"scan_schedules") -WebSession $ip360session
 $r = $r | Where-Object {$_.results.name -eq $ScanScheduleName} # For some reason, search doesn't reliable
return networks, so we filter here
 if($r.count -eq 0){Write-host "Error - object not found - check name"}else{return $r.results}
}
function Invoke-IP360-OnDemandScan-Now{
 param($startTime,$endTime,$NetworkName,$AppliancePool,$ProfileName,$ScanName)
 if(!$ScanName){$ScanName = ("API-Invoked-Scan-" + (New-Guid))}
 $ScanID = Get-IP360-ScanSchedules -ScanScheduleName $ScanName
 if($ScanID.results.count -gt 1){Write-host "WARNING: More than one profile found matching this scan name -
please ensure you use unique scan names";}#break}
 $scanid = ($scanid.url -split '/')[-1]
 $appliancepooltouse = Get-IP360-AppliancePool -AppliancePool $AppliancePool
 $appliancepooltouse = $appliancepooltouse.url
 $networktouse = Get-IP360-Network -NetworkName $NetworkName
 $networktouse = $networktouse.url
 $profiletouse = Get-IP360-ScanProfile -ProfileName $ProfileName
 $profiletouse = $profiletouse.url
 $payload = @{name="$ScanName";scan_profile="$profiletouse";is_debug=$false;scan_end_datetime= $endTime;
scan_start_datetime= $startTime;pool="$appliancepooltouse";network= "$networktouse"} | ConvertTo-Json
 $r = Invoke-RestMethod -Method Put -Uri ($uri+"scan_schedules/$scanid") -WebSession $ip360session -
ContentType "application/json" -Body $payload
}
function Invoke-IP360-Audit{
 param($NetworkName,$AppliancePool,$ProfileName,$ScanName)
 $appliancepooltouse = Get-IP360-AppliancePool -AppliancePool $AppliancePool
 $appliancepooltouse = $appliancepooltouse.url
 $networktouse = Get-IP360-Network -NetworkName $NetworkName
 $networktouse = $networktouse.url
 $profiletouse = Get-IP360-ScanProfile -ProfileName $ProfileName
 $profiletouse = $profiletouse.url
 $payload = @{name="$ScanName";scan_profile="$profiletouse";debug=$false;pool="$appliancepooltouse";network=
"$networktouse"} | ConvertTo-Json
 $r = Invoke-RestMethod -Method Post -Uri ($uri+"audits") -WebSession $ip360session -ContentType "application
/json" -Body $payload
}
#-----------------------------------------------------------[Execution]
------------------------------------------------------------
# Build connection settings
if($disableSSLcheck -eq $True){Disable-SSLValidation}
Write-host "This script gathers data about DPs"
if($Vne -eq $null)
 {Write-host "Please enter a valid IP360 VNE Address"
 Break
 }
else
 {
 Write-host "Attempting to connect to $Vne"
 # $testnetconnect = Test-NetConnection -Port 443 -ComputerName $Vne
 if ($testnetconnect.TcpTestSucceeded -eq $True){
 Write-host "Connection successfully on port 443"
 }
 else
 {
 Write-host "Unable to establish connection to $Vne on port 443- please check firewall configuration"
 # Break
 }
 }
$uri = "https://$Vne/rest/v1/"
Write-host "Connecting to API via $uri"
# Check for credentials
if(!$password -or !$username){
 # prompt for credentials
 Write-host "Credentials required"
 Break
}
else
{
 # Connect to IP360
 # Get login form
 $loginform = Invoke-WebRequest -Method Get -Uri "https://$VNE/index.ice" -SessionVariable ip360session
 # Use form for a login
 $loginform.Forms[0].Fields.login = $username
 $loginform.Forms[0].Fields.password = $password
 $loginform.Forms[0].Fields.do = "auth"
 $connect = Invoke-WebRequest -Method Post -Uri "https://$VNE/index.ice" -WebSession $ip360session -Body
$loginform
 $ip360session.headers.Add("Referer","https://$vne")
 $sid = $ip360session.Cookies.GetCookies("https://$VNE/index.ice")
 $csrf = $ip360session.Cookies.GetCookies("https://$VNE/index.ice") | Where-Object {$_.name -eq "csrftoken"}
| select value
 $csrf = $csrf[0].Value
 $ip360session.Headers.Add('X-CSRFToken',"$csrf")
}
Invoke-IP360-Scan -startTime $startTime -endTime $endTime -NetworkName $NetworkName -AppliancePool
$AppliancePool -ProfileName $ProfileName -ScanName $ScanName
Invoke-IP360-Audit -NetworkName $NetworkName -AppliancePool $AppliancePool -ProfileName $ProfileName -ScanName
$ScanName
Remove-Variable ip360session 

With that script in place (assuming the script is in the same path as you are currently located) to initiate an ad-hoc scan you can run:

.\Invoke-IP360-Scan.ps1 -VNE “192.168.1.99” -username “apiuser@tripwire.com” -password “MyPassword” -
disableSSLcheck $true -startTime "2019-11-05 11:48:21Z” -endTime "2019-11-07 11:48:21Z” -NetworkName “My
Network” -AppliancePool “My Appliance Pool” -ProfileName ”Scan Profile X” -ScanName "My Test Scan"

Note the date format - I'm not doing anything clever to force the format or validate, so be careful with use!

You could also use:

Get-help .\Invoke-IP360-Scan.ps1 –Detailed

for additional instructions on the parameters - although I suspect most will make sense from the names alone! Included in the script there are some helper functions in there that can enumerate your networks/app pools/profiles, etc which might help if you run into issues.