Skip to content

Data Storage (3 stars, Internal Systems)

Challenge

Hi Senior Researcher, the scientific community needs to access a data repository for the timely completion of a groundbreaking scientific publication in vexillology, but the administrator of the repository and all its users are away from civilization on a teambuilding trip. Your task is to gain the access. Stay curious! Data repository sits on smb.nren.tcc

Flag format: Flag{xxxx-xxxx-xxxx-xxxx}

Flag

FLAG{ShWJ-CVi0-cZ2W-7DsZ}

Solution

Step 1: Enumerate SMB shares

Connect anonymously to smb.nren.tcc. Two shares: public (guest read-only) and private (Kerberos required). Read teambuilding.txt and it_notice.txt from public to learn usernames (kevin, eve, jane, dmitri) and Kerberos config (realm NREN.TCC, kdc kdc.nren.tcc).

Step 2: Find jane's password

Brute-forced Kerberos pre-auth for all 4 users. jane's password is 12345. Discovery: testing simple passwords, jane:12345 produced a PyAsn1Error instead of KDC_ERR_PREAUTH_FAILED — the AS-REP decrypted successfully but the ASN.1 parser choked on MIT KDC's non-standard tag (see Technical Notes).

Step 3: Get TGT and TGS for jane (MIT KDC quirks)

Two impacket issues with this MIT KDC required manual protocol handling:

  1. DER tag mismatch: MIT KDC returns EncTGSRepPart (application tag 26/0x7a) in AS-REP instead of EncASRepPart (tag 25/0x79). Fix: patch the first byte of the decrypted enc-part from 0x7a to 0x79 before parsing.

  2. Mandatory req-body checksum: MIT KDC requires a checksum of the TGS-REQ req-body in the authenticator (impacket omits it). The checksum must be computed over the inner SEQUENCE encoding (tag 0x30) of the req-body, NOT the context-tagged version (tag 0xa4) that pyasn1's encoder.encode() produces when the reqBody is created via seq_set(). Fix: strip the outer [4] context tag before checksumming.

# 1. Fix DER tag in AS-REP enc-part
plainText = cipher_cls.decrypt(key, 3, encPartData)
if plainText[0] == 0x7a:
    plainText = bytes([0x79]) + plainText[1:]
encASRepPart = decoder.decode(plainText, asn1Spec=EncASRepPart())[0]

# 2. Strip context tag for req-body checksum
encodedFull = encoder.encode(reqBody)  # starts with 0xa4 (context [4])
if encodedFull[0] == 0xa4:
    if encodedFull[1] & 0x80:
        nlen = encodedFull[1] & 0x7f
        innerSeq = encodedFull[2 + nlen:]
    else:
        innerSeq = encodedFull[2:]
cksum = make_checksum(16, sessionKey, 6, innerSeq)  # cksumtype 16 = hmac-sha1-96-aes256
# Add to authenticator: auth['cksum']['cksumtype'] = 16, auth['cksum']['checksum'] = cksum

Step 4: Access private share as jane

With jane's TGS for cifs/smb.nren.tcc, pass it to SMBConnection.kerberosLogin() as a dict:

TGS_dict = {'KDC_REP': raw_tgs_bytes, 'cipher': svc_cipher, 'sessionKey': svc_key, 'oldSessionKey': sessionKey}
smb.kerberosLogin('jane', '', 'NREN.TCC', kdcHost='kdc.nren.tcc', TGS=TGS_dict, useCache=False)

Private share contents:

private/
├── jane/       (readable by jane)
│   ├── fact1.txt   — CESNET/e-INFRA CZ info text
│   ├── fact2.txt   — same
│   ├── fact3.txt   — same
│   └── image.png   — PNG image
├── kevin/
│   ├── kevin.keytab (130 bytes) — readable by jane!
│   └── flag.txt    (26 bytes)  — ACCESS_DENIED for jane
├── eve/
│   └── testing.txt — ACCESS_DENIED for jane
└── dmitri/         — empty

Step 5: Use kevin's keytab to read the flag

kevin.keytab contains kevin's AES256 and AES128 keys (kvno 2):

etype 18 (AES256): ca2375d2f9a22289c4991acfafd5cb9f3a4bddd640730f0003f0395233bea95e
etype 17 (AES128): c4fd34fc533defc930bca45540eb21a1

Use the AES256 key directly for pre-auth (PA-ENC-TIMESTAMP, key usage 1) — no password needed:

