Title here
Summary here
Los extenders son el mecanismo de extensión principal de JustC2. Se compilan como bibliotecas compartidas de Go (.so) y se cargan dinámicamente al iniciar el servidor. Hay dos tipos de extenders:
Cada extender necesita:
mi_extender/
├── Makefile # Compilación del plugin
├── config.yaml # Configuración del extender
├── ax_config.axs # Script de configuración AxScript
├── plugin.go # Código principal del plugin
└── src_*/ # (Solo agentes) Código fuente del agenteextender_type: "listener"
extender_file: "mi_listener.so"
ax_file: "ax_config.axs"
listener_name: "MiListener"
listener_type: "external" # "external" o "internal"
protocol: "http" # Protocolo identificadorextender_type: "agent"
extender_file: "mi_agente.so"
ax_file: "ax_config.axs"
agent_name: "mi_agente"
agent_watermark: "abcd1234" # Identificador único de 8 chars hex
listeners:
- "MiListener" # Listeners compatibles
multi_listeners: false # Si soporta múltiples listenersLos extenders implementan interfaces definidas en el módulo justc2/axc2:
type PluginListener interface {
Create(name, config string, customData []byte) (
ExtenderListener, ListenerData, []byte, error,
)
}type ExtenderListener interface {
Start() error
Edit(config string) (ListenerData, []byte, error)
Stop() error
GetProfile() ([]byte, error)
InternalHandler(data []byte) (string, error)
}type PluginAgent interface {
GenerateProfiles(profile BuildProfile) ([][]byte, error)
BuildPayload(profile BuildProfile, agentProfiles [][]byte) ([]byte, string, error)
CreateAgent(beat []byte) (AgentData, ExtenderAgent, error)
GetExtender() ExtenderAgent
}type ExtenderAgent interface {
CreateCommand(AgentData, map[string]any) (TaskData, ConsoleMessageData, error)
PackTasks(AgentData, []TaskData) ([]byte, error)
ProcessData(AgentData, []byte) error
Encrypt([]byte, []byte) ([]byte, error)
Decrypt([]byte, []byte) ([]byte, error)
PivotPackData(string, []byte) (TaskData, error)
TunnelCallbacks() TunnelCallbacks
TerminalCallbacks() TerminalCallbacks
}package main
import "justc2/axc2"
type MiListenerPlugin struct{}
func (p *MiListenerPlugin) Create(name, config string, customData []byte) (
axc2.ExtenderListener, axc2.ListenerData, []byte, error,
) {
listener := &MiListener{name: name}
data := axc2.ListenerData{
Name: name,
Protocol: "mi_protocolo",
Type: "external",
Status: "active",
}
return listener, data, nil, nil
}
// Exportar el plugin
var PluginListener MiListenerPlugintype MiListener struct {
name string
}
func (l *MiListener) Start() error {
// Iniciar el listener (abrir puerto, etc.)
return nil
}
func (l *MiListener) Stop() error {
// Detener el listener
return nil
}
func (l *MiListener) Edit(config string) (axc2.ListenerData, []byte, error) {
// Modificar configuración
return axc2.ListenerData{}, nil, nil
}
func (l *MiListener) GetProfile() ([]byte, error) {
// Retornar perfil de transporte
return nil, nil
}
func (l *MiListener) InternalHandler(data []byte) (string, error) {
// Manejar datos internos (para listeners bind)
return "", nil
}go build -buildmode=plugin -o mi_listener.so plugin.goLos extenders de agente son más complejos ya que deben:
func (p *MiAgentePlugin) BuildPayload(
profile axc2.BuildProfile,
agentProfiles [][]byte,
) ([]byte, string, error) {
// Compilar el agente con los perfiles de transporte
// Retorna: binario, nombre del archivo, error
return binaryData, "mi_agente_linux_x64", nil
}func (e *MiAgenteExtender) ProcessData(
agent axc2.AgentData,
data []byte,
) error {
// Procesar datos recibidos del agente
// Decodificar, descifrar, ejecutar callbacks
return nil
}Los extenders pueden registrar endpoints HTTP adicionales a través del teamserver:
// Endpoint autenticado (requiere JWT)
ts.RegisterEndpoint("POST", "/mi/endpoint", handler)
// Endpoint público (sin autenticación)
ts.RegisterPublicEndpoint("GET", "/publico/data", handler)build:
go build -buildmode=plugin -o mi_extender.so .
dist: build
mkdir -p dist
cp mi_extender.so dist/
cp config.yaml dist/
cp ax_config.axs dist/
module mi_extender
go 1.26.5
require justc2/axc2 v0.0.0
replace justc2/axc2 => ../../../axc2Añade el extender al profile.yaml:
Teamserver:
extenders:
- "extenders/mi_extender/config.yaml"