Full port scan reveals a classic domain controller profile: Kerberos, LDAP, and SMB. SSH on port 22 is unusual for Windows — it's OpenSSH for Windows, and it becomes the primary shell method throughout because WinRM is absent. HTTP on port 80 redirects to a Gibbon LMS instance.
faketime -f "+7h" throughout this box.Add the DC hostname to /etc/hosts — and critically, put the FQDN first. This matters for Kerberos SPN lookups (explained in detail in the Kerberos Setup section).
host/frizzdc.frizz.htb@FRIZZ.HTB. If frizz.htb comes first, SSH looks for host/frizz.htb@FRIZZ.HTB — a SPN that doesn't exist — and GSSAPI fails with "Permission denied" even with a valid TGT. Always put the DC FQDN first.Confirm the NTLM situation before going further. Both SMB and LDAP null sessions return STATUS_NOT_SUPPORTED — NTLM is completely disabled at the domain level.
The HTTP site at http://frizzdc.frizz.htb/home/ runs Gibbon LMS — an open-source school management system. Research for this version reveals a known file-write RCE that doesn't require authentication.
Gibbon LMS has an unauthenticated file-write vulnerability that allows uploading a PHP web shell. The exploit abuses an AJAX endpoint in the Rubrics module that writes attacker-controlled content to the web root without any authentication or path sanitisation check.
http://frizzdc.frizz.htb/. Pointing at /Gibbon-LMS/ fails — the exploit auto-discovers the installation path from the root. The discovered shell path will include the correct subdirectory automatically.Upgrade to a stable reverse shell by uploading nc.exe while the web shell is still alive.
The first thing to check in any PHP application is the database configuration file. Gibbon LMS stores its DB credentials in config.php at the application root.
Query the gibbonPerson table for user hashes. The passwordStrong and passwordStrongSalt columns hold the credentials.
-p and the password: -p "password" (with space) makes mysql prompt interactively for a password and hang forever. -p"password" (no space) passes the password non-interactively. A subtle difference that wastes time.Before cracking, always read the source to understand exactly how the hash was constructed. Getting the salt order wrong means zero cracks even with the correct password in the wordlist.
sha256(salt + password) — hashcat mode 1420. Input format: hash:salt.f.frizzle : Jenni_Luvs_Magic23With NTLM disabled, every tool needs a valid Kerberos TGT. This is where TheFrizz forces you to understand how Kerberos authentication actually works rather than relying on the usual pass-the-hash shortcuts. The three things needed are: a correctly configured krb5.conf, a TGT obtained at the right system time, and SSH using GSSAPI to consume that TGT.
With a valid TGT in the cache, SSH uses GSSAPI (Kerberos) automatically — no password prompt. The key insight is that SSH does a reverse lookup on the hostname to build the Kerberos SPN, which is why /etc/hosts order is critical (covered in the Enumeration section).
frizzdc.frizz.htb is the first hostname for the IP in /etc/hosts.With valid Kerberos credentials, run BloodHound collection using the --kerberos flag. NTLM is off, so bloodhound-python falls back to Kerberos authentication when collecting from LDAP and SMB.
BloodHound reveals the following attack path:
· Group Policy Creator Owners membership on M.SchoolBus — can create new GPOs
· WriteGPLink on
OU=Class_Frizz — can link GPOs to that OU
·
v.frizzle (Domain Admin) resides in Class_Frizz — and so do all regular users
Move to M.SchoolBus using the same Kerberos workflow: obtain a TGT for the new account and SSH in. Confirm group memberships to verify the GPO creation rights are in place before attempting the escalation.
Class_Frizz, this is enough for the escalation.The goal is to create a GPO with a malicious scheduled task that runs as SYSTEM on the DC, delivering a reverse shell. Three components make this possible:
· Group Policy Creator Owners — M.SchoolBus can create new GPOs in the domain
· WriteGPLink — M.SchoolBus can link GPOs to OUs
· Computer Scheduled Task — runs as SYSTEM when Group Policy refreshes on any in-scope computer
This section covers four failed attempts before the working approach — each failure teaches something important about how GPO scoping actually works.
Step 1: Upload tools. C:\Windows\Temp is write-denied for M.SchoolBus. C:\ProgramData is writable and works as a staging location.
Step 2: Create the GPO and link it. Linking to just Class_Frizz is insufficient for a computer task (explained in the failures below). The GPO must also be linked to the domain root so that the DC computer object inherits it.
What failed and why — four attempts before it worked.
faketime -f "+7h" python3 pygpoabuse.py frizz.htb/M.SchoolBus -k -no-pass ...Failed with two issues:
-no-pass and -ou are not valid flags in this version of pyGPOAbuse. Also hit KDC_ERR_S_PRINCIPAL_UNKNOWN when using the raw IP for -dc-ip instead of the DC FQDN — Kerberos needs resolvable hostnames, not IPs.
--AddComputerTask linked only to Class_Frizz:Computer GPO tasks apply only to computer objects in the targeted OU. The
Class_Frizz OU contains only user accounts — no computers. Linking a GPO with a computer task to an OU full of users does absolutely nothing, because no computer object receives that policy scope.
Class_Frizz OU: f.frizzle (user), M.SchoolBus (user), v.frizzle (user) — no computers
--AddUserTask:User tasks apply to user objects, making Class_Frizz the right scope. However,
gpupdate /force in an SSH session uses a network logon token (logon type 3). User GPO scheduled tasks are designed for interactive logons (logon type 2). The task was created and visible in Group Policy, but gpupdate via SSH only reliably applies computer policy — the user task was never triggered.
--AddComputerTask linked to domain root — WORKED:The DC computer object (
FRIZZDC$) lives in OU=Domain Controllers, which inherits GPOs from the domain root (DC=frizz,DC=htb). By linking the GPO to the domain root, the DC itself enters scope for the computer policy. gpupdate /force on the DC then processes the computer task and runs it as SYSTEM.
DC=frizz,DC=htb (domain root — GPO linked here) └── OU=Domain Controllers └── FRIZZDC$ (inherits GPO, processes computer task as SYSTEM)
Step 3: Verify SYSTEM execution before deploying the shell. Test with a harmless command-to-file write first — if the output file contains nt authority\system, the computer task is running correctly.
Step 4: Deploy the reverse shell.
This is worth understanding deeply. GPO task scoping is what made this box hard, and it's a concept that trips up most people because the distinction between computer and user policy isn't obvious from the BloodHound graph.
GPO Scope — what a GPO applies to.
A GPO applies to the objects in the OU it's linked to:
· Linked to an OU containing users → user configuration applies to those users
· Linked to an OU containing computers → computer configuration applies to those machines
· Linked to the domain root → applies to all objects in the domain through inheritance
Scheduled Tasks in GPO — when they run.
| Task Type | Applies To | Runs When |
|---|---|---|
| Computer Task | Computer objects in scope | Any user logs on, or gpupdate runs on that machine |
| User Task | User objects in scope | That specific user logs on interactively (logon type 2) |
Why network logon breaks user GPO tasks.
SSH creates a network logon (logon type 3). User GPO preferences and scheduled tasks are designed for interactive logons (logon type 2 — what you get at a physical console or RDP). When you run gpupdate /force in an SSH session, Windows processes computer policy reliably but silently skips user GPO preferences and scheduled tasks because there's no interactive logon context to attach them to.
The winning combination — why it worked.
| Step | What | Why |
|---|---|---|
| 1 | Create GPO as M.SchoolBus | Group Policy Creator Owners grants this right |
| 2 | Link to domain root | Inheritance reaches OU=Domain Controllers → FRIZZDC$ enters scope |
| 3 | --AddComputerTask | Applies to computer objects; runs as SYSTEM regardless of who triggers it |
| 4 | gpupdate /force in SSH session | Computer policy processes reliably over network logon — computer tasks fire |
--AddComputerTask vs --AddUserTask: always run Get-ADUser -Filter * -SearchBase "OU=..." and Get-ADComputer -Filter * -SearchBase "OU=..." to understand what object types live in each OU. That determines which task type makes sense and which OU to link the GPO to. Getting this wrong means the task is created, Group Policy applies cleanly, and absolutely nothing executes.· NTLM disabled —
STATUS_NOT_SUPPORTED on SMB/LDAP means everything needs Kerberos. Every tool needs -k, a valid TGT, and faketime -f "+Xh" prefixed when clock skew exists· /etc/hosts order — the first hostname for an IP is used for Kerberos SPN construction. Always put the DC FQDN first
· GPO computer tasks need computer objects in scope — linking to a user-only OU silently does nothing. When no computer objects are in the target OU, link to the domain root to reach the DC via inheritance
· User GPO tasks don't fire over SSH — SSH is a network logon (type 3). User GPO scheduled tasks require interactive logon (type 2). Use computer tasks for reliable remote execution
· Salted hash cracking — always read the source to confirm the exact salt order and hashing function.
sha256(salt + pass) is mode 1420 with format hash:salt. Getting salt order wrong means zero results even with the correct password in the wordlist· MySQL
-p flag — no space between -p and the password. -p "pass" hangs interactively; -p"pass" works inline