kevin_key = Key(18, bytes.fromhex('ca2375d2...'))
encTS = cipher_cls.encrypt(kevin_key, 1, encoder.encode(pa_ts), None)

Get TGT as kevin → get TGS for cifs/smb.nren.tcc → authenticate to SMB → read kevin/flag.txt:

FLAG{ShWJ-CVi0-cZ2W-7DsZ}

Infrastructure

SMB Server: smb.nren.tcc (10.99.26.31)

  • Samba 4.22.8-Debian
  • Ports: 139/tcp, 445/tcp (only these two)
  • SMB signing enabled but not required
  • Two shares:
  • public — guest access, read-only
  • private — requires Kerberos authentication
  • NTLM auth maps to guest (map to guest = bad user/bad password)
  • No local Samba users (only guest RID 501)

KDC: kdc.nren.tcc (10.99.26.30)

  • Port: 88/tcp (only this one — 464/kpasswd, 749/kadmin, 389/LDAP, 22/SSH all closed)
  • Realm: NREN.TCC
  • MIT Kerberos (not Active Directory)
  • PBKDF2 with 4096 iterations for AES256 key derivation
  • RC4 (etype 23) NOT supported — must use AES (etype 18)

krb5.conf

[libdefaults]
    default_realm = NREN.TCC
    dns_lookup_realm = false
    dns_lookup_kdc = false
[realms]
    NREN.TCC = {
        kdc = kdc.nren.tcc
        admin_server = kdc.nren.tcc
    }
[domain_realm]
    .nren.tcc = NREN.TCC
    nren.tcc = NREN.TCC

Public Share Contents

teambuilding.txt

2026 TEAMBUILDING CHART - local branch A
+-------------------+-----------------+--------------+-------------------+
| name              | attendance      | sleepover    | notes             |
+-------------------+-----------------+--------------+-------------------+
| kevin             | no              | no           | not interested    |
| eve               | yes             | yes          | room with jane    |
| jane              | yes             | yes          | room with eve     |
| dmitri            | yes             | yes          | room with jane ;) |
+-------------------+-----------------+--------------+-------------------+

it_notice.txt

Kevin (head of IT) notice about Kerberos migration: - realm: NREN.TCC, kdc: kdc.nren.tcc - "your login will be the same as your company account, i.e. yourname@REALM" - "You should be able to Google the rest of the config" - Contains typos: "neccessary", "Regural"

Known Users

  • kevin — IT head, set up Kerberos, "not interested" in teambuilding
  • eve — attending, room with jane
  • jane — attending, room with eve
  • dmitri — attending, "room with jane ;)"
  • All 4 require Kerberos pre-authentication

Kerberos Principals Without Pre-Auth

  • kadmin/changepw — no pre-auth required
  • kadmin/admin — no pre-auth required

Cross-Challenge Intel

  • From ticket_system: Kevin used password LearnHowToOptimize for DB (db.nren.tcc, user crmtest). Did NOT work for any Kerberos user.

What Has Been Tried (Exhaustively)

1. Network Brute Force (all failed)

  • All 4 users x top 10K rockyou (>=5 chars) = 40,000 attempts at ~11/s
  • All 4 users x ~106 themed passwords (vexillology terms, typos from files, user names, CTF terms, cross-challenge passwords + variations)
  • All 4 users x 156 creative/themed passwords + 91 CamelCase phrases
  • All 4 users x 1960 name+special+number patterns (from quantum_repository_keys policy hint)
  • All 4 users x 180 misc patterns
  • LearnHowToOptimize + variations for kevin
  • admin#1234 + variations for kadmin/admin and kadmin/changepw
  • cifs/smb.nren.tcc service principal x ~60 common passwords

2. AS-REP Roasting + Hashcat GPU Cracking (extraction OK, crack failed)

  • Extracted AS-REP (no pre-auth) for kadmin/changepw and kadmin/admin (etype 18, AES256)
  • Extracted TGS ticket for cifs/smb.nren.tcc (etype 18, AES256, kvno 2, 433 bytes)
  • Hashcat GPU (GTX 1650, ~135k H/s) — cracked all three hashes against full rockyou (14.3M):
  • AS-REP kadmin/changepw (salt=NREN.TCCkadminchangepw, mode 32200): EXHAUSTED
  • AS-REP kadmin/admin (salt=NREN.TCCkadminadmin, mode 32200): EXHAUSTED
  • TGS cifs/smb.nren.tcc (salt=NREN.TCCcifssmb.nren.tcc, mode 19700): EXHAUSTED
  • Also tried with original salt kadmin/changepw (with slash): EXHAUSTED
  • Hashcat with rules — dive.rule (98K rules) on 20 targeted words (~2M combinations): EXHAUSTED
  • Each hash took ~2 minutes against full rockyou at GPU speed

