Merge pull request #87 from rvrsh3ll/master

Threading Updates
1.6
HarmJ0y 2015-11-08 20:37:41 -05:00
commit c68177cff7
2 changed files with 319 additions and 125 deletions

View File

@ -1,10 +1,130 @@
function Find-Fruit
function Invoke-ThreadedFunction
{
[CmdletBinding()]
param (
[Parameter(Position = 0, Mandatory = $True)]
[String[]]$ComputerName,
[Parameter(Position = 1, Mandatory = $True)]
[System.Management.Automation.ScriptBlock]$ScriptBlock,
[Parameter(Position = 2)]
[Hashtable]$ScriptParameters,
[Int]$Threads = 20,
[Int]$Timeout = 100
)
begin
{
if ($PSBoundParameters['Debug'])
{
$DebugPreference = 'Continue'
}
Write-Verbose "[*] Total number of hosts: $($ComputerName.count)"
# Adapted from:
# http://powershell.org/wp/forums/topic/invpke-parallel-need-help-to-clone-the-current-runspace/
$SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$SessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
# threading adapted from
# https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1#L407
# Thanks Carlos!
# create a pool of maxThread runspaces
$Pool = [runspacefactory]::CreateRunspacePool(1, $Threads, $SessionState, $Host)
$Pool.Open()
$Jobs = @()
$PS = @()
$Wait = @()
$Counter = 0
}
process
{
ForEach ($Computer in $ComputerName)
{
# make sure we get a server name
if ($Computer -ne '')
{
While ($($Pool.GetAvailableRunspaces()) -le 0)
{
Start-Sleep -MilliSeconds $Timeout
}
# create a "powershell pipeline runner"
$PS += [powershell]::create()
$PS[$Counter].runspacepool = $Pool
# add the script block + arguments
$Null = $PS[$Counter].AddScript($ScriptBlock).AddParameter('ComputerName', $Computer)
if ($ScriptParameters)
{
ForEach ($Param in $ScriptParameters.GetEnumerator())
{
$Null = $PS[$Counter].AddParameter($Param.Name, $Param.Value)
}
}
# start job
$Jobs += $PS[$Counter].BeginInvoke();
# store wait handles for WaitForAll call
$Wait += $Jobs[$Counter].AsyncWaitHandle
}
$Counter = $Counter + 1
}
}
end
{
Write-Verbose "Waiting for scanning threads to finish..."
$WaitTimeout = Get-Date
# set a 60 second timeout for the scanning threads
while ($($Jobs | Where-Object { $_.IsCompleted -eq $False }).count -gt 0 -or $($($(Get-Date) - $WaitTimeout).totalSeconds) -gt 60)
{
Start-Sleep -MilliSeconds $Timeout
}
# end async call
for ($y = 0; $y -lt $Counter; $y++)
{
try
{
# complete async job
$PS[$y].EndInvoke($Jobs[$y])
}
catch
{
Write-Warning "error: $_"
}
finally
{
$PS[$y].Dispose()
}
}
$Pool.Dispose()
Write-Verbose "All threads completed!"
}
}
function Find-Fruit
{
<#
.SYNOPSIS
Search for "low hanging fruit".
.DESCRIPTION
A script to find potentially easily exploitable web servers on a target network.
@ -23,12 +143,24 @@ Path to custom dictionary.
.PARAMETER Timeout
Set timeout for each connection.
Timeout for each connection in milliseconds.
.PARAMETER UseSSL
Use an SSL connection.
.PARAMETER Threads
The maximum concurrent threads to execute..
.PARAMETER NoPing
Disable Ping Check
.PARAMETER FoundOnly
Only display found URI's
.EXAMPLE
C:\PS> Find-Fruit -Rhosts 192.168.1.0/24 -Port 8080 -Timeout 50
@ -41,164 +173,221 @@ HTTP Status Codes: 100 - Informational * 200 - Success * 300 - Redirection * 400
#>
[CmdletBinding()]
[CmdletBinding()] Param(
[Parameter(Mandatory = $True)]
[String]
$Rhosts,
[Int]
$Port,
[String]
$Path,
[Int]
$Timeout = "50",
[Switch]
$UseSSL
)
$hostList = New-Object System.Collections.ArrayList
[String] $iHosts = $Rhosts.Split(",")
foreach($iHost in $iHosts)
param (
[Parameter(Mandatory = $True)]
[String]$Rhosts,
[Int]$Port,
[String]$Path,
[Int]$Timeout = "110",
[Switch]$UseSSL,
[ValidateRange(1, 100)]
[Int]$Threads,
[Switch]$NoPing,
[Switch]$FoundOnly
)
begin
{
$hostList = New-Object System.Collections.ArrayList
$iHosts = $Rhosts -split ","
foreach ($iHost in $iHosts)
{
$iHost = $iHost.Replace(" ", "")
if(!$iHost)
if (!$iHost)
{
continue
}
if($iHost.contains("/"))
if ($iHost.contains("/"))
{
$netPart = $iHost.split("/")[0]
[uint32]$maskPart = $iHost.split("/")[1]
$address = [System.Net.IPAddress]::Parse($netPart)
if ($maskPart -ge $address.GetAddressBytes().Length * 8)
{
throw "Bad host mask"
}
$numhosts = [System.math]::Pow(2,(($address.GetAddressBytes().Length *8) - $maskPart))
$numhosts = [System.math]::Pow(2, (($address.GetAddressBytes().Length * 8) - $maskPart))
$startaddress = $address.GetAddressBytes()
[array]::Reverse($startaddress)
$startaddress = [System.BitConverter]::ToUInt32($startaddress, 0)
[uint32]$startMask = ([System.math]::Pow(2, $maskPart)-1) * ([System.Math]::Pow(2,(32 - $maskPart)))
[uint32]$startMask = ([System.math]::Pow(2, $maskPart) - 1) * ([System.Math]::Pow(2, (32 - $maskPart)))
$startAddress = $startAddress -band $startMask
#in powershell 2.0 there are 4 0 bytes padded, so the [0..3] is necessary
$startAddress = [System.BitConverter]::GetBytes($startaddress)[0..3]
[array]::Reverse($startaddress)
$address = [System.Net.IPAddress] [byte[]] $startAddress
$hostList.Add($address.IPAddressToString)
for ($i=0; $i -lt $numhosts-1; $i++)
$address = [System.Net.IPAddress][byte[]]$startAddress
$Null = $hostList.Add($address.IPAddressToString)
for ($i = 0; $i -lt $numhosts - 1; $i++)
{
$nextAddress = $address.GetAddressBytes()
$nextAddress = $address.GetAddressBytes()
[array]::Reverse($nextAddress)
$nextAddress = [System.BitConverter]::ToUInt32($nextAddress, 0)
$nextAddress ++
$nextAddress = [System.BitConverter]::ToUInt32($nextAddress, 0)
$nextAddress++
$nextAddress = [System.BitConverter]::GetBytes($nextAddress)[0..3]
[array]::Reverse($nextAddress)
$address = [System.Net.IPAddress] [byte[]] $nextAddress
$hostList.Add($address.IPAddressToString)|Out-Null
$address = [System.Net.IPAddress][byte[]]$nextAddress
$Null = $hostList.Add($address.IPAddressToString)
}
}
else
{
$Null = $hostList.Add($iHost)
}
}
$HostEnumBlock = {
param($ComputerName, $UseSSL, $Port, $Path, $Timeout, $FoundOnly)
if ($UseSSL -and $Port -eq 0)
{
# Default to 443 if SSL is specified but no port is specified
$Port = 443
}
elseif ($Port -eq 0)
{
# Default to port 80 if no port is specified
$Port = 80
}
if ($UseSSL)
{
$SSL = 's'
# Ignore invalid SSL certificates
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $True }
}
else
{
$SSL = ''
}
if (($Port -eq 80) -or ($Port -eq 443))
{
$PortNum = ''
}
else
{
$PortNum = ":$Port"
}
if ($Path)
{
if (!(Test-Path -Path $Path)) { Throw "File doesnt exist" }
$VulnLinks = @()
foreach ($Link in Get-Content $Path)
{
$VulnLinks = $VulnLinks + $Link
}
}
else
{
$hostList.Add($iHost)
$VulnLinks = @()
$VulnLinks = $VulnLinks + "jmx-console/" # Jboss
$VulnLinks = $VulnLinks + "web-console/ServerInfo.jsp" # Jboss
$VulnLinks = $VulnLinks + "invoker/JMXInvokerServlet" # Jboss
$VulnLinks = $VulnLinks + "lc/system/console" # Adobe LiveCycle OSGi console
$VulnLinks = $VulnLinks + "axis2/axis2-admin/" # Apache Axis2
$VulnLinks = $VulnLinks + "manager/html/" # Tomcat
$VulnLinks = $VulnLinks + "tomcat/manager/html/" # Tomcat
$VulnLinks = $VulnLinks + "wp-admin" # Wordpress
$VulnLinks = $VulnLinks + "workorder/FileDownload.jsp" #Manage Engine
$VulnLinks = $VulnLinks + "ibm/console/logon.jsp?action=OK" # WebSphere
$VulnLinks = $VulnLinks + "data/login" # Dell iDrac
$Vulnlinks = $Vulnlinks + "CFIDE/administrator/index.cfm" #ColdFusion
}
}
# Check Http status for each entry in the ditionary file
foreach ($Target in $ComputerName)
{
foreach ($Item in $Vulnlinks)
{
$WebTarget = "http$($SSL)://$($Target)$($PortNum)/$($Item)"
$URI = New-Object Uri($WebTarget)
try
{
$WebRequest = [System.Net.WebRequest]::Create($URI)
$WebResponse = $WebRequest.Timeout = $Timeout
$WebResponse = $WebRequest.GetResponse()
$WebStatus = $WebResponse.StatusCode
$ResultObject += $ScanObject
$WebResponse.Close()
}
catch
{
$WebStatus = $Error[0].Exception.InnerException.Response.StatusCode
if ($WebStatus -eq $null)
{
# Not every exception returns a StatusCode.
# If that is the case, return the Status.
$WebStatus = $Error[0].Exception.InnerException.Status
}
}
if ($UseSSL -and $Port -eq 0) {
# Default to 443 if SSL is specified but no port is specified
$Port = 443
} elseif ($Port -eq 0) {
# Default to port 80 if no port is specified
$Port = 80
$Result = @{
Status = $WebStatus;
URL = $WebTarget
}
if ($FoundOnly) {
New-Object -TypeName PSObject -Property $Result | Where-Object {$_.Status -eq 'OK'}
} else {
New-Object -TypeName PSObject -Property $Result
}
}
}
}
}
process {
if(-not $NoPing -and ($hostList.count -ne 1)) {
# ping all hosts in parallel
$Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
$hostList = Invoke-ThreadedFunction -ComputerName $hostList -ScriptBlock $Ping -Threads 100
}
if ($UseSSL) {
$SSL = 's'
# Ignore invalid SSL certificates
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $True }
} else {
$SSL = ''
}
if (($Port -eq 80) -or ($Port -eq 443)) {
$PortNum = ''
} else {
$PortNum = ":$Port"
}
if($Threads) {
Write-Verbose "Using threading with threads = $Threads"
if ($Path)
{
if (!(Test-Path -Path $Path)) { Throw "File doesnt exist" }
$VulnLinks = @()
foreach ($Link in Get-Content $Path) {
$VulnLinks = $VulnLinks + $Link
}
} else {
$VulnLinks = @()
$VulnLinks = $VulnLinks + "jmx-console/" # Jboss
$VulnLinks = $VulnLinks + "web-console/ServerInfo.jsp" # Jboss
$VulnLinks = $VulnLinks + "invoker/JMXInvokerServlet" # Jboss
$VulnLinks = $VulnLinks + "lc/system/console" # Adobe LiveCycle OSGi console
$VulnLinks = $VulnLinks + "axis2/axis2-admin/" # Apache Axis2
$VulnLinks = $VulnLinks + "manager/html/" # Tomcat
$VulnLinks = $VulnLinks + "tomcat/manager/html/" # Tomcat
$VulnLinks = $VulnLinks + "wp-admin" # Wordpress
$VulnLinks = $VulnLinks + "workorder/FileDownload.jsp" #Manage Engine
$VulnLinks = $VulnLinks + "ibm/console/logon.jsp?action=OK" # WebSphere
$VulnLinks = $VulnLinks + "data/login" # Dell iDrac
}
# if we're using threading, kick off the script block with Invoke-ThreadedFunction
$ScriptParams = @{
'UseSSL' = $UseSSL
'Port' = $Port
'Path' = $Path
'Timeout' = $Timeout
'FoundOnly' = $FoundOnly
}
# Check Http status for each entry in the ditionary file
foreach ($Target in $hostList)
{
$TcpConnection = New-Object System.Net.Sockets.TcpClient
Write-Verbose "Path Test Succeeded - Testing Connectivity"
# kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $hostList -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
}
foreach ($Item in $Vulnlinks) {
$WebTarget = "http$($SSL)://$($Target)$($PortNum)/$($Item)"
$URI = New-Object Uri($WebTarget)
try {
$WebRequest = [System.Net.WebRequest]::Create($URI)
$WebResponse = $WebRequest.Timeout=$Timeout
$WebResponse = $WebRequest.GetResponse()
$WebStatus = $WebResponse.StatusCode
$ResultObject += $ScanObject
$WebResponse.Close()
} catch {
$WebStatus = $Error[0].Exception.InnerException.Response.StatusCode
if ($WebStatus -eq $null) {
# Not every exception returns a StatusCode.
# If that is the case, return the Status.
$WebStatus = $Error[0].Exception.InnerException.Status
}
}
$Result = @{ Status = $WebStatus;
URL = $WebTarget}
$ScanObject = New-Object -TypeName PSObject -Property $Result
Write-Output $ScanObject
else {
Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $HostList, $UseSSL, $Port, $Path, $Timeout, $FoundOnly
}
}
}

View File

@ -65,6 +65,11 @@ class Module:
'Description' : 'Switch. Show all results (default is to only show 200s).',
'Required' : False,
'Value' : ''
},
'FoundOnly' : {
'Description' : 'Switch. Show only found sites',
'Required' : False,
'Value' : ''
}
}