From DnsAdmins to SYSTEM to Domain Compromise
Last updated
Last updated
In this lab I'm trying to get code execution with SYSTEM
level privileges on a DC that runs a DNS service as originally researched by Shay Ber here.
The attack relies on a DLL injection into the dns service running as SYSTEM on the DNS server which most of the time is on a Domain Contoller.
For the attack to work, we need to have compromised a user that belongs to a DnsAdmins
group on a domain. Luckily, our user spotless
already belongs to the said group:
As mentioned earlier, we need to build a DNS plugin DLL that we will be injecting into a dns.exe process on a victim DNS server (DC). Below is a screenshot of the DLL exported functions that are expected by the dns.exe binary when loading a plugin DLL. I have also added a simple system command to invoke a netcat reverse shell once the plugin is initialized and code is executed.
I then tested the function with rundll32 as shown below, which returned a reverse shell to my attacking machine - code gets executed, shell gets spawned:
Now that we have the DLL and we checked that it is working, we can ask the victim DC01
to load our malicious DLL (from the victim controlled network share on host 10.0.0.2) next time the service starts (or when the attacker restarts it):
The below looks promising and suggests the request to load our malicious DLL was successful:
dnscmd
is a windows utility that allows people with DnsAdmins
privileges manage the DNS server. The utility can be installed by adding DNS Server Tools
to your system as shown in the below screengrab.
The below command on the victim further suggests that our request was successful and the registry value ServerLevelPluginDll
points to our malicious DLL:
Now the next time dns service starts, our malicious DLL should be loaded to the dns.exe process and a reverse shell should be sent back to our attacking system, so let's go and restart the DNS service:
By this point, I should have received a reverse shell, but unfortunately, I did not.
After checking the DNS logs on the DC01
I saw the below error, suggesting there was something off with my DLL:
I tried exporting functions with C++ name mangling and without and although the DLL exports seemed to be OK per CFF Explorer, I was still not able to make the DC load my malicious DLL successfully without corrupting the dns service:
Although I was not able to correctly inject the DLL without crashing the dns service in my lab environment, I still decided to publish these notes, in case they will be stubmled upon by a reader who had successfully injected a custom DLL and who would like to share their thoughts on what I am overlooking as this would be much appreciated.
Since I could not get my malicious DLL injected into the dns.exe successfully, I thought of trying to inject the meterpreter payload using the same technique.
It can be observed, that the DLL with meterpreter payloads gets ineed loaded and we receive a call back attempt from meterpreter, but since the DLL does not conform to the required format (does not have required exported functions), the session dies immediately (or this is what I thought initially - as you will later see, it turns out I was simply using a wrong listener):
Since the above suggests that the the DLL code still got executed, we can try asking the DLL to execute the following on the DC:
Before restarting the DNS service and getting our malicious DLL executed, let's make sure our attacking user spotless
is not in Domain Admins
group:
Now if we restart the DNS service which will load our addDA.dll
, we see that the user spotless
is now a member of the Domain Admins
:
Warning: at this time the DNS service is probably crashed, so be warned - using DLLs that do not conform to the plugin requirements is not stealthy and this type of activity probably will get picked up by defenders really quickly unless you can restore the DNS service immediately.
Below confirms that the dns service is down, however we can still access the DC C$ share by DC's IP from our spotless user, meaning that we have escalated privileges to DA:
One could think about scripting/automating the after-attack cleanup and the DNS service restoration and include the required code in the same malicious DLL that creates a backdoor user in the first place:
Once the DNS service is restored, we can now access the C$ using DC01 computer name:
It turns out that the reason the meterpreter payload failed because of a classic mistake of not using the right listener for staged/non-staged payloads - always double check your payloads and make sure that the listeners are able to handle the callbacks.
Once I set up the listener correctly, the meterpreter shell came back as expected - note that the dns.exe service still gets corrupted.
As a defender, one should considering monitoring for suspicious child processes (rundll32, powershell, cmd, net, etc.) spawned by the dns.exe on DCs:
Also, you may want to consider monitoring HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters
value ServerLevelPluginDll
, especially if it begins with string \\
in the data field.
I was pointed out by a reader that a video by ippsec https://youtu.be/8KJebvmd1Fk?t=3130 explains why the dns service was crashing, so please check the video, but if you are too lazy, the answer is provided here too.
You need to execute your code in a new thread (this was the missing piece in my first attempt that made the service crash) in the exported DLL function DnsPluginInitialize
, which is the function that gets invoked, when the dnscmd loads our malicious DNS service plugin DLL.