├── PPRT.psd1
├── PPRT.history.zip
├── Private
├── shorturls.xml
├── Write-LogEntry.ps1
├── Create-PPRTDatabase.ps1
├── Create-PPRTDatabaseTables.ps1
├── Add-ObjectDetail.ps1
└── Parse-EmailHeader.ps1
├── DRAFT
├── Untitled9.ps1
└── Get-FirstReceivedIPMapInfo.ps1
├── PPRT.psm1
├── Public
├── Connect-RIPE.ps1
├── Connect-APNIC.ps1
├── Connect-LACNIC.ps1
├── Get-ParsedURL.ps1
├── Send-ToAntiPhishingGroup.ps1
├── Send-ToIronPort.ps1
├── Get-URLFromMessage.ps1
├── Get-PhishingGeoLocationAllIPs.ps1
├── Send-ToAbuseContact.ps1
├── Get-PhishingGeoLocationStartingIPs.ps1
├── Get-IPaddress.ps1
├── Get-LongUrl.ps1
├── Get-WhichWHOIS.ps1
├── Expand-ShortURL.ps1
├── Check-ARIN.ps1
├── Connect-ARIN.ps1
├── New-AllReceivedFromIPObject.ps1
├── Get-AbsoluteUri.ps1
├── New-PPRTAbuseContactObject.ps1
├── Invoke-VTAttachment.ps1
├── Send-PPRTNotification.ps1
├── Get-PhishingGeoLocationHeatMap.ps1
├── New-FirstReceivedFromIPObject.ps1
├── New-PPRTNotificationObject.ps1
├── Send-PhishingNotifications.ps1
├── Export-MessageAttachment.ps1
├── New-MessageObject.ps1
├── Parse-EmailHeader.ps1
├── Invoke-PhishingResponse.ps1
└── Get-PhishingGeoLocation.ps1
└── README.md
/PPRT.psd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MSAdministrator/PPRT/HEAD/PPRT.psd1
--------------------------------------------------------------------------------
/PPRT.history.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MSAdministrator/PPRT/HEAD/PPRT.history.zip
--------------------------------------------------------------------------------
/Private/shorturls.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MSAdministrator/PPRT/HEAD/Private/shorturls.xml
--------------------------------------------------------------------------------
/DRAFT/Untitled9.ps1:
--------------------------------------------------------------------------------
1 |
2 | #check and see if Database has previously been created
3 | #Check the registry for information about the database
4 | #If it has been created, then open connection
5 | #if it has not been created
6 | #then create the database
7 | Create-PPRTDatabase -Server $Serverz
8 | #then create the Tables
9 | Create-PPRTDatabaseTables -Server $Server
10 | #add this information to the Registry
11 |
12 |
13 | $cmd.commandtext = "INSERT INTO servers (servername,username,spversion,reason) VALUES('{0}','{1}','{2}','{3}')" -f $os.__SERVER,$env.username,$os.servicepackmajorversion,$reason
14 | $cmd.executenonquery()
15 | $conn.close()
--------------------------------------------------------------------------------
/PPRT.psm1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | #Get public and private function definition files.
3 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
4 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
5 |
6 | #Dot source the files
7 | Foreach($import in @($Public + $Private))
8 | {
9 | Try
10 | {
11 | . $import.fullname
12 | }
13 | Catch
14 | {
15 | Write-Error -Message "Failed to import function $($import.fullname): $_"
16 | }
17 | }
18 |
19 | #download and import POSH-VirusTotal
20 | if (!(Test-Path -Path "$Home\Documents\WindowsPowerShell\Modules\Posh-VirusTotal"))
21 | {
22 | Write-Verbose -Message 'Downloading Posh-VirusTotal PowerShell Module....'
23 | Invoke-Expression -Command (New-Object -TypeName Net.WebClient).DownloadString('https://gist.githubusercontent.com/darkoperator/9138373/raw/22fb97c07a21139a398c2a3d6ca7e3e710e476bc/PoshVTInstall.ps1')
24 | }
25 |
26 | Export-ModuleMember -Function $Public.Basename
--------------------------------------------------------------------------------
/Public/Connect-RIPE.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 3
2 | function Connect-RIPE ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,Position = 1,HelpMessage = 'Please provide a IP address')]
7 | $ipaddress
8 | )
9 | <#
10 | .SYNOPSIS
11 | Takes IP address as input and queries RIPE's WHOIS implementation for the IP addresses abuse contact email - RESTFul API
12 |
13 | .DESCRIPTION
14 | Takes a IP Address and searches for RIPE's WHOIS abuse contact email for that IP based on registration data
15 | Returns this contact email address
16 |
17 | .PARAMETER ipaddress
18 | Specifices the specific IP address belonging to RIPE
19 |
20 | .EXAMPLE
21 | C:\PS> Check-RIPE -ipaddress '195.42.65.82'
22 |
23 | #>
24 |
25 |
26 | $abusecontact = Invoke-RestMethod -Uri "http://rest.db.ripe.net/abuse-contact/$ipaddress"
27 |
28 | $result = $abusecontact.'abuse-resources'.'abuse-contacts'.email
29 |
30 | return $result
31 | }
32 |
--------------------------------------------------------------------------------
/Public/Connect-APNIC.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 3
2 | function Connect-APNIC ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,Position = 1,HelpMessage = 'Please provide a IP address')]
7 | $ipaddress
8 | )
9 | <#
10 | .SYNOPSIS
11 | Takes IP address as input and queries APNIC's RDAP implementation for the IP addresses abuse contact email - RESTFul API
12 |
13 | .DESCRIPTION
14 | Takes a IP Address and searches for APNIC's RDAP abuse contact email for that IP based on registration data
15 | Returns this contact email address
16 |
17 | .PARAMETER ipaddress
18 | Specifices the specific IP address belonging to APNIC
19 |
20 | .EXAMPLE
21 | C:\PS> Check-APNIC -ipaddress '150.42.65.82'
22 |
23 | #>
24 |
25 | $regx2 = "[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
26 |
27 | $rawdata = Invoke-WebRequest -Uri "http://rdap.apnic.net/ip/$ipaddress" | ConvertFrom-Json
28 |
29 | for($i = 0;$i -lt ($rawdata.entities.vcardArray).count; $i++)
30 | {
31 | foreach ($item in $rawdata.entities.vcardArray.SyncRoot[$i])
32 | {
33 | [array]$result += $item
34 | }
35 | }
36 |
37 | $result | Select-String -Pattern $regx2
38 |
39 | return $result
40 | }
41 |
--------------------------------------------------------------------------------
/Public/Connect-LACNIC.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 3
2 | function Connect-LACNIC ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,Position = 1,HelpMessage = 'Please provide a IP address')]
7 | $ipaddress
8 | )
9 | <#
10 | .SYNOPSIS
11 | Takes IP address as input and queries LACNIC's RDAP implementation for the IP addresses abuse contact email - RESTFul API
12 |
13 | .DESCRIPTION
14 | Takes a IP Address and searches for LACNIC's RDAP abuse contact email for that IP based on registration data
15 | Returns this contact email address
16 |
17 | .PARAMETER ipaddress
18 | Specifices the specific IP address belonging to LACNIC
19 |
20 | .EXAMPLE
21 | C:\PS> Check-LACNIC -ipaddress '190.42.65.82'
22 |
23 | #>
24 |
25 |
26 | $regx = "[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
27 |
28 | $rawdata = Invoke-WebRequest -Uri "http://rdap.lacnic.net/rdap/ip/$ipaddress" | ConvertFrom-Json
29 |
30 | for($i = 0;$i -lt ($rawdata.entities.vcardArray).count; $i++)
31 | {
32 | foreach ($item in $rawdata.entities.vcardArray.SyncRoot[$i])
33 | {
34 | [array]$result += $item
35 | }
36 | }
37 | $parsedresult = $result | Select-String -Pattern $regx
38 | Write-Debug -Message 'parsed result: ' $parsedresult
39 | if ($parsedresult.count -gt 0)
40 | {
41 | return $parsedresult
42 | }
43 | return 'NO POC FOR LACNIC'
44 | }
45 |
--------------------------------------------------------------------------------
/Private/Write-LogEntry.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 1
2 | Function Write-LogEntry
3 | {
4 | param (
5 | [string]$type,
6 | [string]$message,
7 | [string]$Folder,
8 | [string]$CustomMessage
9 | )
10 |
11 | [bool]$CustomMessage
12 |
13 | $mutex = New-Object -TypeName 'Threading.Mutex' -ArgumentList $false, 'MyInterprocMutex'
14 |
15 | switch ($type){
16 | 'Error'
17 | {
18 | $mutex.waitone()
19 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [ERROR]: $message" >> "$($Folder)\log.log"
20 | if ($CustomMessage)
21 | {
22 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [CUSTOM MESSAGE]: $CustomMessage" >> "$($Folder)\log.log"
23 | }
24 | $mutex.ReleaseMutex()
25 | }
26 | 'Info'
27 | {
28 | $mutex.waitone()
29 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [INFO]: $message" >> "$($Folder)\log.log"
30 | if ($CustomMessage)
31 | {
32 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [CUSTOM MESSAGE]: $CustomMessage" >> "$($Folder)\log.log"
33 | }
34 | $mutex.ReleaseMutex()
35 | }
36 | 'Debug'
37 | {
38 | $mutex.waitone()
39 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [DEBUG]: $message" >> "$($Folder)\log.log"
40 | if ($CustomMessage)
41 | {
42 | "$((Get-Date).ToString('yyyyMMddThhmmss')) [CUSTOM MESSAGE]: $CustomMessage" >> "$($Folder)\log.log"
43 | }
44 | $mutex.ReleaseMutex()
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Public/Get-ParsedURL.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-ParsedURL ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a URL to parse')]
8 | $url,
9 |
10 | [parameter(Mandatory = $true,
11 | HelpMessage = 'Please provide a log path.')]
12 | $logpath
13 | )
14 | <#
15 | .SYNOPSIS
16 | Takes a URL as input and splits the URL down to just the hostname. This function returns parsed URL
17 |
18 | .DESCRIPTION
19 | Takes a URL as input and splits the URL down to just the hostname.
20 | This function returns parsed URL
21 |
22 | .PARAMETER url
23 | Specifices the specific URL
24 |
25 | .EXAMPLE
26 | C:\PS> Get-ParsedURL -url 'http://outlookadminmailaccess.bravesites.com/'
27 |
28 | #>
29 |
30 | $ReturnObject = @()
31 |
32 | $regexipv4 = '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3} (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b'
33 |
34 | if ($url -like $regexipv4)
35 | {
36 | $log = Write-LogEntry -type 'INFO' -message "URL is a IP Address - URL = $url" -Folder $logpath
37 | return $url
38 | }
39 |
40 | $ParsedURL = [system.net.webrequest]::Create($url)
41 |
42 | $AbsoluteURL = $ParsedURL.GetResponse().ResponseUri.AbsoluteUri
43 | $URLAuthoirty = $ParsedURL.GetResponse().ResponseUri.Authority
44 |
45 | $props = @{
46 | OriginalURL = $url
47 | AbsoluteURL = $AbsoluteURL
48 | URLAuthority = $URLAuthoirty
49 | }
50 |
51 | $ReturnObject = New-Object -TypeName PSObject -Property $props
52 |
53 | return $ReturnObject
54 | }
55 |
--------------------------------------------------------------------------------
/Public/Send-ToAntiPhishingGroup.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Send-ToAntiPhishingGroup
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please the trimmed phishing url link')]
8 | [string]$trimmedlink,
9 |
10 | [parameter(Mandatory = $true,
11 | HelpMessage = 'Please provide th Send On Behalf email address.')]
12 | $From,
13 |
14 | [parameter(Mandatory = $true,
15 | HelpMessage = 'Please provide a logging location')]
16 | $LogLocation
17 | )
18 |
19 | $date = Get-Date -Format yyyyMMdd
20 | "$trimmedlink" + ',' + "$date"
21 |
22 | try
23 | {
24 | $outlook = New-Object -ComObject Outlook.Application
25 | $Mail = $outlook.CreateItem(0)
26 | $Mail.To = 'anti-phishing-email-reply-discuss@googlegroups.com'
27 | $Mail.Sentonbehalfofname = "$($From)"
28 | $Mail.Subject = ('Phishing Links ' + $date)
29 | $Mail.Body = "$trimmedlink" + ',' + "$date"
30 | $Mail.Send()
31 | Write-LogEntry -type Info -message 'Sucessfully sent notification to Abuse Contact' -Folder $LogLocation -CustomMessage "Sent $("$trimmedlink" + ',' + "$date") to: anti-phishing-email-reply-discuss@googlegroups.com"
32 | return $true
33 | }
34 | catch
35 | {
36 | $msg = ('An error occurred that could not be resolved: {0}' -f $_.Exception.Message)
37 | Write-LogEntry -type ERROR -message 'Error Sending to Abuse Contact' -Folder $LogLocation -CustomMessage "$msg"
38 | Write-LogEntry -type ERROR -message 'Exception' -Folder $LogLocation -CustomMessage "$($_.Exception)"
39 | Write-LogEntry -type ERROR -message 'Unknown Exception' -Folder $LogLocation -CustomMessage "$($_)"
40 | return $false
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Public/Send-ToIronPort.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Send-ToIronPort
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please the original phishing url link')]
8 | [string]$originallink,
9 |
10 | [parameter(Mandatory = $true,
11 | HelpMessage = 'Please provide the original message to attach to email. ')]
12 | $messagetoattach,
13 |
14 | [parameter(Mandatory = $true,
15 | HelpMessage = 'Please provide th Send On Behalf email address.')]
16 | $From,
17 |
18 | [parameter(Mandatory = $true,
19 | HelpMessage = 'Please provide a logging location')]
20 | $LogLocation
21 | )
22 |
23 | try
24 | {
25 | $outlook = New-Object -ComObject Outlook.Application
26 | $Mail = $outlook.CreateItem(0)
27 | $Mail.To = 'spam@access.ironport.com;phishing-report@us-cert.gov;spam@uce.gov'
28 | $Mail.Attachments.Add($messagetoattach)
29 | $Mail.Sentonbehalfofname = "$($From)"
30 | $Mail.Subject = 'Phishing E-Mail'
31 | $Mail.Body = "The attached email is a phishing email: $originallink"
32 | $Mail.Send()
33 | Write-LogEntry -type Info -message 'Sucessfully sent notification to Abuse Contact' -Folder $LogLocation -CustomMessage 'Sent to: spam@access.ironport.com;phishing-report@us-cert.gov;spam@uce.gov'
34 | return $true
35 | }
36 | catch
37 | {
38 | $msg = ('An error occurred that could not be resolved: {0}' -f $_.Exception.Message)
39 | Write-LogEntry -type ERROR -message 'Error Sending to Abuse Contact' -Folder $LogLocation -CustomMessage "$msg"
40 | Write-LogEntry -type ERROR -message 'Exception' -Folder $LogLocation -CustomMessage "$($_.Exception)"
41 | Write-LogEntry -type ERROR -message 'Unknown Exception' -Folder $LogLocation -CustomMessage "$($_)"
42 | return $false
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Public/Get-URLFromMessage.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-URLFromMessage
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a .MSG file.')]
8 | [PSTypeName('PPRT.Message')]
9 | $Message,
10 |
11 | [Parameter(Mandatory = $true)]
12 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
13 | $LogPath
14 | )
15 | <#
16 | .SYNOPSIS
17 | Takes a .MSG file and parses the links from the message. This function returns the full URL within an email.
18 |
19 | .DESCRIPTION
20 | Takes a .MSG file and parses the links from the message.
21 | This function returns the full URL within an email.
22 |
23 | .PARAMETER inputtext
24 | Specifices the specific .MSG to parse
25 |
26 | .EXAMPLE
27 | C:\PS> Get-URLFromMessage 'C:\Users\UserName\Desktop\PHISING_EMAILS\Dear Email User.msg'
28 |
29 | #>
30 |
31 | Begin
32 | {
33 | $URLPattern = '(?:(?:https?|ftp|file)://|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])'
34 |
35 | $URLObject = @()
36 | }
37 | Process
38 | {
39 | $log = Write-LogEntry -type Info -message "Get-URLFromMessage: Getting URL from $($Message.Subject)" -Folder $LogPath
40 |
41 | $URL = $Message.body | Select-String -AllMatches $URLPattern | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value
42 |
43 | $props = @{
44 | URL = $URL
45 | Name = $Message.Subject
46 | }
47 |
48 | $URLObject = New-Object -TypeName PSObject -Property $props
49 |
50 | $log = Write-LogEntry -type Info -message 'Get-URLFromMessage: Getting URL complete!' -Folder $LogPath
51 |
52 | Add-ObjectDetail -InputObject $URLObject -TypeName PPRT.PhishingURL
53 | }
54 | End
55 | {
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Public/Get-PhishingGeoLocationAllIPs.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-PhishingGeoLocationAllIPs
3 | {
4 | [CmdletBinding()]
5 | Param
6 | (
7 | # Param1 help description
8 | [Parameter(Mandatory = $true)]
9 | [ValidateNotNull()]
10 | [ValidateNotNullOrEmpty()]
11 | [object[]]$AllIPData,
12 | [parameter(HelpMessage = 'Please provide a folder path for ouputting generated maps')]
13 | [ValidateNotNullOrEmpty()]
14 | [string]$FolderPath
15 | )
16 |
17 | $OutStartingIPMap = "$FolderPath\PPRT_MapAllIPs.html"
18 |
19 |
20 | $html = @"
21 |
22 |
23 |
24 |
25 |
26 | Complex icons
27 |
37 |
38 |
39 |
40 |
78 |
80 |
81 |
82 | "@ | Out-File $OutStartingIPMap
83 | }
84 |
--------------------------------------------------------------------------------
/Public/Send-ToAbuseContact.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Send-ToAbuseContact
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please the original phishing url link')]
8 | [string]$originallink,
9 |
10 | [parameter(Mandatory = $true,
11 | HelpMessage = 'Please provide the abuse contact to send email to.')]
12 | $abusecontact,
13 |
14 | [parameter(Mandatory = $true,
15 | HelpMessage = 'Please provide the original message to attach to email. ')]
16 | $messagetoattach,
17 |
18 | [parameter(Mandatory = $true,
19 | HelpMessage = 'Please provide the Send On Behalf email address.')]
20 | $From,
21 |
22 | [parameter(Mandatory = $true,
23 | HelpMessage = 'Please provide a logging location')]
24 | $LogLocation
25 | )
26 |
27 | try
28 | {
29 | $outlook = New-Object -ComObject Outlook.Application
30 | $Mail = $outlook.CreateItem(0)
31 | $Mail.To = "$abusecontact"
32 | $Mail.Attachments.Add($messagetoattach)
33 | $Mail.Sentonbehalfofname = "$($From)"
34 | $Mail.Subject = 'Remove Phishing Website'
35 | $Mail.Body = "We have received a phishing attempt (attached) that is using an IP registered to this contact. Please remove this site as soon as you can: $originallink'.' `n`nIn addition, any logs you can provide surrounding the registration or usage of this site would help us understand who is targeting our environment.`n`n Thank you!"
36 | $Mail.Send()
37 | Write-LogEntry -type Info -message 'Sucessfully sent notification to Abuse Contact' -Folder $LogLocation -CustomMessage "Sent to: $abusecontact"
38 | return $true
39 | }
40 | catch
41 | {
42 | $msg = ('An error occurred that could not be resolved: {0}' -f $_.Exception.Message)
43 | Write-LogEntry -type ERROR -message 'Error Sending to Abuse Contact' -Folder $LogLocation -CustomMessage "$msg"
44 | Write-LogEntry -type ERROR -message 'Exception' -Folder $LogLocation -CustomMessage "$($_.Exception)"
45 | Write-LogEntry -type ERROR -message 'Unknown Exception' -Folder $LogLocation -CustomMessage "$($_)"
46 | return $false
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Public/Get-PhishingGeoLocationStartingIPs.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-PhishingGeoLocationStartingIPs
3 | {
4 | [CmdletBinding()]
5 | Param
6 | (
7 | # Param1 help description
8 | [Parameter(Mandatory = $true)]
9 | [ValidateNotNull()]
10 | [ValidateNotNullOrEmpty()]
11 | [object[]]$StartingIPData,
12 | [parameter(HelpMessage = 'Please provide a folder path for ouputting generated maps')]
13 | [ValidateNotNullOrEmpty()]
14 | [string]$FolderPath
15 | )
16 |
17 | $OutStartingIPMap = "$FolderPath\PPRT_StartingIPs.html"
18 |
19 |
20 | $html = @"
21 |
22 |
23 |
24 |
25 |
26 | Complex icons
27 |
37 |
38 |
39 |
40 |
75 |
77 |
78 |
79 | "@ | Out-File $OutStartingIPMap
80 | }
81 |
--------------------------------------------------------------------------------
/Public/Get-IPaddress.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-IPaddress ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a valid HOSTNAME')]
8 | [string]$hostname,
9 |
10 | [Parameter(Mandatory = $true)]
11 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
12 | $LogPath
13 | )
14 | <#
15 | .SYNOPSIS
16 | Takes HOSTNAME (DNS Name) as input and does a reverse DNS lookup on that HOSTNAME. This function returns the IP address(es) associated with it.
17 |
18 | .DESCRIPTION
19 | Takes a HOSTNAME (DNS Name) and does a reverse DNS lookup on that HOSTNAME
20 | Returns IP Address(es) associated with that HOSTNAME
21 |
22 | .PARAMETER hostname
23 | Specifices the specific HOSTNAME (DNS Name)
24 |
25 | .EXAMPLE
26 | C:\PS> Get-IPAddress -hostname wix.com
27 |
28 | #>
29 | try
30 | {
31 | $log = Write-LogEntry -type Info -message "Get-IPAddress: Attempting GetHostAddresses for $hostname" -Folder $LogPath
32 | $ipaddresses = [System.Net.Dns]::GetHostAddresses("$hostname").IPAddressToString
33 | $log = Write-LogEntry -type Info -message "Get-IPAddress: GetHostAddresses resolved $hostname to the following ipaddress(es)" -Folder $LogPath -CustomMessage $ipaddresses
34 |
35 | return $ipaddresses
36 | }
37 | catch
38 | {
39 | $log = Write-LogEntry -type Error -message "Get-IPAddress: GetHostAddresses could not resolve this host name: $hostname" -Folder $LogPath
40 | }
41 |
42 | try
43 | {
44 | $log = Write-LogEntry -type Info -message "Get-IPAddress: Attempting Test-Connection for $hostname" -Folder $LogPath
45 | $ipaddresses = (Test-Connection $hostname -Count 1).IPV4Address
46 | $log = Write-LogEntry -type Info -message "Get-IPAddress: Test-Connection resolved $hostname to the following ipaddress(es)" -Folder $LogPath -CustomMessage $ipaddresses
47 |
48 | return $ipaddresses
49 | }
50 | catch
51 | {
52 | $log = Write-LogEntry -type Error -message "Get-IPAddress: Test-Connection could not resolve this host name: $hostname" -Folder $LogPath
53 | }
54 |
55 |
56 | return $null
57 | }
58 |
--------------------------------------------------------------------------------
/Public/Get-LongUrl.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Expand-ShortURL
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a .MSG file.')]
8 | [PSTypeName('PPRT.PhishingURL')]
9 | $URLObject
10 | )
11 | <#
12 | .SYNOPSIS
13 | Takes a short url and converts it to a long url
14 |
15 | .DESCRIPTION
16 | This function takes a tinyurl and converts it to a long/normal URL using the System.Net.WebRequest class.
17 | This function will continue to call itself until the URL has been expanded successfully.
18 |
19 | .PARAMETER shorturl
20 | This parameter needs to be a TinyUrl at this time.
21 |
22 | .PARAMETER logpath
23 | This parameter is a folder path that you want to log to
24 |
25 | .EXAMPLE
26 | C:\PS> Get-LongUrl -shorturl $shortUrlVariable -logpath $logpath
27 |
28 | #>
29 |
30 | Add-Type -AssemblyName System.Web
31 |
32 | if ($URLObject | Select-Object -Property URL)
33 | {
34 | $url = $URLObject.URL -as [system.URI]
35 |
36 | if (!($uri.AbsoluteURI -ne $null -and $url.Scheme -match '[http|https]'))
37 | {
38 | exit
39 | }
40 |
41 | $encodedurl = [system.net.webrequest]::Create($url)
42 | }
43 | else
44 | {
45 | $url = $URLObject.URL -as [system.URI]
46 |
47 | if (!($uri.AbsoluteURI -ne $null -and $url.Scheme -match '[http|https]'))
48 | {
49 | exit
50 | }
51 |
52 | $encodedurl = [system.net.webrequest]::Create($url)
53 | }
54 |
55 | $AbsoluteURL = $encodedurl.GetResponse().ResponseUri.AbsoluteUri
56 | $URLAuthority = $encodedurl.GetResponse().ResponseUri.Authority
57 |
58 | Import-Clixml -Path "$(Split-Path -Path $Script:MyInvocation.MyCommand.Path)\Private\shorturls.xml" | ForEach-Object -Process {
59 | if ($AbsoluteURL -like '$_')
60 | {
61 | #call Get-LongUrl to call API to resolve to the normal/long url
62 | $ExpandedURL = Add-ObjectDetail -InputObject $AbsoluteURL -TypeName PPRT.PhishingURL
63 | $FinalURL = Expand-ShortURL $ExpandedURL
64 | }
65 | }
66 |
67 | $props = @{
68 | OriginalURL = $URLObject
69 | EncodedURL = $encodedurl
70 | AbsoluteURL = $AbsoluteURL
71 | URLAuthority = $URLAuthority
72 | }
73 |
74 | $ReturnObject = New-Object -TypeName PSObject -Property $props
75 |
76 | Add-ObjectDetail -InputObject $ReturnObject -TypeName PPRT.ExpandedURL
77 | }
78 |
--------------------------------------------------------------------------------
/Public/Get-WhichWHOIS.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-WhichWHOIS ()
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,Position = 1,HelpMessage = 'Please provide a valid IP Address')]
7 | [string]$ipaddress,
8 |
9 | [Parameter(Mandatory = $true)]
10 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
11 | $LogPath
12 | )
13 | <#
14 | .SYNOPSIS
15 | Takes IPAddress as input and finds which whois should be used.
16 |
17 | .DESCRIPTION
18 | Takes an IPAddress and splits the first octect of the IP address
19 | Takes the first octect and compares against arrays of registrars
20 | Returns which whois should be used
21 |
22 | .PARAMETER ipaddress
23 | Specifies the ipdadress we are wanting information on
24 |
25 | .EXAMPLE
26 | C:\PS> Get-WhichWHOIS -ipaddress '189.84.54.56'
27 |
28 | #>
29 |
30 | $RegistryObject = @()
31 |
32 | try
33 | {
34 | $RegistryData = Invoke-RestMethod -Uri 'http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xml'
35 | }
36 | catch
37 | {
38 | Write-LogEntry -type ERROR -message 'UNABLE TO REACH IANA.org' -Folder $LogPath
39 |
40 | throw 'Unable to reach http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xml at this time'
41 | }
42 |
43 | for ($i = 1; $i -le $RegistryData.registry.record.Count; $i++)
44 | {
45 | if ($null -ne $RegistryData.registry.record[$i].prefix)
46 | {
47 | $TrimmedIP = $(($RegistryData.registry.record[$i].prefix).TrimStart("0"))
48 |
49 | $ComparisonIP = $TrimmedIP.Substring(0,$TrimmedIP.Length - 2)
50 |
51 | if ($($ipaddress.Split('{.}')[0]) -eq $ComparisonIP)
52 | {
53 | if ($RegistryData.registry.record[$i].whois -ne $null)
54 | {
55 | $WHOIS = ($RegistryData.registry.record[$i].whois)
56 |
57 | $props = @{
58 | IPAddress = $ipaddress
59 | WHOIS = $(($WHOIS).Split('{.}')[1])
60 | OriginalWHOIS = $WHOIS
61 | }
62 |
63 | $TempObject = New-Object -TypeName PSCustomObject -Property $props
64 |
65 | Add-ObjectDetail -InputObject $TempObject -TypeName PPRT.WHOIS
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Public/Expand-ShortURL.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-AbsoluteUri
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a .MSG file.')]
8 | [PSTypeName('PPRT.PhishingURL')]
9 | $URLObject
10 | )
11 | <#
12 | .SYNOPSIS
13 | Takes a short url and converts it to a long url
14 |
15 | .DESCRIPTION
16 | This function takes a tinyurl and converts it to a long/normal URL using the System.Net.WebRequest class.
17 | This function will continue to call itself until the URL has been expanded successfully.
18 |
19 | .PARAMETER shorturl
20 | This parameter needs to be a TinyUrl at this time.
21 |
22 | .PARAMETER logpath
23 | This parameter is a folder path that you want to log to
24 |
25 | .EXAMPLE
26 | C:\PS> Get-LongUrl -shorturl $shortUrlVariable -logpath $logpath
27 |
28 | #>
29 |
30 | Add-Type -AssemblyName System.Web
31 |
32 | if ($URLObject | Select-Object -Property URL)
33 | {
34 | $url = $URLObject.URL -as [system.URI]
35 |
36 | if (!($url.AbsoluteURI -ne $null -and $url.Scheme -match '[http|https]'))
37 | {
38 | Write-Error -Message 'URL is not formatted correctly'
39 | }
40 |
41 | $encodedurl = [system.net.webrequest]::Create($url)
42 | }
43 | else
44 | {
45 | $url = $URLObject.URL -as [system.URI]
46 |
47 | if (!($url.AbsoluteURI -ne $null -and $url.Scheme -match '[http|https]'))
48 | {
49 | Write-Error -Message 'URL is not formatted correctly'
50 | }
51 |
52 | $encodedurl = [system.net.webrequest]::Create($url)
53 | }
54 |
55 | $AbsoluteURL = $encodedurl.GetResponse().ResponseUri.AbsoluteUri
56 | $URLAuthority = $encodedurl.GetResponse().ResponseUri.Authority
57 |
58 | Import-Clixml -Path "$(Split-Path -Path $Script:MyInvocation.MyCommand.Path)\Private\shorturls.xml" | ForEach-Object -Process {
59 | if ($AbsoluteURL -like '$_')
60 | {
61 | #call Get-LongUrl to call API to resolve to the normal/long url
62 | $ExpandedURL = Add-ObjectDetail -InputObject $AbsoluteURL -TypeName PPRT.PhishingURL
63 | $FinalURL = Expand-ShortURL $ExpandedURL
64 | }
65 | }
66 |
67 | $props = @{
68 | OriginalURL = $URLObject
69 | EncodedURL = $encodedurl
70 | AbsoluteURL = $AbsoluteURL
71 | URLAuthority = $URLAuthority
72 | }
73 |
74 | $ReturnObject = New-Object -TypeName PSObject -Property $props
75 |
76 | Add-ObjectDetail -InputObject $ReturnObject -TypeName PPRT.ExpandedURL
77 | }
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PPRT
2 | =============
3 |
4 | This PowerShell Module is designed to send notifications to hosting companies that host phishing URLs by utilizing the major WHOIS/RDAP Abuse Point of Contact (POC) information.
5 |
6 | 0. This function takes in a .msg file and strips links from a phishing URL.
7 | 0. After getting the phishig email, it is then converted to it's IP Address.
8 | 0. Once the IP Address of the hosting website is identified, then we check which WHOIS/RDAP to search.
9 | 0. Each major WHOIS/RDAP is represented: ARIN, APNIC, AFRNIC, LACNIC, & RIPE.
10 | 0. We call the specific WHOIS/RDAP's API to determine the Abuse POC.
11 | 0. Once we have the POC, we send them an email telling them to shut the website down. This email contains the original email as an attachment, the original phishing link, and verbage telling them to remove the website.
12 |
13 | This Module came out of necessity. I was sick of trying to contact these individual sites, so I have began automating our response time to these events.
14 |
15 | The next steps for this project are to fully intergrate into Outlook and automate this even further by enabling a simple text search or based on a selected 'folder' event.
16 |
17 | Pull requests and other contributions would be welcome!
18 |
19 | # Instructions
20 |
21 | ```powershell
22 | # One time setup
23 | # Download the repository
24 | # Unblock the zip
25 | # Extract the PPRT folder to a module path (e.g. $env:USERPROFILE\Documents\WindowsPowerShell\Modules\)
26 |
27 | # Import the module.
28 | Import-Module PPRT #Alternatively, Import-Module \\Path\To\PPRT
29 |
30 | # Get commands in the module
31 | Get-Command -Module PPRT
32 |
33 | # Get help
34 | Get-Help New-MessageObject -Full
35 | Get-Help Invoke-PhishingResponse
36 | ```
37 |
38 | ### Prerequisites
39 |
40 | * PowerShell 3 or later
41 | * A valid VirsuTotal API token (if using this feature)
42 | * This module using Posh-VirusTotal (https://github.com/darkoperator/Posh-VirusTotal)
43 |
44 | # Examples
45 |
46 | ### Create a New-MessageObject
47 |
48 | ```powershell
49 | # This example creates a new PPRT.Message Object
50 |
51 | $msgobj= New-MessageObject -Message C:\PHISHING_EMAILS -FullDetails -LogPath C:\PHISHING_EMAILS
52 |
53 |
54 | ```powershell
55 | # This example creates a new PPRT.Message Object
56 |
57 | #A folder that contains a single or multiple Phishing Emails
58 | $Message = C:\PHISHING_EMAILS
59 |
60 | #A folder that you want the log file to be created
61 | $LogPath = C:\PHISHING_EMAILS
62 |
63 | $MsgObject = New-MessageObject -Uri $Message `
64 | -LogPath $LogPath `
65 | -FullDetails
66 |
67 | ### Invoke-PhishingResponse
68 |
69 | ```powershell
70 | # This example calls Invoke-PhishingResponse
71 |
72 | #A PPRT.Message Object
73 | $Message = $MsgObject
74 |
75 | #A From address to send Phishing Notification to Abuse Contact
76 | $From = 'abuse@company.com'
77 |
78 | #The From Addresses SMTP Server
79 | $SMTPServer = 'smtp.office365.com'
80 |
81 | #Credentials for Send-MailMessage
82 | $Cred = (Get-Credential)
83 |
84 | #A folder that you want the log file to be created
85 | $LogPath = C:\PHISHING_EMAILS
86 |
87 | $PhishingResponse = Invoke-PhishingResponse -Message $MsgObject `
88 | -From $From `
89 | -SMTPServer $SMTPServer `
90 | -Credential $cred `
91 | -LogPath $LogPath
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Public/Check-ARIN.ps1:
--------------------------------------------------------------------------------
1 | function Check-ARIN (){
2 |
3 | param (
4 | [parameter(Mandatory=$true,Position=1,HelpMessage="Please provide a IP address")]
5 | $ipaddress,
6 |
7 | [Parameter(Mandatory = $true)]
8 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
9 | $LogPath
10 | )
11 | <#
12 | .SYNOPSIS
13 | Takes IP address as input and queries ARIN's WHOIS implementation for the IP addresses abuse contact email - RESTFul API
14 |
15 | .DESCRIPTION
16 | Takes a IP Address and searches for ARIN's WHOIS abuse contact email for that IP based on registration data
17 | Returns this contact email address
18 |
19 | .PARAMETER ipaddress
20 | Specifices the specific IP address belonging to ARIN
21 |
22 |
23 | .EXAMPLE
24 | C:\PS> Check-ARIN 146.42.65.82
25 |
26 | #>
27 | Begin
28 | {
29 | try
30 | {
31 | $TestingWebRequest = Invoke-WebRequest -Uri 'https://www.google.com'
32 | }
33 | catch
34 | {
35 | throw 'Unable to connect to google.com or Internet Explorer has not be used on this system.`
36 | Please correct this before proceeding.'
37 | break
38 | }
39 | }
40 | Process
41 | {
42 | try
43 | {
44 | $ipdata = Invoke-RestMethod -Uri "http://whois.arin.net/rest/ip/$ipaddress" -UseBasicParsing
45 | }
46 | catch
47 | {
48 | Write-LogEntry -type ERROR `
49 | -message 'Unable to Invoke-RestMethod against whois.arin.net' `
50 | -CustomMessage $($Error[0] | Format-List -Property * -Force) `
51 | -Folder $LogPath
52 | }
53 |
54 | try
55 | {
56 | $statusCode = Invoke-WebRequest $(($ipdata.net.orgRef.'#text')+'/pocs') | % {$_.StatusCode}
57 | }
58 | catch
59 | {
60 | Write-LogEntry -type ERROR `
61 | -message 'Unable to Invoke-WebRequest to get Status code of site' `
62 | -CustomMessage $($Error[0] | Format-List -Property * -Force) `
63 | -Folder $LogPath
64 | }
65 |
66 | $orgdata = Invoke-RestMethod -Uri $(($ipdata.net.orgRef.'#text')+'/pocs')
67 | #$parentnetref = Invoke-RestMethod -Uri $(($ipdata.net.parentNetRef.'#text')+'/org/pocs')
68 |
69 | # $parentpocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($parentnetref.pocs.pocLinkRef | ?{$_.description -eq 'Abuse'}).handle)
70 | # $parentpocdata
71 | $orgDataObject = @()
72 |
73 | foreach ($item in $orgdata.pocs.pocLinkRef)
74 | {
75 | $pocdata = @()
76 | $pocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($item.handle))#
77 |
78 | $props = @{
79 | Type = $item.Description
80 | Function = $item.Function
81 | Handle = $item.Handle
82 | URL = $item.'#text'
83 | POC = $pocdata.poc
84 | }
85 |
86 | $tempObject = New-Object -TypeName PSCustomObject -Property $props
87 | $orgDataObject += $tempObject
88 | }
89 |
90 | Add-ObjectDetail -InputObject $orgDataObject -TypeName PPRT.ARIN
91 |
92 |
93 |
94 | # $pocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($orgdata.pocs.pocLinkRef)) #| ?{$_.description -eq 'Abuse'}).handle)
95 | # $pocdata
96 | # If ($pocdata.poc.emails.InnerText -ne ""){return $pocdata.poc.emails.InnerText}
97 | # If ($parentpocdata.poc.emails.InnerText -ne ""){return $parentpocdata.poc.emails.InnerText}
98 | }
99 | End
100 | {
101 | # return "NO ABUSE POC ON RECORD"
102 | }
103 | }
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/Public/Connect-ARIN.ps1:
--------------------------------------------------------------------------------
1 | function Connect-ARIN (){
2 |
3 | param (
4 | [parameter(Mandatory=$true,Position=1,HelpMessage="Please provide a IP address")]
5 | $ipaddress,
6 |
7 | [Parameter(Mandatory = $true)]
8 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
9 | $LogPath
10 | )
11 | <#
12 | .SYNOPSIS
13 | Takes IP address as input and queries ARIN's WHOIS implementation for the IP addresses abuse contact email - RESTFul API
14 |
15 | .DESCRIPTION
16 | Takes a IP Address and searches for ARIN's WHOIS abuse contact email for that IP based on registration data
17 | Returns this contact email address
18 |
19 | .PARAMETER ipaddress
20 | Specifices the specific IP address belonging to ARIN
21 |
22 |
23 | .EXAMPLE
24 | C:\PS> Check-ARIN 146.42.65.82
25 |
26 | #>
27 | Begin
28 | {
29 | try
30 | {
31 | $TestingWebRequest = Invoke-WebRequest -Uri 'https://www.google.com' | Out-Null
32 | }
33 | catch
34 | {
35 | throw 'Unable to connect to google.com or Internet Explorer has not be used on this system.`
36 | Please correct this before proceeding.'
37 | break
38 | }
39 | }
40 | Process
41 | {
42 | try
43 | {
44 | $ipdata = Invoke-RestMethod -Uri "http://rdap.arin.net/bootstrap/ip/$ipaddress" -UseBasicParsing
45 | }
46 | catch
47 | {
48 | Write-LogEntry -type ERROR `
49 | -message 'Unable to Invoke-RestMethod against whois.arin.net' `
50 | -CustomMessage $($Error[0] | Format-List -Property * -Force) `
51 | -Folder $LogPath
52 | }
53 |
54 | try
55 | {
56 | $statusCode = Invoke-WebRequest $(($ipdata.net.orgRef.'#text')+'/pocs') | % {$_.StatusCode}
57 | }
58 | catch
59 | {
60 | Write-LogEntry -type ERROR `
61 | -message 'Unable to Invoke-WebRequest to get Status code of site' `
62 | -CustomMessage $($Error[0] | Format-List -Property * -Force) `
63 | -Folder $LogPath
64 | }
65 |
66 | $orgdata = Invoke-RestMethod -Uri $(($ipdata.net.orgRef.'#text')+'/pocs')
67 | #$parentnetref = Invoke-RestMethod -Uri $(($ipdata.net.parentNetRef.'#text')+'/org/pocs')
68 |
69 | # $parentpocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($parentnetref.pocs.pocLinkRef | ?{$_.description -eq 'Abuse'}).handle)
70 | # $parentpocdata
71 | $orgDataObject = @()
72 |
73 | foreach ($item in $orgdata.pocs.pocLinkRef)
74 | {
75 | $pocdata = @()
76 | $pocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($item.handle))#
77 |
78 | $props = @{
79 | Type = $item.Description
80 | Function = $item.Function
81 | Handle = $item.Handle
82 | URL = $item.'#text'
83 | POC = $pocdata.poc
84 | }
85 |
86 | $tempObject = New-Object -TypeName PSCustomObject -Property $props
87 | $orgDataObject += $tempObject
88 | }
89 |
90 | Add-ObjectDetail -InputObject $orgDataObject -TypeName PPRT.ARIN
91 |
92 |
93 |
94 | # $pocdata = Invoke-RestMethod -Uri ("http://whois.arin.net/rest/poc/"+$($orgdata.pocs.pocLinkRef)) #| ?{$_.description -eq 'Abuse'}).handle)
95 | # $pocdata
96 | # If ($pocdata.poc.emails.InnerText -ne ""){return $pocdata.poc.emails.InnerText}
97 | # If ($parentpocdata.poc.emails.InnerText -ne ""){return $parentpocdata.poc.emails.InnerText}
98 | }
99 | End
100 | {
101 | # return "NO ABUSE POC ON RECORD"
102 | }
103 | }
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/Public/New-AllReceivedFromIPObject.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 3
2 | <#
3 | .Synopsis
4 | Short description
5 | .DESCRIPTION
6 | Long description
7 | .EXAMPLE
8 | Example of how to use this cmdlet
9 | .EXAMPLE
10 | Another example of how to use this cmdlet
11 | #>
12 | function New-AllReceivedFromIPObject
13 | {
14 | [CmdletBinding()]
15 | Param
16 | (
17 | [Parameter(Mandatory = $true,
18 | ValueFromPipelineByPropertyName = $true,
19 | ParameterSetName = 'MessageObject')]
20 | [PSTypeName('PPRT.Message')]
21 | $MessageObject,
22 |
23 | [Parameter(Mandatory = $true,
24 | ValueFromPipelineByPropertyName = $true,
25 | ParameterSetName = 'EmailHeader')]
26 | $EmailHeader,
27 |
28 | [Parameter(Mandatory = $true,
29 | ValueFromPipelineByPropertyName = $true)]
30 | $SavePath,
31 |
32 | [Parameter(Mandatory = $false,
33 | ValueFromPipelineByPropertyName = $true)]
34 | [switch]$HeatMap
35 | )
36 |
37 | Begin
38 | {
39 | #regex is used for getting IPs from String
40 | $regex = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
41 |
42 | $polyline = @() #used for array of PolyLines
43 | $originalPolyline = @()
44 | $ReceivedFromIP = @()
45 | $ReturnObject = @()
46 | }
47 | Process
48 | {
49 |
50 | switch ($PSBoundParameters.Keys)
51 | {
52 | 'MessageObject'
53 | {
54 | $msg = $MessageObject.Headers
55 | }
56 | 'EmailHeader'
57 | {
58 | if($null -ne $EmailHeader)
59 | {
60 | $msg = $EmailHeader
61 | }
62 | else
63 | {
64 | Write-Warning -Message 'Please provide Email Headers'
65 | break
66 | }
67 | }
68 | }
69 |
70 | foreach ($item in $MessageObject)
71 | {
72 | $ReceivedFromIP = (Parse-EmailHeader -InputFileName $item.Headers).From |
73 | Select-String -Pattern $regex -AllMatches |
74 | ForEach-Object -Process {
75 | $_.Matches
76 | } |
77 | ForEach-Object -Process {
78 | $_.Value
79 | }
80 |
81 |
82 | foreach ($ip in $ReceivedFromIP)
83 | {
84 | $IpLocation = ''
85 | $IpLocation = Invoke-RestMethod -Uri "http://freegeoip.net/xml/$($ip)"
86 |
87 | if (($IpLocation.Response.Latitude -ne 0) -or ($IpLocation.Response.Longitude -ne 0))
88 | {
89 | if (![string]::IsNullOrWhiteSpace($IpLocation.Response.Latitude))
90 | {
91 | if (![string]::IsNullOrWhiteSpace($IpLocation.Response.Longitude))
92 | {
93 | $originalPolyline = "{lat: $($IpLocation.Response.Latitude), lng: $($IpLocation.Response.Longitude)}"
94 | $polyline += $originalPolyline
95 | }
96 | }
97 | }
98 | }
99 |
100 | $props = @{
101 | marker = "[$($polyline -join ',')]"
102 | subject = $item.Subject
103 | SentFromAddress = $item.SenderEmailAddress
104 | SentFromType = $item.SenderEmailType
105 | ReceivedTime = $item.ReceivedTime
106 | EmailBody = $item.Body
107 | }
108 |
109 | $tempAllIPObject = New-Object -TypeName PSObject -Property $props
110 | $AllIPObject += $tempAllIPObject
111 |
112 | $polyline = @()
113 | }
114 |
115 | $ReturnObject = $AllIPObject
116 | }
117 | End
118 | {
119 | return $ReturnObject
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/Public/Get-AbsoluteUri.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-AbsoluteUri
3 | {
4 | [CmdletBinding()]
5 | param (
6 | [parameter(Mandatory = $true,
7 | HelpMessage = 'Please provide a .MSG file.')]
8 | #[PSTypeName('PPRT.PhishingURL')]
9 | $URLObject,
10 |
11 | [Parameter(Mandatory = $true)]
12 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
13 | $LogPath
14 | )
15 | <#
16 | .SYNOPSIS
17 | This function will get the Absolute Uri for a given URLObject
18 |
19 | .DESCRIPTION
20 | This function checks and verifies that URL passed in is formed for the correct scheme
21 | We will get the response from contacting the website and return detailed information about
22 | the given URL.
23 |
24 | .PARAMETER URLObject
25 | A PPRT.PhishingURL Object Type that will checked and more detail returned.
26 |
27 | .PARAMETER LogPath
28 | This parameter is a folder path that you want to log to
29 |
30 | .EXAMPLE
31 | C:\PS> Get-AbsoluteUri -URLObject $URL -LogPath $LogPath
32 |
33 | #>
34 |
35 | $ReturnObject = @()
36 | $AbsoluteURL = @()
37 | $URLAuthority = @()
38 |
39 | Add-Type -AssemblyName System.Web
40 |
41 | $TempURL = $URLObject.URL
42 |
43 | if (($null -eq $TempURL.AbsoluteURI -and $TempURL.Scheme -match '[http|https]'))
44 | {
45 | $log = Write-LogEntry -type Error -message 'Get-AbsoluteUri: URL is not the correct scheme' -Folder $LogPath
46 | }
47 |
48 | $log = Write-LogEntry -type Info -message 'Get-AbsoluteUri: Creating WebRequest' -Folder $LogPath
49 |
50 |
51 | $encodedurl = [system.net.webrequest]::Create($($TempURL))
52 | $Response = $null
53 |
54 | try
55 | {
56 | $log = Write-LogEntry -type Info -message 'Get-AbsoluteUri: Getting Response' -Folder $LogPath
57 | $Response = $encodedurl.GetResponse()
58 |
59 | $AbsoluteURL = $Response.ResponseUri.AbsoluteUri
60 | $URLAuthority = $Response.ResponseUri.Authority
61 | }
62 | catch
63 | {
64 | $log = Write-LogEntry -type Error -message 'Get-AbsoluteUri: ERROR GETTING RESPONSE!!!' -Folder $LogPath -CustomMessage 'BREAK!'
65 | continue
66 | }
67 | finally
68 | {
69 | # Clear the response, otherwise the next HttpWebRequest may fail... (don't know why)
70 | if ($Response -ne $null)
71 | {
72 | $Response.Close()
73 | }
74 | }
75 |
76 | try
77 | {
78 | Import-Clixml -Path "$(Split-Path -Path $Script:MyInvocation.MyCommand.Path)\Private\shorturls.xml" | ForEach-Object -Process {
79 | if ($AbsoluteURL -like '$_')
80 | {
81 | $log = Write-LogEntry -type Info -message "Get-AbsoluteUri: URL matches a Short URL - $AbsoluteURL = $($_)" -Folder $LogPath
82 |
83 | #call Get-LongUrl to call API to resolve to the normal/long url
84 | $ExpandedURL = Add-ObjectDetail -InputObject $AbsoluteURL -TypeName PPRT.PhishingURL
85 |
86 | $log = Write-LogEntry -type Info -message 'Get-AbsoluteUri: Calling Get-AbsoluteUri Again' -Folder $LogPath
87 |
88 | $FinalURL = Get-AbsoluteUri $ExpandedURL
89 | }
90 | }
91 | }
92 | catch
93 | {
94 | $log = Write-LogEntry -type Error -message 'Get-AbsoluteUri: Unable to find shorturls.xml!' -Folder $LogPath
95 | }
96 |
97 | $props = @{
98 | OriginalURL = $URLObject
99 | EncodedURL = $($encodedurl)
100 | AbsoluteURL = $AbsoluteURL
101 | URLAuthority = $URLAuthority
102 | }
103 |
104 | $ReturnObject = New-Object -TypeName PSObject -Property $props
105 |
106 | $log = Write-LogEntry -type Info -message 'Get-AbsoluteUri: Completed Successfully!' -Folder $LogPath
107 |
108 | Add-ObjectDetail -InputObject $ReturnObject -TypeName PPRT.Uri
109 | }
110 |
--------------------------------------------------------------------------------
/Private/Create-PPRTDatabase.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Short description
4 | .DESCRIPTION
5 | Long description
6 | .EXAMPLE
7 | Example of how to use this cmdlet
8 | .EXAMPLE
9 | Another example of how to use this cmdlet
10 | #>
11 | function Create-PPRT2Database
12 | {
13 | [CmdletBinding()]
14 | Param
15 | (
16 | # Param1 help description
17 | [Parameter(Mandatory=$true,
18 | ValueFromPipelineByPropertyName=$true
19 | )]
20 | $Server,
21 |
22 | [Parameter(Mandatory=$true,
23 | ValueFromPipelineByPropertyName=$true
24 | )]
25 | $DatabaseLocation,
26 |
27 | [Parameter(Mandatory=$true,
28 | ValueFromPipelineByPropertyName=$true
29 | )]
30 | $LoggingLocation
31 | )
32 |
33 | Begin
34 | {
35 | $User = 'Administrator'
36 | $PWord = '!QAZ2wsx'
37 |
38 |
39 | $conn = New-Object System.Data.SqlClient.SqlConnection
40 | $conn.ConnectionString = "Data Source=172.20.1.117,1433;Network Library=DBMSSOCN;Initial Catalog=myDataBase;User ID=$($User);Password=$($PWord);"
41 | $conn.open()
42 |
43 | $CreatePPRT2Database = @"
44 | USE [master]
45 | GO
46 |
47 | /****** Object: Database [PPRT2] Script Date: 5/31/2016 8:29:38 PM ******/
48 | CREATE DATABASE [PPRT22]
49 | CONTAINMENT = NONE
50 | ON PRIMARY
51 | ( NAME = N'PPRT2', FILENAME = N'$($DatabaseLocation)\PPRT22.mdf' , SIZE = 4096KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
52 | LOG ON
53 | ( NAME = N'PPRT2_log', FILENAME = N'$($LoggingLocation)\PPRT22_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
54 | GO
55 |
56 | ALTER DATABASE [PPRT2] SET COMPATIBILITY_LEVEL = 120
57 | GO
58 |
59 | IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
60 | begin
61 | EXEC [PPRT2].[dbo].[sp_fulltext_database] @action = 'enable'
62 | end
63 | GO
64 |
65 | ALTER DATABASE [PPRT2] SET ANSI_NULL_DEFAULT OFF
66 | GO
67 |
68 | ALTER DATABASE [PPRT2] SET ANSI_NULLS OFF
69 | GO
70 |
71 | ALTER DATABASE [PPRT2] SET ANSI_PADDING OFF
72 | GO
73 |
74 | ALTER DATABASE [PPRT2] SET ANSI_WARNINGS OFF
75 | GO
76 |
77 | ALTER DATABASE [PPRT2] SET ARITHABORT OFF
78 | GO
79 |
80 | ALTER DATABASE [PPRT2] SET AUTO_CLOSE OFF
81 | GO
82 |
83 | ALTER DATABASE [PPRT2] SET AUTO_SHRINK OFF
84 | GO
85 |
86 | ALTER DATABASE [PPRT2] SET AUTO_UPDATE_STATISTICS ON
87 | GO
88 |
89 | ALTER DATABASE [PPRT2] SET CURSOR_CLOSE_ON_COMMIT OFF
90 | GO
91 |
92 | ALTER DATABASE [PPRT2] SET CURSOR_DEFAULT GLOBAL
93 | GO
94 |
95 | ALTER DATABASE [PPRT2] SET CONCAT_NULL_YIELDS_NULL OFF
96 | GO
97 |
98 | ALTER DATABASE [PPRT2] SET NUMERIC_ROUNDABORT OFF
99 | GO
100 |
101 | ALTER DATABASE [PPRT2] SET QUOTED_IDENTIFIER OFF
102 | GO
103 |
104 | ALTER DATABASE [PPRT2] SET RECURSIVE_TRIGGERS OFF
105 | GO
106 |
107 | ALTER DATABASE [PPRT2] SET DISABLE_BROKER
108 | GO
109 |
110 | ALTER DATABASE [PPRT2] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
111 | GO
112 |
113 | ALTER DATABASE [PPRT2] SET DATE_CORRELATION_OPTIMIZATION OFF
114 | GO
115 |
116 | ALTER DATABASE [PPRT2] SET TRUSTWORTHY OFF
117 | GO
118 |
119 | ALTER DATABASE [PPRT2] SET ALLOW_SNAPSHOT_ISOLATION OFF
120 | GO
121 |
122 | ALTER DATABASE [PPRT2] SET PARAMETERIZATION SIMPLE
123 | GO
124 |
125 | ALTER DATABASE [PPRT2] SET READ_COMMITTED_SNAPSHOT OFF
126 | GO
127 |
128 | ALTER DATABASE [PPRT2] SET HONOR_BROKER_PRIORITY OFF
129 | GO
130 |
131 | ALTER DATABASE [PPRT2] SET RECOVERY FULL
132 | GO
133 |
134 | ALTER DATABASE [PPRT2] SET MULTI_USER
135 | GO
136 |
137 | ALTER DATABASE [PPRT2] SET PAGE_VERIFY CHECKSUM
138 | GO
139 |
140 | ALTER DATABASE [PPRT2] SET DB_CHAINING OFF
141 | GO
142 |
143 | ALTER DATABASE [PPRT2] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )
144 | GO
145 |
146 | ALTER DATABASE [PPRT2] SET TARGET_RECOVERY_TIME = 0 SECONDS
147 | GO
148 |
149 | ALTER DATABASE [PPRT2] SET DELAYED_DURABILITY = DISABLED
150 | GO
151 |
152 | ALTER DATABASE [PPRT2] SET READ_WRITE
153 | GO
154 | "@
155 | }
156 | Process
157 | {
158 | $cmd = New-Object System.Data.SqlClient.SqlCommand
159 | $cmd.connection = $conn
160 | $cmd.Commandtext = "$CreatePPRT2Database"
161 | $command.ExecuteNonQuery()
162 | }
163 | End
164 | {
165 | $conn.close()
166 | }
167 | }
168 |
169 |
170 |
--------------------------------------------------------------------------------
/Public/New-PPRTAbuseContactObject.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | <#
3 | .Synopsis
4 | New-PPRTAbuseContactObject is a function to gather information about the abuse/registration POC
5 | .DESCRIPTION
6 | New-PPRTAbuseContactObject is a function to gather information about the abuse/registration POC.
7 | Additionally, this function will:
8 | Check to see if the URL is alive
9 | Get detailed URL information (AbsoluteUri)
10 | Get the IP Address of the host/URL
11 | Find out which WHOIS owns this IP
12 | Run against the owner/registrars RDAP/WHOIS API
13 | .EXAMPLE
14 | New-PPRTAbuseContactObject -URLObject $URLObject -LogPath $LogPath
15 | .EXAMPLE
16 | $URLObject | New-PPRTAbuseContactObject -LogPath $LogPath
17 | #>
18 | function New-PPRTAbuseContactObject
19 | {
20 | [CmdletBinding()]
21 | [OutputType([System.Collections.Hashtable],[String])]
22 | Param
23 | (
24 | [Parameter(Mandatory = $true,
25 | ValueFromPipeline = $true,
26 | ValueFromPipelineByPropertyName = $true)]
27 | # [PSTypeName('PPRT.PhishingURL')]
28 | $URLObject,
29 |
30 | [Parameter(Mandatory = $true)]
31 | [ValidateScript({ if (Test-Path $_){$true}else{ throw 'Please provide a valid path for LogPath' }})]
32 | $LogPath
33 | )
34 | Begin
35 | {
36 | $AllAttachments = @()
37 | $ReturnOjbect = @()
38 |
39 | $object = @{}
40 | }
41 | Process
42 | {
43 | foreach ($url in $URLObject)
44 | {
45 | $Body = @{}
46 |
47 | $Body.URL = $url
48 |
49 | $URLAlive = @()
50 |
51 | # try
52 | # {
53 |
54 | $log = Write-LogEntry -type Info -message "New-PPRTAbuseContactObject: Verifying that URL is alive - $($url)" -Folder $LogPath
55 |
56 | $log = Write-LogEntry -type Info -message 'New-PPRTAbuseContactObject: Getting AbsoluteUri' -Folder $LogPath
57 |
58 | $AbsoluteUri = Get-AbsoluteUri -URLObject $url -LogPath $LogPath
59 |
60 | if ($AbsoluteUri -eq $null)
61 | {
62 | $log = Write-LogEntry -type Error -message 'New-PPRTAbuseContactObject: AbsoluteUri is Null' -Folder $LogPath
63 | $AbsoluteUri = $null
64 | }
65 |
66 | $Body.AbsoluteUri = $AbsoluteUri
67 |
68 | $AbsoluteUri.URLAuthority
69 |
70 | [array]$ipaddress = Get-IPaddress -hostname $($AbsoluteUri.URLAuthority) -LogPath $LogPath
71 | if ($ipaddress -eq $null)
72 | {
73 | $log = Write-LogEntry -type Error -message 'New-PPRTAbuseContactObject: IPAddress is Null' -Folder $LogPath
74 | $ipaddress = $null
75 | }
76 |
77 | $Body.IPAddress = $ipaddress
78 |
79 | foreach ($ip in $ipaddress)
80 | {
81 | #based on the ipaddress we are going to get which WHOIS/RDAP to use
82 | $whoisdb = Get-WhichWHOIS -ipaddress $ip
83 |
84 | if ($whoisdb.WHOIS -eq $null )
85 | {
86 | $log = Write-LogEntry -type Error -message 'New-PPRTAbuseContactObject: WHOIS is Null' -Folder $LogPath
87 | $whoisdb = $null
88 | }
89 |
90 | $Body.WHOIS = $whoisdb
91 |
92 | #based on info from Get-WhichWHOIS we will then begin those specific API calls
93 | switch ($whoisdb){
94 | 'arin'
95 | {
96 | [array]$abusecontact = Check-ARIN $ip
97 | }
98 | 'ripe'
99 | {
100 | [array]$abusecontact = Check-RIPE $ip
101 | }
102 | 'apnic'
103 | {
104 | $abusecontact = Check-APNIC $ip
105 | }
106 | 'lacnic'
107 | {
108 | [array]$abusecontact = Check-LACNIC $ip
109 | }
110 | 'afrnic'
111 | {
112 | $abusecontact = 'NOCONTACT'
113 | }
114 | $null
115 | {
116 |
117 | }
118 | }
119 |
120 | $Body.AbuseContact = $abusecontact
121 | }
122 |
123 |
124 | Add-ObjectDetail -InputObject $Body -TypeName PPRT.AbuseContact
125 | }
126 | }
127 | End
128 | {
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Private/Create-PPRTDatabaseTables.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Short description
4 | .DESCRIPTION
5 | Long description
6 | .EXAMPLE
7 | Example of how to use this cmdlet
8 | .EXAMPLE
9 | Another example of how to use this cmdlet
10 | #>
11 | function Create-PPRTDatabaseTables
12 | {
13 | [CmdletBinding()]
14 | Param
15 | (
16 | # Param1 help description
17 | [Parameter(Mandatory=$true,
18 | ValueFromPipelineByPropertyName=$true
19 | )]
20 | $Server
21 | )
22 |
23 | Begin
24 | {
25 | [assembly.reflection]::loadwithpartialname('System.Data')
26 | $conn = New-Object System.Data.SqlClient.SqlConnection
27 | $conn.ConnectionString = "Server=$($Server);Database=PPRT;Trusted_Connection=True;"
28 | $conn.open()
29 | }
30 | Process
31 | {
32 |
33 | $email = @"
34 | USE [PPRT]
35 | GO
36 |
37 | /****** Object: Table [dbo].[Email] Script Date: 5/31/2016 8:31:16 PM ******/
38 | SET ANSI_NULLS ON
39 | GO
40 |
41 | SET QUOTED_IDENTIFIER ON
42 | GO
43 |
44 | CREATE TABLE [dbo].[Email](
45 | [ID] [int] NOT NULL,
46 | [FullName] [nvarchar](max) NULL,
47 | [Subject] [nvarchar](max) NULL,
48 | [PhishingURL] [int] NULL,
49 | [Body] [nvarchar](max) NULL,
50 | [HTMLBody] [nvarchar](max) NULL,
51 | [BCC] [nvarchar](max) NULL,
52 | [CC] [nvarchar](max) NULL,
53 | [ReceivedOnBehalfOfEntryID] [nvarchar](max) NULL,
54 | [ReceivedOnBehalfOfName] [nvarchar](max) NULL,
55 | [ReceivedTime] [nvarchar](max) NULL,
56 | [Receipents] [nvarchar](max) NULL,
57 | [ReplyRecipientsName] [nvarchar](max) NULL,
58 | [SenderName] [nvarchar](max) NULL,
59 | [SentOnDate] [nvarchar](max) NULL,
60 | [SentOnBehalfOfName] [nvarchar](max) NULL,
61 | [SentTo] [nvarchar](max) NULL,
62 | [SenderEmailAddress] [nvarchar](max) NULL,
63 | [SenderEmailType] [nvarchar](max) NULL,
64 | [SendUsingAccount] [nvarchar](max) NULL,
65 | [Headers] [nvarchar](max) NULL,
66 | [Attachments] [int] NULL,
67 | [DateProcessed] AS (getdate()),
68 | PRIMARY KEY CLUSTERED
69 | (
70 | [ID] ASC
71 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
72 | ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
73 |
74 | GO
75 |
76 | ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_Attachments] FOREIGN KEY([Attachments])
77 | REFERENCES [dbo].[Attachments] ([ID])
78 | GO
79 |
80 | ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_Attachments]
81 | GO
82 |
83 | ALTER TABLE [dbo].[Email] WITH CHECK ADD CONSTRAINT [FK_Email_PhishingURL] FOREIGN KEY([PhishingURL])
84 | REFERENCES [dbo].[PhishingURL] ([ID])
85 | GO
86 |
87 | ALTER TABLE [dbo].[Email] CHECK CONSTRAINT [FK_Email_PhishingURL]
88 | GO
89 |
90 | "@
91 |
92 | $Attachments = @"
93 | USE [PPRT]
94 | GO
95 |
96 | /****** Object: Table [dbo].[Attachments] Script Date: 5/31/2016 8:30:22 PM ******/
97 | SET ANSI_NULLS ON
98 | GO
99 |
100 | SET QUOTED_IDENTIFIER ON
101 | GO
102 |
103 | CREATE TABLE [dbo].[Attachments](
104 | [ID] [int] NOT NULL,
105 | [OriginalAttachmentName] [nvarchar](max) NULL,
106 | [NewAttachmentName] [nvarchar](max) NULL,
107 | [AttachmentSavePath] [nvarchar](max) NULL,
108 | [AttachmentHash] [nvarchar](max) NULL,
109 | [VirusTotalResults] [nvarchar](max) NULL,
110 | [ProcessedDate] AS (getdate()),
111 | PRIMARY KEY CLUSTERED
112 | (
113 | [ID] ASC
114 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
115 | ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
116 |
117 | GO
118 |
119 | "@
120 |
121 | $phishingURL = @"
122 | USE [PPRT]
123 | GO
124 |
125 | /****** Object: Table [dbo].[PhishingURL] Script Date: 5/31/2016 8:32:18 PM ******/
126 | SET ANSI_NULLS ON
127 | GO
128 |
129 | SET QUOTED_IDENTIFIER ON
130 | GO
131 |
132 | CREATE TABLE [dbo].[PhishingURL](
133 | [ID] [int] NOT NULL,
134 | [RawPhishingLink] [nvarchar](max) NULL,
135 | [PhishingLinkStatus] [bit] NULL,
136 | [ShortenedURL] [nvarchar](max) NULL,
137 | [ParsedURL] [nvarchar](max) NULL,
138 | [URLIPAddress] [nvarchar](max) NULL,
139 | [WHOIS] [nvarchar](50) NULL,
140 | [AbuseNotificationStatus] [bit] NULL,
141 | [AdditionalNotifications] [nvarchar](50) NULL,
142 | [DateProcessed] AS (getdate()),
143 | PRIMARY KEY CLUSTERED
144 | (
145 | [ID] ASC
146 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
147 | ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
148 |
149 | GO
150 |
151 | "@
152 |
153 |
154 | $cmd = New-Object System.Data.SqlClient.SqlCommand
155 | $cmd.connection = $conn
156 | $cmd.Commandtext = "$email"
157 | $command.ExecuteNonQuery()
158 |
159 | $cmd.Commandtext = "$Attachments"
160 | $command.ExecuteNonQuery()
161 |
162 | $cmd.Commandtext = "$phishingURL"
163 | $command.ExecuteNonQuery()
164 | }
165 | End
166 | {
167 | $conn.close()
168 | }
169 | }
170 |
171 |
172 |
--------------------------------------------------------------------------------
/Public/Invoke-VTAttachment.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2 -Modules Posh-VirusTotal
2 | <#
3 | .Synopsis
4 | Short description
5 | .DESCRIPTION
6 | Long description
7 | .EXAMPLE
8 | Example of how to use this cmdlet
9 | .EXAMPLE
10 | Another example of how to use this cmdlet
11 | #>
12 | function Invoke-VTAttachment
13 | {
14 | [CmdletBinding()]
15 | Param
16 | (
17 | [Parameter(Mandatory = $true,
18 | ValueFromPipelineByPropertyName = $true,
19 | Helpmessage = 'Please provide a message file')]
20 | [PSTypeName('PPRT.Attachment')]
21 | $AttachmentHash,
22 |
23 | [parameter(Mandatory = $true,
24 | ValueFromPipelineByPropertyName = $true,
25 | HelpMessage = 'Please provide your Virus Total API Key')]
26 | $VTAPIKey,
27 |
28 | [Parameter(Mandatory = $true)]
29 | $LogPath
30 | )
31 |
32 | Begin
33 | {
34 | $ReturnObject = @()
35 |
36 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: Checking to see if Posh-VirusTotal is installed' -Folder $LogPath
37 |
38 | #download and import POSH-VirusTotal
39 | if (!(Test-Path -Path "$Home\Documents\WindowsPowerShell\Modules\Posh-VirusTotal"))
40 | {
41 | $log = Write-LogEntry -type Error -message 'Invoke-VTAttachment: Unable to find Posh-VirusTotal' -Folder $LogPath
42 |
43 | $result = [System.Windows.Forms.MessageBox]::Show('You must have the Posh-VirusTotal PowerShell Module installed. Do you want to download Posh-VirusTotal now?', 'Warning', 'YesNo', 'Warning')
44 | if ($result -eq 'Yes')
45 | {
46 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: Begin Downloading of Posh-VirusTotal' -Folder $LogPath
47 |
48 | Invoke-Expression -Command (New-Object -TypeName Net.WebClient).DownloadString('https://gist.githubusercontent.com/darkoperator/9138373/raw/22fb97c07a21139a398c2a3d6ca7e3e710e476bc/PoshVTInstall.ps1')
49 | }
50 | else
51 | {
52 | $log = Write-LogEntry -type Error -message 'Invoke-VTAttachment: You must have Posh-VirusTotal installed before continuing' -Folder $LogPath -CustomMessage 'Break'
53 | break
54 | }
55 | }
56 | }
57 | Process
58 | {
59 | foreach ($hash in $AttachmentHash.Hash)
60 | {
61 | $log = Write-LogEntry -type Info -message "Invoke-VTAttachment: Getting VirusTotal File Report for $hash" -Folder $LogPath
62 |
63 | $VTFileReport = @()
64 | $VTFileReport = Get-VTFileReport -Resource $hash -APIKey $VTAPIKey
65 |
66 | if ($VTFileReport.ResponseCode -eq 1)
67 | {
68 | $result = [System.Windows.Forms.MessageBox]::Show("The following SHA256 hash was already been submitted to VirusTotal.`n $hash", 'Warning', 'Ok', 'Warning')
69 |
70 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: VirusTotal Submission' -Folder $LogPath -CustomMessage "Hash has been previously submitted to VirusTotal: $hash"
71 |
72 | $SubmissionStatus = 'Previously Submitted'
73 |
74 | $props = {
75 | AttachmentHash = $hash
76 | SubmissionStatus = $SubmissionStatus
77 | VTFileReport = $VTFileReport
78 | VTSubmissionResult = $null
79 | }
80 |
81 | $VTObject = New-Object -TypeName PSObject -Property $props
82 |
83 | Add-ObjectDetail -InputObject $VTObject -TypeName PPRT.VTResults
84 | }
85 | if ($VTFileReport.ResponseCode -eq 0)
86 | {
87 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: VirusTotal Submission' -Folder $LogPath -CustomMessage "Hash has NOT been previously submitted to VirusTotal: $hash"
88 |
89 | $result = [System.Windows.Forms.MessageBox]::Show("The following SHA256 hash has NOT been submitted to VirusTotal. Do you want to upload this file to VirusTotal Now?`n $hash", 'Warning', 'YesNo', 'Warning')
90 |
91 | if ($result -eq $true)
92 | {
93 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: Submitting File to VirusTotal' -Folder $LogPath
94 |
95 | $SubmitToVT = Submit-VTFile -File $AttachmentHash.Path -APIKey $VTAPIKey
96 |
97 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: File Submitted Successfully' -Folder $LogPath
98 |
99 | $log = Write-LogEntry -type Info -message 'Invoke-VTAttachment: Getting VirusTotal File Report' -Folder $LogPath
100 |
101 | $VTFileReport = Get-VTFileReport -Resource $AttachmentHash.Path -APIKey $VTAPIKey
102 | $SubmissionStatus = 'Hash Submitted'
103 | }
104 | else
105 | {
106 | $log = Write-LogEntry -type Error -message "Invoke-VTAttachment: Hash not Found or Submitted - $hash" -Folder $LogPath
107 | $SubmissionStatus = 'Hash not Found or Submitted'
108 | }
109 |
110 | $props = {
111 | AttachmentHash = $hash
112 | SubmissionStatus = $SubmissionStatus
113 | VTFileReport = $VTFileReport
114 | VTSubmissionResult = $SubmitToVT
115 | }
116 |
117 | $VTObject = New-Object -TypeName PSObject -Property $props
118 |
119 | Add-ObjectDetail -InputObject $VTObject -TypeName PPRT.VTResults
120 | }
121 | }
122 | }
123 | End
124 | {
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/Public/Send-PPRTNotification.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | <#
3 | .Synopsis
4 | Short description
5 | .DESCRIPTION
6 | Long description
7 | .EXAMPLE
8 | Example of how to use this cmdlet
9 | .EXAMPLE
10 | Another example of how to use this cmdlet
11 | #>
12 | function Send-PPRTNotification
13 | {
14 | [CmdletBinding(DefaultParameterSetName = 'Full')]
15 | [OutputType([System.Collections.Hashtable],[String])]
16 | Param
17 | (
18 | #[PSTypeName('PPRT.Message')]
19 | [Parameter(Mandatory = $true,
20 | ValueFromPipeline = $true)]
21 | $To,
22 |
23 | [Parameter(Mandatory = $true,
24 | ValueFromPipeline = $true)]
25 | $Attachment,
26 |
27 | [Parameter(ParameterSetName = 'Single',
28 | Mandatory = $true,
29 | ValueFromPipelineByPropertyName = $true)]
30 | [string]$From,
31 |
32 | [Parameter(ParameterSetName = 'Single',
33 | Mandatory = $false,
34 | ValueFromPipelineByPropertyName = $true)]
35 | [string]$CC,
36 |
37 | [Parameter(ParameterSetName = 'Single',
38 | Mandatory = $false,
39 | ValueFromPipelineByPropertyName = $true)]
40 | [string]$BCC,
41 |
42 | [Parameter(ParameterSetName = 'Single',
43 | Mandatory = $false,
44 | ValueFromPipelineByPropertyName = $true)]
45 | [string]$Subject,
46 |
47 | [Parameter(ParameterSetName = 'Single',
48 | Mandatory = $true,
49 | ValueFromPipelineByPropertyName = $true)]
50 | $Body,
51 |
52 | [Parameter(ParameterSetName = 'Single',
53 | Mandatory = $false,
54 | ValueFromPipelineByPropertyName = $true)]
55 | [switch]$HTMLBody,
56 |
57 | [Parameter(ParameterSetName = 'Single',
58 | Mandatory = $false,
59 | ValueFromPipelineByPropertyName = $true)]
60 | [switch]$IncludeAttachment,
61 |
62 |
63 | [ValidateSet('Normal','High','Low')]
64 | [Parameter(ParameterSetName = 'Single',
65 | Mandatory = $false,
66 | ValueFromPipelineByPropertyName = $true)]
67 | [string]$Priority = 'Normal',
68 |
69 | [Parameter(ParameterSetName = 'Single',
70 | Mandatory = $false,
71 | ValueFromPipelineByPropertyName = $true)]
72 | [switch]$UseSSL,
73 |
74 |
75 | [ValidateSet('ASCII','UTF8','UTF7','UTF32','Unicode','BigEndianUnicode','Default','OEM')]
76 | [Parameter(ParameterSetName = 'Single',
77 | Mandatory = $false,
78 | ValueFromPipelineByPropertyName = $true)]
79 | [string]$Encoding,
80 |
81 | [Parameter(ParameterSetName = 'Single',
82 | Mandatory = $true,
83 | ValueFromPipelineByPropertyName = $true)]
84 | [System.Management.Automation.PSCredential]$Credential,
85 |
86 | [Parameter(ParameterSetName = 'Single',
87 | Mandatory = $true,
88 | ValueFromPipelineByPropertyName = $true)]
89 | [Alias('PSEmailServer')]
90 | [string]$SMTPServer = $PSEmailServer,
91 |
92 | [Parameter(ParameterSetName = 'Single',
93 | Mandatory = $true,
94 | ValueFromPipelineByPropertyName = $true)]
95 | [int]$SMTPPort = '25'
96 | )
97 | Begin
98 | {
99 | if ($null -eq $SMTPServer)
100 | {
101 | if ($null -eq $PSEmailServer)
102 | {
103 | Write-Error -Message 'Your $PSEmailServer variable is null. You must either set this variable or provide a SMTP Server address.'
104 | Write-Error -Message 'Exiting.....'
105 | return
106 | }
107 | }
108 | }
109 | Process
110 | {
111 | foreach ($msg in $MessageObject)
112 | {
113 | $Obj = @{}
114 |
115 | Add-Member -InputObject $Obj -MemberType NoteProperty -Name To -Value $(($AbuseContactObject.AbuseContact) -join ';') -Force
116 |
117 | if ($IncludeAttachment)
118 | {
119 | $Attachment = $msg.FullName
120 |
121 | Add-Member -InputObject $Obj -MemberType NoteProperty -Name Attachments -Value $Attachment -Force
122 | }
123 |
124 | switch ($psboundparameters.keys)
125 | {
126 | 'From'
127 | {
128 | $Obj.From = $From
129 | }
130 | 'Body'
131 | {
132 | $Obj.Body = $Body
133 | }
134 | 'HTMLBody'
135 | {
136 | $Obj.HTMLBody = $BodyAsHtml
137 | }
138 | 'BCC'
139 | {
140 | $Obj.BCC = $BCC
141 | }
142 | 'CC'
143 | {
144 | $Obj.CC = $CC
145 | }
146 | 'Subject'
147 | {
148 | $Obj.Subject = $Subject
149 | }
150 | 'Priority'
151 | {
152 | $Obj.Priority = $Priority
153 | }
154 | 'UseSSL'
155 | {
156 | $Obj.UseSSL = $UseSSL
157 | }
158 | 'Encoding'
159 | {
160 | $Obj.Encoding = $Encoding
161 | }
162 | 'Credential'
163 | {
164 | $Obj.Credential = $Credential
165 | }
166 | 'SMTPServer'
167 | {
168 | $Obj.SMTPServer = $SMTPServer
169 | }
170 | 'SMTPPort'
171 | {
172 | $Obj.SMTPPort = $SMTPPort
173 | }
174 | 'URL'
175 | {
176 | $Obj.URL = $AbuseContactObject.URL
177 | }
178 | }
179 |
180 | Send-MailMessage @Obj
181 | }
182 | }
183 | End
184 | {
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/Private/Add-ObjectDetail.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Add-ObjectDetail
3 | {
4 | <#
5 | .SYNOPSIS
6 | Decorate an object with
7 | - A TypeName
8 | - New properties
9 | - Default parameters
10 |
11 | .DESCRIPTION
12 | Helper function to decorate an object with
13 | - A TypeName
14 | - New properties
15 | - Default parameters
16 |
17 | .PARAMETER InputObject
18 | Object to decorate. Accepts pipeline input.
19 |
20 | .PARAMETER TypeName
21 | Typename to insert.
22 |
23 | This will show up when you use Get-Member against the resulting object.
24 |
25 | .PARAMETER PropertyToAdd
26 | Add these noteproperties.
27 |
28 | Format is a hashtable with Key (Property Name) = Value (Property Value).
29 |
30 | Example to add a One and Date property:
31 |
32 | -PropertyToAdd @{
33 | One = 1
34 | Date = (Get-Date)
35 | }
36 |
37 | .PARAMETER DefaultProperties
38 | Change the default properties that show up
39 |
40 | .PARAMETER Passthru
41 | Whether to pass the resulting object on. Defaults to true
42 |
43 | .EXAMPLE
44 | #
45 | # Create an object to work with
46 | $Object = [PSCustomObject]@{
47 | First = 'Cookie'
48 | Last = 'Monster'
49 | Account = 'CMonster'
50 | }
51 |
52 | #Add a type name and a random property
53 | Add-ObjectDetail -InputObject $Object -TypeName 'ApplicationX.Account' -PropertyToAdd @{ AnotherProperty = 5 }
54 |
55 | # First Last Account AnotherProperty
56 | # ----- ---- ------- ---------------
57 | # Cookie Monster CMonster 5
58 |
59 | #Verify that get-member shows us the right type
60 | $Object | Get-Member
61 |
62 | # TypeName: ApplicationX.Account ...
63 |
64 | .EXAMPLE
65 | #
66 | # Create an object to work with
67 | $Object = [PSCustomObject]@{
68 | First = 'Cookie'
69 | Last = 'Monster'
70 | Account = 'CMonster'
71 | }
72 |
73 | #Add a random property, set a default property set so we only see two props by default
74 | Add-ObjectDetail -InputObject $Object -PropertyToAdd @{ AnotherProperty = 5 } -DefaultProperties Account, AnotherProperty
75 |
76 | # Account AnotherProperty
77 | # ------- ---------------
78 | # CMonster 5
79 |
80 | #Verify that the other properties are around
81 | $Object | Select -Property *
82 |
83 | # First Last Account AnotherProperty
84 | # ----- ---- ------- ---------------
85 | # Cookie Monster CMonster 5
86 |
87 | .NOTES
88 | This breaks the 'do one thing' rule from certain perspectives...
89 | The goal is to decorate an object all in one shot
90 |
91 | This abstraction simplifies decorating an object, with a slight trade-off in performance. For example:
92 |
93 | 10,000 objects, add a property and typename:
94 | Add-ObjectDetail: ~4.6 seconds
95 | Add-Member + PSObject.TypeNames.Insert: ~3 seconds
96 |
97 | Initial code borrowed from Shay Levy:
98 | http://blogs.microsoft.co.il/scriptfanatic/2012/04/13/custom-objects-default-display-in-powershell-30/
99 |
100 | .LINK
101 | http://ramblingcookiemonster.github.io/Decorating-Objects/
102 |
103 | .FUNCTIONALITY
104 | PowerShell Language
105 | #>
106 | [CmdletBinding()]
107 | param(
108 | [Parameter( Mandatory = $true,
109 | Position = 0,
110 | ValueFromPipeline = $true )]
111 | [ValidateNotNullOrEmpty()]
112 | [psobject[]]$InputObject,
113 |
114 | [Parameter( Mandatory = $false,
115 | Position = 1)]
116 | [string]$TypeName,
117 |
118 | [Parameter( Mandatory = $false,
119 | Position = 2)]
120 | [System.Collections.Hashtable]$PropertyToAdd,
121 |
122 | [Parameter( Mandatory = $false,
123 | Position = 3)]
124 | [ValidateNotNullOrEmpty()]
125 | [Alias('dp')]
126 | [System.String[]]$DefaultProperties,
127 |
128 | [boolean]$Passthru = $true
129 | )
130 |
131 | Begin
132 | {
133 | if($PSBoundParameters.ContainsKey('DefaultProperties'))
134 | {
135 | # define a subset of properties
136 | $ddps = New-Object -TypeName System.Management.Automation.PSPropertySet -ArgumentList DefaultDisplayPropertySet, $DefaultProperties
137 | $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]$ddps
138 | }
139 | }
140 | Process
141 | {
142 | foreach($Object in $InputObject)
143 | {
144 | switch ($PSBoundParameters.Keys)
145 | {
146 | 'PropertyToAdd'
147 | {
148 | foreach($Key in $PropertyToAdd.Keys)
149 | {
150 | #Add some noteproperties. Slightly faster than Add-Member.
151 | $Object.PSObject.Properties.Add( ( New-Object -TypeName System.Management.Automation.PSNoteProperty -ArgumentList ($Key, $PropertyToAdd[$Key]) ) )
152 | }
153 | }
154 | 'TypeName'
155 | {
156 | #Add specified type
157 | [void]$Object.PSObject.TypeNames.Insert(0,$TypeName)
158 | }
159 | 'DefaultProperties'
160 | {
161 | # Attach default display property set
162 | Add-Member -InputObject $Object -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers
163 | }
164 | }
165 | if($Passthru)
166 | {
167 | $Object
168 | }
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/Public/Get-PhishingGeoLocationHeatMap.ps1:
--------------------------------------------------------------------------------
1 | #requires -Version 2
2 | function Get-PhishingGeoLocationHeatMap
3 | {
4 | [CmdletBinding()]
5 | Param
6 | (
7 | # Param1 help description
8 | [Parameter(Mandatory = $true)]
9 | [ValidateNotNull()]
10 | [ValidateNotNullOrEmpty()]
11 | $HeatMapData,
12 | [parameter(HelpMessage = 'Please provide a folder path for ouputting generated maps')]
13 | [ValidateNotNullOrEmpty()]
14 | [string]$FolderPath
15 | )
16 |
17 | $OutHeatMap = "$FolderPath\PPRT_HeatMap.html"
18 |
19 | $webdata = @"
20 |
21 |
22 |
23 | Complex icons
24 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
265 |
267 |
268 |