[SHEHZADE//ABDULLAH ANSARI]
Red Team Consultant @ Google | MS in Cybersecurity @ NYU
● Notice //GitHub (@shehzade) is temporarily suspended pending an automated false-positive review. All tools are hosted on this Code Mirror and available on request (contact); GitHub links will return once reinstated.
PUBLIC MIRRORGo v1.0
Multi-protocol network egress assessment and DLP verification framework featuring automated L4 sweeps, corporate proxy traversal, and covert protocol smuggling across 20+ channels.
$
git clone https://shehzade.io/repos/contraband.git
Copy
Source ZIP (1.93 MB)
307 lines · 11.1 KB
| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "fmt" |
| 6 | "math/rand" |
| 7 | "os" |
| 8 | "os/signal" |
| 9 | "strconv" |
| 10 | "strings" |
| 11 | "syscall" |
| 12 | "time" |
| 13 | |
| 14 | "github.com/shehzade/contraband/pkg/common" |
| 15 | "github.com/shehzade/contraband/pkg/dryrun" |
| 16 | "github.com/shehzade/contraband/pkg/server" |
| 17 | "github.com/shehzade/contraband/pkg/server/listeners" |
| 18 | "github.com/shehzade/contraband/pkg/server/multiplexer" |
| 19 | "github.com/spf13/cobra" |
| 20 | ) |
| 21 | |
| 22 | var ( |
| 23 | flagConfig string |
| 24 | flagVerbose bool |
| 25 | flagJSON bool |
| 26 | flagSeed int64 |
| 27 | flagDryRun bool |
| 28 | |
| 29 | serverBind string |
| 30 | serverDomain string |
| 31 | serverPorts string |
| 32 | serverProtocols string |
| 33 | serverSMBMode string |
| 34 | serverCert string |
| 35 | serverKey string |
| 36 | serverEnableEBPF bool |
| 37 | serverDB string |
| 38 | serverSavePayload bool |
| 39 | serverEvidenceDir string |
| 40 | serverTCP bool |
| 41 | serverUDP bool |
| 42 | serverBanner string |
| 43 | serverPortAlias string |
| 44 | serverDashboard string |
| 45 | |
| 46 | loadedConfig *common.ProfileConfig |
| 47 | appLogger common.Logger |
| 48 | ) |
| 49 | |
| 50 | var rootCmd = &cobra.Command{ |
| 51 | Use: "contraband-server", |
| 52 | Short: "Contraband Standalone Reflection Server & Session Ledger", |
| 53 | Long: `Dedicated standalone server binary for multi-port reflection, |
| 54 | multi-protocol listener coordination, and session ledger reassembly.`, |
| 55 | SilenceUsage: true, |
| 56 | SilenceErrors: true, |
| 57 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { |
| 58 | appLogger = common.GetLogger() |
| 59 | if flagJSON { |
| 60 | appLogger.SetMode(common.LogModeJSON) |
| 61 | } |
| 62 | if flagVerbose { |
| 63 | appLogger.SetLevel(common.LogLevelDebug) |
| 64 | } |
| 65 | if flagSeed != 0 { |
| 66 | rand.Seed(flagSeed) |
| 67 | appLogger.Debug(fmt.Sprintf("Initialized deterministic random seed: %d", flagSeed)) |
| 68 | } |
| 69 | if flagConfig != "" { |
| 70 | cfg, err := common.LoadProfileConfig(flagConfig) |
| 71 | if err != nil { |
| 72 | return fmt.Errorf("failed to load configuration profile: %w", err) |
| 73 | } |
| 74 | loadedConfig = cfg |
| 75 | } |
| 76 | return nil |
| 77 | }, |
| 78 | RunE: runServerStandalone, |
| 79 | } |
| 80 | |
| 81 | func init() { |
| 82 | rootCmd.PersistentFlags().StringVarP(&flagConfig, "config", "c", "", "Path to YAML/JSON configuration profile") |
| 83 | rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Enable verbose debug logging") |
| 84 | rootCmd.PersistentFlags().BoolVar(&flagJSON, "json", false, "Output results in structured JSON format") |
| 85 | rootCmd.PersistentFlags().Int64Var(&flagSeed, "seed", 0, "Deterministic random seed for reproducible runs") |
| 86 | rootCmd.PersistentFlags().BoolVar(&flagDryRun, "dry-run", false, "Pre-flight validation without transmitting live network traffic") |
| 87 | |
| 88 | rootCmd.Flags().StringVarP(&serverBind, "bind", "b", "0.0.0.0", "Server IP interface to bind listeners") |
| 89 | rootCmd.Flags().StringVarP(&serverDomain, "domain", "d", "contraband.example.com", "Authoritative domain for DNS tunneling reassembly") |
| 90 | rootCmd.Flags().StringVarP(&serverPorts, "ports", "p", "quick", "Port matrix for multiplexer: 'quick', 'standard', or ranges") |
| 91 | rootCmd.Flags().StringVar(&serverPortAlias, "port", "", "Alias for --ports") |
| 92 | rootCmd.Flags().StringVar(&serverProtocols, "protocols", "all", "Server protocol listeners to activate ('all', 'web', 'dns', etc.)") |
| 93 | rootCmd.Flags().StringVar(&serverSMBMode, "smb-mode", "hash-capture", "SMB server operational mode: 'hash-capture' or 'file-transfer'") |
| 94 | rootCmd.Flags().StringVar(&serverCert, "cert", "", "Custom TLS certificate path (auto-generates dynamic CA if omitted)") |
| 95 | rootCmd.Flags().StringVar(&serverKey, "key", "", "Custom TLS private key path") |
| 96 | rootCmd.Flags().BoolVar(&serverEnableEBPF, "enable-ebpf", false, "Enable Linux eBPF/nftables full-spectrum port redirection (requires root)") |
| 97 | rootCmd.Flags().StringVar(&serverDB, "db", ":memory:", "SQLite database path for session ledger (:memory: for in-memory)") |
| 98 | rootCmd.Flags().BoolVar(&serverSavePayload, "save-payload", false, "Physically reconstruct and save received payload files to disk") |
| 99 | rootCmd.Flags().StringVar(&serverEvidenceDir, "evidence-dir", "evidence", "Destination directory for physical session payloads") |
| 100 | rootCmd.Flags().BoolVar(&serverTCP, "tcp", true, "Enable TCP reflection in port multiplexer") |
| 101 | rootCmd.Flags().BoolVar(&serverUDP, "udp", true, "Enable UDP reflection in port multiplexer") |
| 102 | rootCmd.Flags().StringVar(&serverBanner, "banner", "", "Custom JSON reflection banner format string") |
| 103 | rootCmd.Flags().StringVar(&serverDashboard, "dashboard", "", "Address to bind live command center dashboard and report server (e.g. :8080)") |
| 104 | rootCmd.Flags().StringVar(&serverDashboard, "live-dashboard", "", "Alias for --dashboard") |
| 105 | |
| 106 | rootCmd.AddCommand(&cobra.Command{ |
| 107 | Use: "version", |
| 108 | Short: "Print server version", |
| 109 | Run: func(cmd *cobra.Command, args []string) { |
| 110 | fmt.Printf("Contraband Server v%s (Pure Go, CGO_ENABLED=0)\n", common.Version) |
| 111 | }, |
| 112 | }) |
| 113 | } |
| 114 | |
| 115 | func runServerStandalone(cmd *cobra.Command, args []string) error { |
| 116 | if serverPortAlias != "" && (serverPorts == "quick" || serverPorts == "") { |
| 117 | serverPorts = serverPortAlias |
| 118 | } |
| 119 | |
| 120 | cfg := server.DefaultServerConfig() |
| 121 | cfg.BindIP = serverBind |
| 122 | cfg.Domain = serverDomain |
| 123 | cfg.Ports = serverPorts |
| 124 | cfg.Protocols = serverProtocols |
| 125 | cfg.SMBMode = serverSMBMode |
| 126 | cfg.CertPath = serverCert |
| 127 | cfg.KeyPath = serverKey |
| 128 | cfg.EnableEBPF = serverEnableEBPF |
| 129 | cfg.DBPath = serverDB |
| 130 | cfg.SavePayload = serverSavePayload |
| 131 | cfg.EvidenceDir = serverEvidenceDir |
| 132 | cfg.DashboardAddr = serverDashboard |
| 133 | cfg.EnableTCP = serverTCP |
| 134 | cfg.EnableUDP = serverUDP |
| 135 | cfg.Banner = serverBanner |
| 136 | |
| 137 | if flagDryRun { |
| 138 | return dryrun.RunServerDryRun(cfg) |
| 139 | } |
| 140 | |
| 141 | engine, err := server.NewServerEngine(cfg) |
| 142 | if err != nil { |
| 143 | return fmt.Errorf("failed to initialize server engine: %w", err) |
| 144 | } |
| 145 | |
| 146 | requestedPorts, err := common.ParsePortsField(cfg.Ports) |
| 147 | if err != nil { |
| 148 | return fmt.Errorf("invalid ports specification %q: %w", cfg.Ports, err) |
| 149 | } |
| 150 | |
| 151 | registry := listeners.NewListenerRegistry(appLogger) |
| 152 | logger := common.GetLogger() |
| 153 | tlsConfig := engine.GetTLSConfig() |
| 154 | sshHostKey := engine.GetSSHHostKey() |
| 155 | |
| 156 | protoLower := strings.ToLower(cfg.Protocols) |
| 157 | isCustomPorts := cfg.Ports != "quick" && cfg.Ports != "standard" && cfg.Ports != "full" |
| 158 | |
| 159 | dashPort := 0 |
| 160 | if cfg.DashboardAddr != "" { |
| 161 | parts := strings.Split(cfg.DashboardAddr, ":") |
| 162 | if len(parts) > 1 { |
| 163 | if dp, err := strconv.Atoi(parts[len(parts)-1]); err == nil { |
| 164 | dashPort = dp |
| 165 | } |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | if protoLower != "none" && protoLower != "reflector" { |
| 170 | if isCustomPorts { |
| 171 | hasPort := func(target int) bool { |
| 172 | for _, p := range requestedPorts { |
| 173 | if p == target { |
| 174 | return true |
| 175 | } |
| 176 | } |
| 177 | return false |
| 178 | } |
| 179 | if protoLower == "all" || strings.Contains(protoLower, "web") || strings.Contains(protoLower, "http") { |
| 180 | var webPorts []int |
| 181 | for _, p := range requestedPorts { |
| 182 | if (p == 8443 || p == 9443 || p == 10443 || p == 80 || p == 443 || p == 8080) && p != dashPort { |
| 183 | webPorts = append(webPorts, p) |
| 184 | } |
| 185 | } |
| 186 | if len(webPorts) > 0 { |
| 187 | _ = registry.Register(listeners.NewHTTPServerListener(cfg.BindIP, webPorts, webPorts[0], tlsConfig)) |
| 188 | } |
| 189 | } |
| 190 | if (protoLower == "all" || strings.Contains(protoLower, "dns")) && hasPort(53) { |
| 191 | _ = registry.Register(listeners.NewDNSServerListener(cfg.BindIP, 53, 53, 853, 8443, tlsConfig)) |
| 192 | } |
| 193 | } else { |
| 194 | defaultWebPorts := []int{80, 443, 8080} |
| 195 | if dashPort > 0 { |
| 196 | var filtered []int |
| 197 | for _, p := range defaultWebPorts { |
| 198 | if p != dashPort { |
| 199 | filtered = append(filtered, p) |
| 200 | } |
| 201 | } |
| 202 | defaultWebPorts = filtered |
| 203 | } |
| 204 | |
| 205 | dohPort := 8443 |
| 206 | for _, p := range defaultWebPorts { |
| 207 | if p == dohPort { |
| 208 | dohPort = 8444 |
| 209 | break |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | if err := registry.Register(listeners.NewHTTPServerListener(cfg.BindIP, defaultWebPorts, 443, tlsConfig)); err != nil { |
| 214 | logger.Warn(fmt.Sprintf("Failed to register HTTPServerListener: %v", err)) |
| 215 | } |
| 216 | if err := registry.Register(listeners.NewGRPCServerListener(cfg.BindIP, []int{50051}, tlsConfig)); err != nil { |
| 217 | logger.Warn(fmt.Sprintf("Failed to register GRPCServerListener: %v", err)) |
| 218 | } |
| 219 | if err := registry.Register(listeners.NewDNSServerListener(cfg.BindIP, 53, 53, 853, dohPort, tlsConfig)); err != nil { |
| 220 | logger.Warn(fmt.Sprintf("Failed to register DNSServerListener: %v", err)) |
| 221 | } |
| 222 | if err := registry.Register(listeners.NewFTPServerListener(cfg.BindIP, 21, 990, tlsConfig)); err != nil { |
| 223 | logger.Warn(fmt.Sprintf("Failed to register FTPServerListener: %v", err)) |
| 224 | } |
| 225 | if err := registry.Register(listeners.NewSFTPServerListener(cfg.BindIP, 22, sshHostKey)); err != nil { |
| 226 | logger.Warn(fmt.Sprintf("Failed to register SFTPServerListener: %v", err)) |
| 227 | } |
| 228 | if err := registry.Register(listeners.NewSMTPServerListener(cfg.BindIP, 25, 465, 587, tlsConfig)); err != nil { |
| 229 | logger.Warn(fmt.Sprintf("Failed to register SMTPServerListener: %v", err)) |
| 230 | } |
| 231 | if err := registry.Register(listeners.NewSMBServerListener(cfg.BindIP, 445, cfg.SMBMode)); err != nil { |
| 232 | logger.Warn(fmt.Sprintf("Failed to register SMBServerListener: %v", err)) |
| 233 | } |
| 234 | if err := registry.Register(listeners.NewSMBQUICServerListener(cfg.BindIP, 4430, tlsConfig)); err != nil { |
| 235 | logger.Warn(fmt.Sprintf("Failed to register SMBQUICServerListener: %v", err)) |
| 236 | } |
| 237 | if err := registry.Register(listeners.NewICMPServerListener(cfg.BindIP)); err != nil { |
| 238 | logger.Warn(fmt.Sprintf("Failed to register ICMPServerListener: %v", err)) |
| 239 | } |
| 240 | if err := registry.Register(listeners.NewNTPServerListener(cfg.BindIP, 123)); err != nil { |
| 241 | logger.Warn(fmt.Sprintf("Failed to register NTPServerListener: %v", err)) |
| 242 | } |
| 243 | if err := registry.Register(listeners.NewSyslogServerListener(cfg.BindIP, 514, 5140, 6514, tlsConfig)); err != nil { |
| 244 | logger.Warn(fmt.Sprintf("Failed to register SyslogServerListener: %v", err)) |
| 245 | } |
| 246 | if err := registry.Register(listeners.NewMQTTServerListener(cfg.BindIP, 1883, 8883, tlsConfig)); err != nil { |
| 247 | logger.Warn(fmt.Sprintf("Failed to register MQTTServerListener: %v", err)) |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | for _, l := range registry.GetAllListeners() { |
| 253 | engine.RegisterListener(l) |
| 254 | } |
| 255 | |
| 256 | multiplexPorts := registry.FilterMultiplexPorts(requestedPorts) |
| 257 | if len(multiplexPorts) > 0 { |
| 258 | portStrList := make([]string, len(multiplexPorts)) |
| 259 | for i, p := range multiplexPorts { |
| 260 | portStrList[i] = fmt.Sprintf("%d", p) |
| 261 | } |
| 262 | muxPorts := strings.Join(portStrList, ",") |
| 263 | |
| 264 | muxCfg := multiplexer.MultiplexerConfig{ |
| 265 | BindIP: cfg.BindIP, |
| 266 | Ports: muxPorts, |
| 267 | EnableTCP: cfg.EnableTCP, |
| 268 | EnableUDP: cfg.EnableUDP, |
| 269 | EnableEBPF: cfg.EnableEBPF, |
| 270 | PeekTimeout: cfg.PeekTimeout, |
| 271 | SocketTimeout: cfg.SocketTimeout, |
| 272 | } |
| 273 | mux, err := multiplexer.NewUserspaceMultiplexer(muxCfg, engine.GetLedger(), appLogger) |
| 274 | if err != nil { |
| 275 | return fmt.Errorf("failed to create userspace multiplexer: %w", err) |
| 276 | } |
| 277 | engine.SetMultiplexer(mux) |
| 278 | } |
| 279 | |
| 280 | ctx, cancel := context.WithCancel(context.Background()) |
| 281 | defer cancel() |
| 282 | |
| 283 | sigChan := make(chan os.Signal, 1) |
| 284 | signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) |
| 285 | go func() { |
| 286 | <-sigChan |
| 287 | appLogger.Info("Shutdown signal received, gracefully terminating server...") |
| 288 | cancel() |
| 289 | }() |
| 290 | |
| 291 | if err := engine.Start(ctx); err != nil { |
| 292 | return fmt.Errorf("failed to start server: %w", err) |
| 293 | } |
| 294 | |
| 295 | <-ctx.Done() |
| 296 | |
| 297 | shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) |
| 298 | defer shutdownCancel() |
| 299 | return engine.Shutdown(shutdownCtx) |
| 300 | } |
| 301 | |
| 302 | func main() { |
| 303 | if err := rootCmd.Execute(); err != nil { |
| 304 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) |
| 305 | os.Exit(1) |
| 306 | } |
| 307 | } |