174 lines
4.6 KiB
Ruby
174 lines
4.6 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Search Engine Subdomains Collector',
|
|
'Description' => %q(
|
|
This module can be used to gather subdomains about a domain
|
|
from Yahoo, Bing.
|
|
),
|
|
'Author' => [ 'Nixawk' ],
|
|
'License' => MSF_LICENSE))
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGET', [ true, "The target to locate subdomains for, ex: rapid7.com, 8.8.8.8"]),
|
|
OptBool.new('IP_SEARCH', [ false, "Enable ip of subdomains to locate subdomains", true]),
|
|
OptBool.new('ENUM_BING', [ true, "Enable Bing Search Subdomains", true]),
|
|
OptBool.new('ENUM_YAHOO', [ true, "Enable Yahoo Search Subdomains", true])
|
|
])
|
|
|
|
deregister_options('RHOST', 'RPORT', 'VHOST', 'SSL', 'Proxies')
|
|
end
|
|
|
|
def rhost_yahoo
|
|
'search.yahoo.com'
|
|
end
|
|
|
|
def rport_yahoo
|
|
80
|
|
end
|
|
|
|
def rhost_bing
|
|
'global.bing.com'
|
|
end
|
|
|
|
def rport_bing
|
|
80
|
|
end
|
|
|
|
def valid_result?(target, subdomain)
|
|
data = Rex::Socket.is_ipv4?(target) ? domain2ip(subdomain) : subdomain
|
|
data && data.include?(target) ? true : false
|
|
end
|
|
|
|
def domain2ip(domain)
|
|
ips = []
|
|
begin
|
|
ips = Rex::Socket.getaddresses(domain)
|
|
rescue SocketError
|
|
end
|
|
ips
|
|
end
|
|
|
|
def uri2domain(uri)
|
|
begin
|
|
URI(uri).host
|
|
rescue URI::InvalidURIError
|
|
nil
|
|
end
|
|
end
|
|
|
|
def bing_search(dork)
|
|
print_status("Searching Bing for subdomains from #{dork}")
|
|
results = []
|
|
|
|
begin
|
|
searches = ['1', '51', '101', '151', '201', '251', '301', '351', '401', '451']
|
|
searches.each do |num|
|
|
resp = send_request_cgi!(
|
|
'rhost' => rhost_bing,
|
|
'rport' => rport_bing,
|
|
'vhost' => rhost_bing,
|
|
'method' => 'GET',
|
|
'uri' => '/search',
|
|
'vars_get' => {
|
|
'FROM' => 'HPCNEN',
|
|
'setmkt' => 'en-us',
|
|
'setlang' => 'en-us',
|
|
'first' => num,
|
|
'q' => dork
|
|
})
|
|
|
|
next unless resp && resp.code == 200
|
|
html = resp.get_html_document
|
|
matches = html.search('cite')
|
|
matches.each do |match|
|
|
result = uri2domain(match.text)
|
|
next unless result
|
|
result.to_s.downcase!
|
|
results << result
|
|
end
|
|
end
|
|
rescue ::Exception => e
|
|
print_error("#{dork} - #{e.message}")
|
|
end
|
|
results
|
|
end
|
|
|
|
def yahoo_search(dork)
|
|
print_status("Searching Yahoo for subdomains from #{dork}")
|
|
results = []
|
|
|
|
begin
|
|
searches = ["1", "101", "201", "301", "401", "501"]
|
|
searches.each do |num|
|
|
resp = send_request_cgi!(
|
|
'rhost' => rhost_yahoo,
|
|
'rport' => rport_yahoo,
|
|
'vhost' => rhost_yahoo,
|
|
'method' => 'GET',
|
|
'uri' => '/search',
|
|
'vars_get' => {
|
|
'pz' => 100,
|
|
'p' => dork,
|
|
'b' => num
|
|
})
|
|
|
|
next unless resp && resp.code == 200
|
|
html = resp.get_html_document
|
|
matches = html.search('span[@class=" fz-15px fw-m fc-12th wr-bw lh-15"]')
|
|
matches.each do |match|
|
|
result = match.text
|
|
result = result.split('/')[0]
|
|
result = result.split(':')[0]
|
|
next unless result
|
|
result.to_s.downcase!
|
|
results << result
|
|
end
|
|
end
|
|
rescue ::Exception => e
|
|
print_error("#{dork} - #{e.message}")
|
|
end
|
|
results
|
|
end
|
|
|
|
def search_subdomains(target)
|
|
domains = {}
|
|
ipv4 = Rex::Socket.is_ipv4?(target)
|
|
dork = ipv4 ? "ip:#{target}" : "domain:#{target}"
|
|
|
|
results = [] # merge results to reduce query times
|
|
results |= bing_search(dork) if datastore['ENUM_BING']
|
|
results |= yahoo_search(dork) if datastore['ENUM_YAHOO']
|
|
|
|
return domains if results.nil? || results.empty?
|
|
results.each do |subdomain|
|
|
next if domains.include?(subdomain)
|
|
next unless valid_result?(target, subdomain)
|
|
print_good("#{dork} subdomain: #{subdomain}")
|
|
if ipv4
|
|
domains[subdomain] = [target]
|
|
else
|
|
ips = domain2ip(subdomain)
|
|
next if ips.empty?
|
|
domains[subdomain] = ips
|
|
ips.each { |ip| search_subdomains(ip) } if !ips.empty? && datastore['IP_SEARCH']
|
|
end
|
|
end
|
|
return if domains.empty?
|
|
report_note(host: target, type: 'Subdomains', update: :unique_data, data: domains)
|
|
end
|
|
|
|
def run
|
|
search_subdomains(datastore['TARGET'])
|
|
end
|
|
end
|