3. CPU Offline Cracking (failed)

  • top10K x 3 salt variants for kadmin/changepw AS-REP: no match
  • top100K x 3 salt variants for kadmin/changepw AS-REP: no match
  • Full rockyou attempted but failed due to multiprocessing error under python3 -I

4. SMB Enumeration (expanded)

  • RID brute force: only guest (RID 501)
  • lookupnames: kevin(S-1-22-1-1001), eve(S-1-22-1-1002), jane(S-1-22-1-1003), dmitri(S-1-22-1-1004) — Unix UID-mapped SIDs
  • Domain SID: S-1-5-21-4234862031-1388807591-4152307358
  • querydominfo: Domain=WORKGROUP, Server=SMB, Role=ROLE_DOMAIN_PDC
  • getdompwinfo: min_password_length=5, password_properties=0x00000000
  • Share paths: public→C:\data\public, private→C:\data\private (i.e., /data/public and /data/private)
  • Private share ACL: S-1-1-0 (Everyone) has FULL access (0x1f01ff) — only Kerberos auth is the barrier
  • Path traversal from public to private: NT_STATUS_OBJECT_NAME_NOT_FOUND

5. Port Scanning (minimal attack surface)

  • KDC: only port 88/tcp open (full -p- scan confirmed)
  • SMB: only ports 139/tcp, 445/tcp open (full -p- scan confirmed)
  • No LDAP (389), no kadmin (749), no kpasswd (464), no SSH (22), no HTTP, no RPC endpoint mapper (135)

6. CVE-2026-4480 — Samba Print %J Injection (NOT exploitable)

  • Samba 4.22.8 is vulnerable (fix in 4.22.10)
  • Exploit requires a printable share with print command containing %J
  • No printers configured: enumprinters returns empty
  • Printing subsystem is active: Spooler service running, "Samba Printer Port" exists, DefaultSpoolDirectory set
  • Tried adding printer via rpcclient addprinter: WERR_ACCESS_DENIED (as anonymous/guest)
  • Tried opening printer handles for 14 different names: all WERR_INVALID_PRINTER_NAME
  • Tried submitting print job to public share: NT_STATUS_ACCESS_DENIED
  • Conclusion: Cannot exploit without a printable share. Need authenticated access to add a printer.

7. CVE-2026-4408 — Samba SAMR Password Script Injection (NOT exploitable)

  • Samba 4.22.8 is vulnerable (fix in 4.22.10)
  • Exploit injects commands via %u (username) in check password script
  • Uses SamrValidatePassword (opnum 67) — levels 1, 2, and 3 all tried
  • ACCESS_DENIED for all levels as anonymous
  • Guest auth fails due to SMB2 signature mismatch
  • Also tried injection through chgpasswd3 username field: returns NT_STATUS_WRONG_PASSWORD (old password check happens before script invocation)
  • No TCP RPC endpoint (port 135 closed), only named pipes via SMB
  • Conclusion: Requires authenticated access to call SamrValidatePassword, or correct old password for chgpasswd3 path

8. Kerberos Protocol Exploration (no bypass found)

  • Confirmed salts via etype-info2: kevin→NREN.TCCkevin, eve→NREN.TCCeve, jane→NREN.TCCjane, dmitri→NREN.TCCdmitri
  • cifs/smb.nren.tcc salt: NREN.TCCcifssmb.nren.tcc
  • Supported etypes: AES128 (17) and AES256 (18) only
  • Checked 17+ special/anonymous principals (WELLKNOWN/ANONYMOUS, host/, nfs/, HTTP/, etc.)
  • K/M principal exists but is REVOKED
  • kpasswd protocol works through port 88 (not just 464), confirmed via changepasswd.py
  • No zone transfer or interesting DNS records

