● 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)
Code 174 Commits 1
← Back to directory
271 lines · 11.5 KB
Raw
1package main
2
3import (
4 "context"
5 "fmt"
6 "math/rand"
7 "os"
8 "strconv"
9 "strings"
10
11 "github.com/shehzade/contraband/pkg/client"
12 "github.com/shehzade/contraband/pkg/common"
13 "github.com/shehzade/contraband/pkg/dryrun"
14 "github.com/spf13/cobra"
15)
16
17var (
18 flagConfig string
19 flagVerbose bool
20 flagJSON bool
21 flagSeed int64
22 flagDryRun bool
23
24 clientServer string
25 clientPorts string
26 clientProtocols string
27 clientDLP string
28 clientCarrierType string
29 clientSize string
30 clientChunkSize string
31 clientThreads int
32 clientThroughput string
33 clientCadence string
34 clientIntervalMin string
35 clientIntervalMax string
36 clientTransforms string
37 clientPassphrase string
38 clientStego string
39 clientTLSFingerprint string
40 clientProxy string
41 clientProxyAuth string
42 clientConcurrency int
43 clientRateLimit int
44 clientOutputJSON string
45 clientOutputHTML string
46 clientOutputSARIF string
47 clientDestroy bool
48 clientSavePayload bool
49 clientEvidenceDir string
50 clientRateAlias string
51 clientSyncReport string
52 clientZone string
53 clientNoColor bool
54
55 loadedConfig *common.ProfileConfig
56 appLogger common.Logger
57)
58
59var rootCmd = &cobra.Command{
60 Use: "contraband-client",
61 Short: "Contraband Standalone Egress Assessment Client",
62 Long: `Dedicated standalone client binary for automated network egress assessment,
63multi-protocol data smuggling, corporate proxy traversal, synthetic DLP verification,
64and forensic reporting.`,
65 SilenceUsage: true,
66 SilenceErrors: true,
67 PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
68 appLogger = common.GetLogger()
69 if flagJSON {
70 appLogger.SetMode(common.LogModeJSON)
71 }
72 if flagVerbose {
73 appLogger.SetLevel(common.LogLevelDebug)
74 }
75 if flagSeed != 0 {
76 rand.Seed(flagSeed)
77 appLogger.Debug(fmt.Sprintf("Initialized deterministic random seed: %d", flagSeed))
78 }
79 if flagConfig != "" {
80 cfg, err := common.LoadProfileConfig(flagConfig)
81 if err != nil {
82 return fmt.Errorf("failed to load configuration profile: %w", err)
83 }
84 loadedConfig = cfg
85 }
86 return nil
87 },
88 RunE: runClientStandalone,
89}
90
91func init() {
92 rootCmd.PersistentFlags().StringVarP(&flagConfig, "config", "c", "", "Path to YAML/JSON configuration profile")
93 rootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Enable verbose debug logging")
94 rootCmd.PersistentFlags().BoolVar(&flagJSON, "json", false, "Output results in structured JSON format")
95 rootCmd.PersistentFlags().Int64Var(&flagSeed, "seed", 0, "Deterministic random seed for reproducible runs")
96 rootCmd.PersistentFlags().BoolVar(&flagDryRun, "dry-run", false, "Pre-flight validation without transmitting live network traffic")
97
98 rootCmd.Flags().StringVarP(&clientServer, "server", "s", "127.0.0.1", "Target server IP or hostname")
99 rootCmd.Flags().StringVarP(&clientPorts, "ports", "p", "quick", "Port preset: 'quick', 'standard', 'full', or comma/range")
100 rootCmd.Flags().StringVar(&clientProtocols, "protocols", "all", "Protocols: 'all', category, or comma-separated list")
101 rootCmd.Flags().StringVar(&clientDLP, "dlp", "all", "Synthetic DLP payloads: 'all', 'pci', 'pii', 'hipaa', 'secrets'")
102 rootCmd.Flags().StringVar(&clientCarrierType, "carrier-type", "csv", "Procedural text carrier: 'csv', 'json', 'sql', 'email', 'syslog'")
103 rootCmd.Flags().StringVar(&clientSize, "size", "1MB", "Data volume to exfiltrate ('100KB', '50MB', '2GB')")
104 rootCmd.Flags().StringVar(&clientChunkSize, "chunk-size", "1MB", "Transfer chunk size ('64KB', '1MB')")
105 rootCmd.Flags().IntVar(&clientThreads, "threads", 4, "Concurrent worker streams (1–64)")
106 rootCmd.Flags().StringVar(&clientThroughput, "throughput", "unlimited", "Outbound rate limit ('100KB/s', '5MB/s', 'unlimited')")
107 rootCmd.Flags().StringVar(&clientCadence, "cadence", "steady", "Traffic pacing: 'burst', 'steady', 'jittered', 'office-hours'")
108 rootCmd.Flags().StringVar(&clientIntervalMin, "interval-min", "500ms", "Minimum jitter sleep interval")
109 rootCmd.Flags().StringVar(&clientIntervalMax, "interval-max", "4s", "Maximum jitter sleep interval")
110 rootCmd.Flags().StringVar(&clientTransforms, "transforms", "raw", "Evasion chain: comma-separated 'raw', 'base64', 'hex', 'gzip', 'zstd', 'aes_gcm'")
111 rootCmd.Flags().StringVar(&clientPassphrase, "passphrase", "", "Passphrase for AES-256-GCM encryption")
112 rootCmd.Flags().StringVar(&clientStego, "stego", "none", "Steganographic carrier: 'none', 'bmp', 'png', 'wav', 'jpeg-zip', 'pdf-jar'")
113 rootCmd.Flags().StringVar(&clientTLSFingerprint, "tls-fingerprint", "chrome", "uTLS Client Hello: 'chrome', 'edge', 'safari', 'firefox', 'curl', 'default'")
114 rootCmd.Flags().StringVar(&clientProxy, "proxy", "auto", "Proxy traversal: 'auto', 'direct', or URL")
115 rootCmd.Flags().StringVar(&clientProxyAuth, "proxy-auth", "basic", "Proxy authentication: 'basic', 'ntlm', 'negotiate'")
116 rootCmd.Flags().IntVar(&clientConcurrency, "concurrency", 100, "Sweep worker pool concurrency")
117 rootCmd.Flags().IntVar(&clientRateLimit, "rate-limit", 500, "Maximum sweep packets per second")
118 rootCmd.Flags().StringVar(&clientOutputJSON, "output-json", "", "Destination file for full JSON results")
119 rootCmd.Flags().StringVar(&clientOutputHTML, "output-html", "", "Destination file for interactive zero-CDN HTML dashboard")
120 rootCmd.Flags().StringVar(&clientOutputSARIF, "output-sarif", "", "Destination file for SARIF v2.1.0 report")
121 rootCmd.Flags().StringVar(&clientSyncReport, "sync-report", "", "URL of live dashboard server to synchronize report to (e.g. http://10.0.0.1:8080)")
122 rootCmd.Flags().StringVar(&clientZone, "zone", "corporate-default", "Network zone or segment identifier for multi-zone telemetry")
123 rootCmd.Flags().BoolVar(&clientNoColor, "no-color", false, "Disable ANSI color formatting in terminal output")
124 rootCmd.Flags().BoolVar(&clientDestroy, "destroy", false, "Auto-cleanup uploaded objects in cloud storage")
125 rootCmd.Flags().BoolVar(&clientSavePayload, "save-payload", false, "Physically retain full exfiltrated payload on client disk")
126 rootCmd.Flags().StringVar(&clientEvidenceDir, "evidence-dir", "evidence", "Directory to store reconstructed exfiltration payloads")
127
128 // Operator flag aliases
129 rootCmd.Flags().StringVar(&clientServer, "target", "127.0.0.1", "Alias for --server")
130 rootCmd.Flags().StringVar(&clientRateAlias, "rate", "", "Alias for --throughput (e.g. '10MB/s') or --rate-limit (e.g. 500)")
131 rootCmd.Flags().StringVar(&clientThroughput, "bandwidth", "unlimited", "Alias for --throughput")
132 rootCmd.Flags().StringVar(&clientTLSFingerprint, "utls", "chrome", "Alias for --tls-fingerprint")
133 rootCmd.Flags().StringVar(&clientIntervalMax, "jitter", "4s", "Alias for --interval-max")
134 rootCmd.Flags().StringVar(&clientIntervalMax, "timing-jitter", "4s", "Alias for --interval-max")
135 rootCmd.Flags().StringVar(&clientOutputJSON, "output", "", "Alias for --output-json")
136 rootCmd.Flags().StringVar(&clientEvidenceDir, "report-dir", "evidence", "Alias for --evidence-dir")
137
138 rootCmd.AddCommand(&cobra.Command{
139 Use: "version",
140 Short: "Print client version",
141 Run: func(cmd *cobra.Command, args []string) {
142 fmt.Printf("Contraband Client v%s (Pure Go, CGO_ENABLED=0)\n", common.Version)
143 },
144 })
145}
146
147func runClientStandalone(cmd *cobra.Command, args []string) error {
148 cfg := client.DefaultClientConfig()
149
150 cfg.Server = clientServer
151 cfg.Ports = clientPorts
152 cfg.Protocols = clientProtocols
153 cfg.DLPPayloads = clientDLP
154 cfg.CarrierType = clientCarrierType
155 cfg.Size = clientSize
156 cfg.ChunkSize = clientChunkSize
157 cfg.Threads = clientThreads
158 cfg.Throughput = clientThroughput
159 cfg.Cadence = clientCadence
160 cfg.IntervalMin = clientIntervalMin
161 cfg.IntervalMax = clientIntervalMax
162 cfg.Transforms = clientTransforms
163 cfg.Passphrase = clientPassphrase
164 cfg.Stego = clientStego
165 cfg.TLSFingerprint = clientTLSFingerprint
166 cfg.Proxy = clientProxy
167 cfg.ProxyAuth = clientProxyAuth
168 cfg.Concurrency = clientConcurrency
169 cfg.RateLimit = clientRateLimit
170 cfg.OutputJSON = clientOutputJSON
171 cfg.OutputHTML = clientOutputHTML
172 cfg.OutputSARIF = clientOutputSARIF
173 cfg.SyncReport = clientSyncReport
174 cfg.Zone = clientZone
175 cfg.NoColor = clientNoColor
176 cfg.Destroy = clientDestroy
177 cfg.SavePayload = clientSavePayload
178 cfg.EvidenceDir = clientEvidenceDir
179 cfg.Seed = flagSeed
180
181 // CLI alias overrides
182 if cmd.Flags().Changed("target") {
183 cfg.Server = clientServer
184 }
185 if cmd.Flags().Changed("rate") {
186 if val, err := strconv.Atoi(clientRateAlias); err == nil {
187 cfg.RateLimit = val
188 clientRateLimit = val
189 } else if strings.HasSuffix(strings.ToLower(clientRateAlias), "/s") || strings.HasSuffix(strings.ToLower(clientRateAlias), "/sec") || strings.ToLower(clientRateAlias) == "unlimited" {
190 if _, err := common.ParseBandwidthRate(clientRateAlias); err != nil {
191 return fmt.Errorf("invalid bandwidth rate %q: %w", clientRateAlias, err)
192 }
193 cfg.Throughput = clientRateAlias
194 clientThroughput = clientRateAlias
195 } else {
196 return fmt.Errorf("invalid argument %q for \"--rate\" flag: strconv.ParseInt: parsing %q: invalid syntax", clientRateAlias, clientRateAlias)
197 }
198 }
199 if cmd.Flags().Changed("bandwidth") {
200 cfg.Throughput = clientThroughput
201 }
202 if cmd.Flags().Changed("utls") {
203 cfg.TLSFingerprint = clientTLSFingerprint
204 }
205 if cmd.Flags().Changed("jitter") || cmd.Flags().Changed("timing-jitter") {
206 cfg.IntervalMax = clientIntervalMax
207 }
208 if cmd.Flags().Changed("output") {
209 cfg.OutputJSON = clientOutputJSON
210 }
211 if cmd.Flags().Changed("report-dir") {
212 cfg.EvidenceDir = clientEvidenceDir
213 }
214
215 if loadedConfig != nil {
216 if loadedConfig.Target.Server != "" && !cmd.Flags().Changed("server") && !cmd.Flags().Changed("target") {
217 cfg.Server = loadedConfig.Target.Server
218 }
219 if loadedConfig.Target.Ports != "" && !cmd.Flags().Changed("ports") {
220 cfg.Ports = loadedConfig.Target.Ports
221 }
222 if len(loadedConfig.Target.Protocols) > 0 && !cmd.Flags().Changed("protocols") {
223 cfg.Protocols = strings.Join(loadedConfig.Target.Protocols, ",")
224 }
225 if len(loadedConfig.DLP.Payloads) > 0 && !cmd.Flags().Changed("dlp") {
226 cfg.DLPPayloads = strings.Join(loadedConfig.DLP.Payloads, ",")
227 }
228 if loadedConfig.DLP.CarrierType != "" && !cmd.Flags().Changed("carrier-type") {
229 cfg.CarrierType = loadedConfig.DLP.CarrierType
230 }
231 if loadedConfig.DLP.Size != "" && !cmd.Flags().Changed("size") {
232 cfg.Size = loadedConfig.DLP.Size
233 }
234 if loadedConfig.Traffic.Threads > 0 && !cmd.Flags().Changed("threads") {
235 cfg.Threads = loadedConfig.Traffic.Threads
236 }
237 if loadedConfig.Traffic.Throughput != "" && !cmd.Flags().Changed("throughput") && !cmd.Flags().Changed("bandwidth") && !cmd.Flags().Changed("rate") {
238 cfg.Throughput = loadedConfig.Traffic.Throughput
239 }
240 if loadedConfig.Sweep.RateLimit > 0 && !cmd.Flags().Changed("rate-limit") && !cmd.Flags().Changed("rate") {
241 cfg.RateLimit = loadedConfig.Sweep.RateLimit
242 }
243 if loadedConfig.Traffic.Cadence != "" && !cmd.Flags().Changed("cadence") {
244 cfg.Cadence = loadedConfig.Traffic.Cadence
245 }
246 if loadedConfig.Proxy.Mode != "" && !cmd.Flags().Changed("proxy") {
247 cfg.Proxy = loadedConfig.Proxy.Mode
248 }
249 if loadedConfig.Output.JSONPath != "" && !cmd.Flags().Changed("output-json") && !cmd.Flags().Changed("output") {
250 cfg.OutputJSON = loadedConfig.Output.JSONPath
251 }
252 if loadedConfig.Output.HTMLPath != "" && !cmd.Flags().Changed("output-html") {
253 cfg.OutputHTML = loadedConfig.Output.HTMLPath
254 }
255 }
256
257 if flagDryRun {
258 return dryrun.RunClientDryRun(cfg)
259 }
260
261 ctx := context.Background()
262 _, err := client.RunAssessment(ctx, cfg)
263 return err
264}
265
266func main() {
267 if err := rootCmd.Execute(); err != nil {
268 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
269 os.Exit(1)
270 }
271}