● 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
contraband / pkg / client / client.go
← Back to directory
279 lines · 7.6 KB
Raw
1package client
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "strconv"
8 "strings"
9 "time"
10
11 _ "github.com/shehzade/contraband/pkg/client/exfil/cloud"
12 _ "github.com/shehzade/contraband/pkg/client/exfil/covert"
13 _ "github.com/shehzade/contraband/pkg/client/exfil/dns"
14 _ "github.com/shehzade/contraband/pkg/client/exfil/file"
15 _ "github.com/shehzade/contraband/pkg/client/exfil/mail"
16 _ "github.com/shehzade/contraband/pkg/client/exfil/smb"
17 _ "github.com/shehzade/contraband/pkg/client/exfil/web"
18 "github.com/shehzade/contraband/pkg/common"
19 "github.com/shehzade/contraband/pkg/report"
20)
21
22// ClientConfig holds all CLI and programmatic configuration parameters for the client engine.
23type ClientConfig struct {
24 Server string `json:"server"`
25 Ports string `json:"ports"`
26 Port int `json:"port,omitempty"`
27 Protocols string `json:"protocols"`
28 DLPPayloads string `json:"dlp_payloads"`
29 CarrierType string `json:"carrier_type"`
30 Size string `json:"size"`
31 ChunkSize string `json:"chunk_size"`
32 Threads int `json:"threads"`
33 Throughput string `json:"throughput"`
34 Cadence string `json:"cadence"`
35 IntervalMin string `json:"interval_min"`
36 IntervalMax string `json:"interval_max"`
37 Transforms string `json:"transforms"`
38 Passphrase string `json:"passphrase"`
39 Stego string `json:"stego"`
40 TLSFingerprint string `json:"tls_fingerprint"`
41 Proxy string `json:"proxy"`
42 ProxyAuth string `json:"proxy_auth"`
43 Concurrency int `json:"concurrency"`
44 RateLimit int `json:"rate_limit"`
45 OutputJSON string `json:"output_json"`
46 OutputHTML string `json:"output_html"`
47 OutputSARIF string `json:"output_sarif"`
48 SyncReport string `json:"sync_report"`
49 Zone string `json:"zone"`
50 NoColor bool `json:"no_color"`
51 Destroy bool `json:"destroy"`
52 SavePayload bool `json:"save_payload"`
53 EvidenceDir string `json:"evidence_dir"`
54 DryRun bool `json:"dry_run"`
55 Seed int64 `json:"seed"`
56 Verbose bool `json:"verbose"`
57 JSON bool `json:"json"`
58}
59
60// DefaultClientConfig returns a ClientConfig populated with standard operational defaults.
61func DefaultClientConfig() ClientConfig {
62 return ClientConfig{
63 Server: "127.0.0.1",
64 Ports: "quick",
65 Port: 0,
66 Protocols: "all",
67 DLPPayloads: "all",
68 CarrierType: "csv",
69 Size: "1MB",
70 ChunkSize: "1MB",
71 Threads: 4,
72 Throughput: "unlimited",
73 Cadence: common.CadenceSteady,
74 IntervalMin: "500ms",
75 IntervalMax: "4s",
76 Transforms: "raw",
77 Stego: common.StegoNone,
78 TLSFingerprint: common.TLSFingerprintChrome,
79 Proxy: "auto",
80 ProxyAuth: "basic",
81 Concurrency: 100,
82 RateLimit: 500,
83 EvidenceDir: "evidence",
84 Zone: "corporate-default",
85 Seed: 0,
86 }
87}
88
89// DefaultPortForProtocol returns the standard port associated with a protocol identifier.
90func DefaultPortForProtocol(proto string) int {
91 switch proto {
92 case common.ProtoHTTP1, "http1", "http", common.ProtoWebDAV:
93 return 80
94 case common.ProtoHTTP2, "http2", "https", common.ProtoHTTP3, "http3", "quic", common.ProtoDoH, common.ProtoSMBQUIC, common.ProtoAWSS3, common.ProtoGCPGCS, common.ProtoAzureBlob:
95 return 443
96 case common.ProtoWebSocket, "websocket", "ws":
97 return 80
98 case common.ProtoGRPC, "grpc":
99 return 50051
100 case common.ProtoDNSA, common.ProtoDNSTXT, "dns":
101 return 53
102 case common.ProtoDoT, "dot":
103 return 853
104 case common.ProtoFTP:
105 return 21
106 case common.ProtoFTPS:
107 return 990
108 case common.ProtoSFTP:
109 return 22
110 case common.ProtoSMTP:
111 return 25
112 case common.ProtoSMBFile, common.ProtoSMBHash, "smb":
113 return 445
114 case common.ProtoICMPEcho, "icmp":
115 return 0
116 case common.ProtoNTPTime, "ntp":
117 return 123
118 case common.ProtoSyslog:
119 return 514
120 case common.ProtoMQTT:
121 return 1883
122 default:
123 return 80
124 }
125}
126
127// ResolveProtocols expands a protocol string ("all", category, or list) into a slice of protocol names.
128func ResolveProtocols(spec string) []string {
129 spec = strings.TrimSpace(strings.ToLower(spec))
130 if spec == "" || spec == "all" {
131 var list []string
132 order := []string{
133 common.CategoryWeb,
134 common.CategoryDNS,
135 common.CategoryFile,
136 common.CategoryMail,
137 common.CategorySMB,
138 common.CategoryCloud,
139 common.CategoryCovert,
140 }
141 for _, cat := range order {
142 list = append(list, common.CategoryMap[cat]...)
143 }
144 return list
145 }
146
147 if protos, ok := common.CategoryMap[spec]; ok {
148 return protos
149 }
150
151 parts := strings.Split(spec, ",")
152 var result []string
153 for _, p := range parts {
154 trimmed := strings.TrimSpace(p)
155 if trimmed != "" {
156 if protos, ok := common.CategoryMap[trimmed]; ok {
157 result = append(result, protos...)
158 } else {
159 result = append(result, trimmed)
160 }
161 }
162 }
163 return result
164}
165
166// RunAssessment coordinates the full 7-stage egress assessment workflow.
167func RunAssessment(ctx context.Context, cfg ClientConfig) (*report.AssessmentReport, error) {
168 logger := common.GetLogger()
169 startTime := time.Now().UTC()
170
171 // Apply defaults
172 if cfg.Server == "" {
173 cfg.Server = "127.0.0.1"
174 }
175 if cfg.Port > 0 && (cfg.Ports == "" || cfg.Ports == "quick") {
176 cfg.Ports = strconv.Itoa(cfg.Port)
177 }
178 if cfg.Ports == "" {
179 cfg.Ports = "quick"
180 }
181 if cfg.Protocols == "" {
182 cfg.Protocols = "all"
183 }
184 if cfg.DLPPayloads == "" {
185 cfg.DLPPayloads = "all"
186 }
187 if cfg.CarrierType == "" {
188 cfg.CarrierType = "csv"
189 }
190 if cfg.Size == "" {
191 cfg.Size = "1MB"
192 }
193 if cfg.ChunkSize == "" {
194 cfg.ChunkSize = "1MB"
195 }
196 if cfg.Cadence == "" {
197 cfg.Cadence = common.CadenceSteady
198 }
199 if cfg.TLSFingerprint == "" {
200 cfg.TLSFingerprint = common.TLSFingerprintChrome
201 }
202 if cfg.Proxy == "" {
203 cfg.Proxy = "auto"
204 }
205 if cfg.EvidenceDir == "" {
206 cfg.EvidenceDir = "evidence"
207 }
208 if cfg.Zone == "" {
209 cfg.Zone = "corporate-default"
210 }
211 if cfg.Concurrency <= 0 {
212 cfg.Concurrency = 100
213 }
214 if cfg.RateLimit < 0 {
215 cfg.RateLimit = 500
216 }
217
218 // If SavePayload is enabled, ensure evidence directory exists
219 if cfg.SavePayload {
220 if err := os.MkdirAll(cfg.EvidenceDir, 0755); err != nil {
221 return nil, fmt.Errorf("failed to create evidence directory %q: %w", cfg.EvidenceDir, err)
222 }
223 }
224
225 // Pre-flight dry-run validation
226 if cfg.DryRun {
227 logger.Info("[DRY-RUN] Pre-flight validation passed successfully. Exiting without transmission.")
228 return &report.AssessmentReport{
229 TargetHost: cfg.Server,
230 GeneratedAt: startTime,
231 }, nil
232 }
233
234 var allProbes []common.ProbeResult
235
236 // STAGE 1: Layer 4 Egress Port Matrix Sweep
237 sweepProbes, err := runStage1Sweep(ctx, cfg, logger)
238 if err != nil {
239 return nil, fmt.Errorf("stage 1 sweep failed: %w", err)
240 }
241 allProbes = append(allProbes, sweepProbes...)
242
243 // STAGE 2: Corporate Proxy Discovery & Traversal
244 fallbackEngine := runStage2Proxy(ctx, cfg, logger)
245
246 // STAGE 3: Traffic Shaper & Cadence Pacing
247 shaper, cadenceEngine := runStage3Shaping(ctx, cfg, logger)
248
249 // STAGE 4: Procedural Synthetic DLP Generation
250 s4, err := runStage4DLP(ctx, &cfg, logger)
251 if err != nil {
252 return nil, fmt.Errorf("stage 4 dlp synthesis failed: %w", err)
253 }
254
255 // STAGE 5: Evasion Transforms & Steganography
256 pipeline, hasEvasion := runStage5Evasion(cfg, s4.EffectiveSeed)
257
258 // STAGE 6: L7 Protocol Smuggling Matrix
259 exfilProbes, err := runStage6Exfil(
260 ctx,
261 cfg,
262 logger,
263 s4.TargetBytes,
264 s4.DLPConfig,
265 s4.ExpectedHash,
266 fallbackEngine,
267 shaper,
268 cadenceEngine,
269 pipeline,
270 hasEvasion,
271 )
272 if err != nil {
273 return nil, fmt.Errorf("stage 6 exfiltration failed: %w", err)
274 }
275 allProbes = append(allProbes, exfilProbes...)
276
277 // STAGE 7: Report Generation, Remediation, ANSI Table & Dashboard Sync
278 return runStage7Reporting(ctx, cfg, logger, allProbes, startTime)
279}