From d66c51125204af790802dc4c29dad4dbda322031 Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Sat, 24 Oct 2015 22:09:35 -0400 Subject: [PATCH] Added find-fruit.py --- lib/modules/recon/find-fruit.py | 270 ++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 lib/modules/recon/find-fruit.py diff --git a/lib/modules/recon/find-fruit.py b/lib/modules/recon/find-fruit.py new file mode 100644 index 0000000..842e3e3 --- /dev/null +++ b/lib/modules/recon/find-fruit.py @@ -0,0 +1,270 @@ +import base64 +from lib.common import helpers + +class Module: + + def __init__(self, mainMenu, params=[]): + + self.info = { + 'Name': 'Find-Fruit', + + 'Author': ['@424f424f'], + + 'Description': ("Searches a network range for potentially vulnerable web services."), + + 'Background' : True, + + 'OutputExtension' : None, + + 'NeedsAdmin' : False, + + 'OpsecSafe' : True, + + 'MinPSVersion' : '2', + + 'Comments': [ + 'Inspired by mattifestation Get-HttpStatus in PowerSploit' + ] + } + + # any options needed by the module, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Agent' : { + 'Description' : 'Agent to run module on.', + 'Required' : True, + 'Value' : '' + }, + 'VoiceText' : { + 'Description' : 'Text to synthesize on target.', + 'Required' : True, + 'Value' : '' + } + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + + def generate(self): + + script = """ +function Get-HttpStatus +{ +<# +.SYNOPSIS + +Search for "low hanging fruit". +.DESCRIPTION + +A script to find potentially easily exploitable web servers on a target network. + +.PARAMETER Rhosts + +Targets in CIDR or comma separated format. + +.PARAMETER Port + +Specifies the port to connect to. + +.PARAMETER Path + +Path to custom dictionary. + +.PARAMETER UseSSL + +Use an SSL connection. + +.EXAMPLE + +C:\PS> Find-Fruit -Rhosts 192.168.1.0/24 -Port 8080 -Timeout 50 +C:\PS> Find-Fruit -Rhosts 192.168.1.0/24 -Path dictionary.txt -Port 443 -Timeout 50 + + +.NOTES +Credits to mattifestation for Get-HttpStatus +HTTP Status Codes: 100 - Informational * 200 - Success * 300 - Redirection * 400 - Client Error * 500 - Server Error + + +#> + + [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) + { + $iHost = $iHost.Replace(" ", "") + + if(!$iHost) + { + continue + } + + 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)) + + $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))) + $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++) + { + $nextAddress = $address.GetAddressBytes() + [array]::Reverse($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 + + } + } + else + { + $hostList.Add($iHost) + + } + } + + 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 { + $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 + } + + # 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" + + + 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 + + } + } +} +Find-Fruit""" + + for option,values in self.options.iteritems(): + if option.lower() != "agent" and option.lower() != "computername": + if values['Value'] and values['Value'] != '': + if values['Value'].lower() == "true": + # if we're just adding a switch + script += " -" + str(option) + else: + script += " -" + str(option) + " \"" + str(values['Value'].strip("\"")) + "\"" + + return script \ No newline at end of file