9. Registry Enumeration (partial, smbconf ACCESS_DENIED)

  • Readable keys: HKLM\SOFTWARE\Samba (has smbconf, Group Policy), HKLM\SYSTEM\CurrentControlSet
  • smbconf: ACCESS_DENIED — can't read Samba configuration
  • Spooler service: Start=2, ImagePath=/usr/lib/x86_64-linux-gnu/samba/svcctl/smbd
  • Print subsystem: Forms, Printers (empty), Environments (x86, x64), Monitors (empty)
  • LanmanServer\Shares: has Security subkey (empty values)
  • ProductType: ServerNT

10. SAMR Password Oracle (works but slow)

  • chgpasswd3 kevin oldpass newpass → NT_STATUS_WRONG_PASSWORD — confirms SAMR password change works
  • SamrUnicodeChangePasswordUser2 via impacket: ~5 attempts/sec single-threaded
  • Can brute force NTLM passwords (MD4-based, no PBKDF2) but limited by network round-trips
  • Even with 8 threads, only ~20-40/s — 14M rockyou would take days
  • 43 targeted passwords tested via SAMR for kevin: all WRONG_PASSWORD

11. Cross-Challenge Credential Reuse (all failed)

  • LearnHowToOptimize (Kevin's DB password from ticket_system): doesn't work for Kerberos
  • admin#1234 (from quantum_repository_keys): doesn't work
  • Password policy "login + special char + number" pattern: all combinations tried for all 4 users
  • osTicket IDOR for Kevin's responses: IDOR is patched, always shows own ticket
  • osTicket staff login as kevin: all passwords failed

Dead Ends / Incorrect Routes Explored

All of the above approaches (sections 1-11) were explored before finding that jane's password was the trivially simple 12345. Key takeaways:

  • AS-REP roasting was a red herring: kadmin/changepw and kadmin/admin lack pre-auth but their passwords are strong — rockyou + rules couldn't crack them.
  • CVE exploitation was unnecessary: Both CVE-2026-4480 and CVE-2026-4408 require authenticated access, creating a chicken-and-egg problem. The intended path was simply finding a weak password.
  • SAMR brute force was too slow: The NTLM-based password oracle works (~5-40 attempts/sec) but is impractical for large wordlists over the network.
  • Hashcat GPU cracking was overkill: The password 12345 IS in rockyou, but it was only tested against kadmin hashes, not user hashes (users require pre-auth, so no AS-REP to crack). The actual solve path was online brute force against user principals.
  • The password 12345 was not tested early because the min_password_length is 5, and 12345 is exactly 5 chars — it should have been in the first batch of attempts. It was likely missed in early runs due to wordlist filtering or ordering issues.

Relevant CVEs for Samba 4.22.8

CVE Description Exploitable? Blocker
CVE-2026-4480 Print %J job name RCE NO No printable share configured
CVE-2026-4408 SAMR password script %u injection NO ValidatePassword ACCESS_DENIED as anonymous
CVE-2026-1933 Read-only share bypass via reparse point UNTESTED May allow bypassing read-only on public share
CVE-2026-58221/58222 LDAP authorization bypass N/A Not an AD DC, no LDAP port

CVE-2026-4480 Exploit Flow (for reference)

# Requires: python3-samba, a valid printer name
from samba.dcerpc import spoolss
iface = spoolss.spoolss(f'ncacn_np:{target}[\\pipe\\spoolss]', lp, creds)
h = iface.OpenPrinter(f'\\\\{target}\\PRINTER_NAME', '', spoolss.DevmodeContainer(), 0x00000008)
i1 = spoolss.DocumentInfo1()
i1.document_name = '|sh'  # %J injects this into print command
i1.datatype = 'RAW'
ctr = spoolss.DocumentInfoCtr()
ctr.level = 1
ctr.info = i1
iface.StartDocPrinter(h, ctr)
iface.StartPagePrinter(h)
iface.WritePrinter(h, b'SHELL_COMMAND_HERE\n', len(payload))
iface.EndPagePrinter(h)
iface.EndDocPrinter(h)

CVE-2026-4408 Exploit Flow (for reference)

# Requires: check password script with %u, authenticated SAMR access
from samba.dcerpc import samr, lsa
conn = samr.samr(f'ncacn_np:{target}[\\pipe\\samr]', lp, creds)
req = samr.ValidatePasswordReq2()
# ... set info fields ...
acct = lsa.StringLarge()
acct.string = 'user$(COMMAND_HERE)'  # %u injection
req.account = acct
conn.ValidatePassword(2, req)

Scripts (in scratchpad)

Solution scripts

  • tgs_access.py — complete solve: AS-REQ as jane → TGS-REQ with MIT KDC fixes → SMB access to private share → download kevin.keytab
  • kevin_flag.py — complete solve: AS-REQ as kevin using keytab AES256 key → TGS-REQ → SMB → read flag.txt
  • kevin.keytab — kevin's keytab downloaded from private share

Enumeration / brute force scripts

  • krbbrute_v5.py — fast network brute force with monkey-patched PBKDF2
  • kerberoast_asreq.py — AS-REQ kerberoasting (extract service tickets via AS exchange)
  • crack_tgs.py — offline TGS AES256 cracker
  • mt_brute.py — multi-threaded Kerberos brute force (8 threads)
  • samr_fast.py — multi-threaded SAMR password oracle brute force
  • check_anon.py — enumerate special/anonymous Kerberos principals
  • check_etypes.py — check supported encryption types
  • brute_svc.py — brute force cifs/smb.nren.tcc service principal

Supporting files

  • krb5.conf — Kerberos config
  • tgs_hashcat_fixed.txt — TGS hash for hashcat mode 19700 (salt=cifssmb.nren.tcc)
  • asrep_hashcat_fixed.txt — AS-REP hash for hashcat mode 32200 (salt=kadminchangepw)
  • asrep_admin_hashcat.txt — AS-REP hash for kadmin/admin (salt=kadminadmin)
  • top10k.txt — top 10K rockyou (>=5 chars)
  • top100k.txt — top 100K rockyou (>=5 chars)
  • Rockyou source: /home/malisha/Downloads/thecatch2025/rockyou.txt (14.3M entries)

Key Technical Notes

MIT KDC vs AD KDC — impacket compatibility

  • EncTGSRepPart tag: MIT KDC returns application tag 26 (EncTGSRepPart) in AS-REP enc-part instead of tag 25 (EncASRepPart). This is technically RFC-compliant (both map to EncKDCRepPart) but breaks impacket's getKerberosTGT() which expects tag 25. Fix: patch byte 0 from 0x7a to 0x79 in the decrypted plaintext.
  • Mandatory TGS-REQ authenticator checksum: MIT KDC requires the authenticator in TGS-REQ to contain a checksum of the req-body (key usage 6, cksumtype 16 for AES256). impacket's getKerberosTGS() omits this. Without it: KRB_AP_ERR_INAPP_CKSUM. With wrong data: KRB_AP_ERR_BAD_INTEGRITY.
  • Context tag stripping: pyasn1 encodes a req-body created via seq_set() with context tag [4] (0xa4) wrapping the SEQUENCE. MIT KDC checksums the inner SEQUENCE only. Must strip [4] tag+length before computing the checksum.
  • Etype negotiation: MIT KDC only supports AES128/AES256. impacket's getKerberosTGS() requests RC4+DES3+DES+AES — the unsupported types are ignored, not rejected.
  • CCache saving fails: CCache.fromTGT() calls str() on pyasn1 timestamp fields from EncTGSRepPart objects, which throws PyAsn1Error. Must build TGS-REQ manually instead of saving/loading CCache.

General

  • Python 3.14 removed MD4 from hashlib — use impacket.ntlm.compute_nthash() for NTLM
  • impacket's PBKDF2 is slow (153ms/call) — monkey-patch with hashlib.pbkdf2_hmac (2.7ms/call) for 90x speedup
  • Use python3 -u -I for unbuffered output and isolated mode
  • KRB5_CONFIG env var must be set in every Bash command (shell state doesn't persist)
  • getKerberosTGT sends pre-auth by default, so AS-REP roasting requires custom AS-REQ builder
  • Hashcat modes: 32200 (AS-REP etype 18), 32100 (AS-REP etype 17), 19700 (TGS etype 18), 19600 (TGS etype 17)
  • GTX 1650 GPU: ~135k H/s for Kerberos AES hashes — full rockyou in ~2 minutes
  • SAMR password oracle: chgpasswd3 user oldpw newpw → NT_STATUS_WRONG_PASSWORD means user exists with different password
  • python3-samba package provides native DCE/RPC bindings with correct NDR marshalling
  • Keytab v2 format: 0x0502 header, entries with principal, etype, kvno, and raw key bytes. Parse manually with struct to extract keys for pre-auth.