● 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 / soak / matrix.go
← Back to directory
253 lines · 7.6 KB
Raw
1package soak
2
3import (
4 "fmt"
5
6 "github.com/shehzade/contraband/pkg/common"
7)
8
9// Standard Multi-Zone Identifiers
10const (
11 ZoneLANCorp = "zone-lan-corp"
12 ZoneDMZ = "zone-dmz"
13 ZonePCIDSS = "zone-pci-dss"
14 ZoneCloudEast = "zone-cloud-east"
15 ZoneBranchOffice = "zone-branch-office"
16)
17
18// AllZones returns the complete set of 5 concurrent enterprise client zones.
19func AllZones() []string {
20 return []string{
21 ZoneLANCorp,
22 ZoneDMZ,
23 ZonePCIDSS,
24 ZoneCloudEast,
25 ZoneBranchOffice,
26 }
27}
28
29// AllSoakProtocols returns all 20+ L7 smuggling protocols supported by Contraband.
30func AllSoakProtocols() []string {
31 return []string{
32 common.ProtoHTTP1, // HTTP/1.1 POST smuggling
33 common.ProtoHTTP2, // HTTP/2 over TLS
34 common.ProtoHTTP3, // HTTP/3 over QUIC
35 common.ProtoWebSocket, // WebSocket binary framing
36 common.ProtoGRPC, // gRPC / HTTP/2 Protobuf streams
37 common.ProtoDNSTXT, // DNS TXT record tunneling
38 common.ProtoDNSA, // DNS A / CNAME / NULL tunneling
39 common.ProtoICMPEcho, // ICMP Echo covert carrier
40 common.ProtoSMTP, // ESMTP DATA MIME smuggling
41 common.ProtoDoH, // DNS over HTTPS
42 common.ProtoDoT, // DNS over TLS
43 common.ProtoSFTP, // SSH / SFTP subsystem channel
44 common.ProtoFTP, // FTP passive channel
45 common.ProtoFTPS, // Explicit FTPS
46 common.ProtoSMBFile, // SMB2/3 File Transfer
47 common.ProtoSMBQUIC, // SMB over QUIC
48 common.ProtoWebDAV, // HTTP WebDAV PUT / PROPFIND
49 common.ProtoNTPTime, // NTP timestamp fraction steganography
50 common.ProtoSyslog, // Syslog RFC 5424 structured exfiltration
51 common.ProtoMQTT, // MQTT 3.1.1 QoS0/1 binary payloads
52 common.ProtoAWSS3, // S3 API REST PUT object
53 common.ProtoGCPGCS, // GCP Cloud Storage REST API
54 common.ProtoAzureBlob, // Azure Blob Storage REST API
55 }
56}
57
58// Progressive Volume Spectrum (in bytes)
59const (
60 Volume50KB int64 = 50 * 1024
61 Volume500KB int64 = 500 * 1024
62 Volume5MB int64 = 5 * 1024 * 1024
63 Volume50MB int64 = 50 * 1024 * 1024
64 Volume100MB int64 = 100 * 1024 * 1024
65 Volume500MB int64 = 500 * 1024 * 1024
66 Volume1GB int64 = 1024 * 1024 * 1024
67 Volume5GB int64 = 5 * 1024 * 1024 * 1024
68)
69
70// AllVolumeTiers returns the progressive large transfer volume spectrum for soak testing.
71func AllVolumeTiers() []int64 {
72 return []int64{
73 Volume50MB,
74 Volume100MB,
75 Volume500MB,
76 Volume1GB,
77 Volume5GB,
78 }
79}
80
81// ValidationVolumeTiers returns micro, medium, and bulk tiers for pre-soak sanity validation.
82func ValidationVolumeTiers() []int64 {
83 return []int64{
84 Volume50KB,
85 Volume500KB,
86 Volume5MB,
87 Volume50MB,
88 Volume100MB,
89 }
90}
91
92// Proxy Modes
93const (
94 ProxyDirect = "direct"
95 ProxyWPAD = "wpad"
96 ProxyPAC = "pac"
97 ProxyAuthNTLM = "auth_ntlm"
98 ProxyAuthBasic = "auth_basic"
99)
100
101// AllProxyModes returns all corporate proxy traversal profiles.
102func AllProxyModes() []string {
103 return []string{
104 ProxyDirect,
105 ProxyWPAD,
106 ProxyPAC,
107 ProxyAuthNTLM,
108 ProxyAuthBasic,
109 }
110}
111
112// Negative Test Injection Types
113const (
114 NegativeNone = ""
115 NegativeL4 = "L4" // Network drop, closed port, timeout -> BLOCKED_L4
116 NegativeL7 = "L7" // TLS reset, proxy 403, invalid verb -> BLOCKED_L7
117 NegativeDLP = "DLP" // Corrupted SHA-256 rolling hash, tampering -> BLOCKED_DLP
118)
119
120// Scenario encapsulates an execution permutation in the soak testing matrix.
121type Scenario struct {
122 ID string `json:"id"`
123 Name string `json:"name"`
124 Zone string `json:"zone"`
125 Protocol string `json:"protocol"`
126 VolumeBytes int64 `json:"volume_bytes"`
127 VolumeStr string `json:"volume_str"`
128 DLPType string `json:"dlp_type"`
129 CarrierType string `json:"carrier_type"`
130 Stego string `json:"stego"`
131 Transforms string `json:"transforms"`
132 Cadence string `json:"cadence"`
133 TLSFingerprint string `json:"tls_fingerprint"`
134 ProxyMode string `json:"proxy_mode"`
135 IsNegative bool `json:"is_negative"`
136 NegativeType string `json:"negative_type,omitempty"`
137 ExpectedVerdict common.Verdict `json:"expected_verdict"`
138}
139
140// IsCovertProtocol returns true if the protocol is a low-bandwidth datagram or covert query tunnel (DNS, DoH, DoT, ICMP, NTP, Syslog, MQTT).
141func IsCovertProtocol(proto string) bool {
142 switch proto {
143 case common.ProtoDNSTXT, common.ProtoDNSA, common.ProtoDoH, common.ProtoDoT,
144 common.ProtoICMPEcho, common.ProtoNTPTime, common.ProtoSyslog, common.ProtoMQTT:
145 return true
146 default:
147 return false
148 }
149}
150
151// GenerateScenarioMatrix synthesizes the full multi-scenario matrix for the soak engine.
152func GenerateScenarioMatrix(volumes []int64) []Scenario {
153 if len(volumes) == 0 {
154 volumes = AllVolumeTiers()
155 }
156
157 zones := AllZones()
158 protocols := AllSoakProtocols()
159 dlpTypes := common.AllDLPTypes
160 carrierTypes := common.AllCarrierTypes
161 stegoCarriers := []string{common.StegoNone, common.StegoPNG, common.StegoJPEG, common.StegoPDF, common.StegoZIP}
162 transforms := []string{
163 common.TransformRaw,
164 common.TransformBase64,
165 common.TransformHex,
166 common.TransformGzip,
167 common.TransformZlib,
168 common.TransformZstd,
169 common.TransformAESGCM,
170 }
171 cadences := common.AllCadenceProfiles
172 fingerprints := common.AllTLSFingerprints
173 proxies := AllProxyModes()
174
175 var matrix []Scenario
176 seq := 1
177
178 for pIdx, proto := range protocols {
179 for vIdx, vol := range volumes {
180 effectiveVol := vol
181 if IsCovertProtocol(proto) && effectiveVol > Volume50KB {
182 effectiveVol = Volume50KB
183 }
184 zone := zones[(pIdx+vIdx)%len(zones)]
185 dlpType := dlpTypes[(pIdx+vIdx)%len(dlpTypes)]
186 carrier := carrierTypes[(pIdx+vIdx)%len(carrierTypes)]
187 stego := stegoCarriers[(pIdx+vIdx)%len(stegoCarriers)]
188 xform := transforms[(pIdx+vIdx)%len(transforms)]
189 cadence := cadences[(pIdx+vIdx)%len(cadences)]
190 fp := fingerprints[(pIdx+vIdx)%len(fingerprints)]
191 proxy := proxies[(pIdx+vIdx)%len(proxies)]
192
193 volStr := common.FormatBytes(effectiveVol)
194 sc := Scenario{
195 ID: fmt.Sprintf("SC-%04d", seq),
196 Name: fmt.Sprintf("%s_%s_%s_%s", zone, proto, volStr, dlpType),
197 Zone: zone,
198 Protocol: proto,
199 VolumeBytes: effectiveVol,
200 VolumeStr: volStr,
201 DLPType: dlpType,
202 CarrierType: carrier,
203 Stego: stego,
204 Transforms: xform,
205 Cadence: cadence,
206 TLSFingerprint: fp,
207 ProxyMode: proxy,
208 IsNegative: false,
209 ExpectedVerdict: common.VerdictSuccess,
210 }
211 matrix = append(matrix, sc)
212 seq++
213 }
214 }
215
216 // Add Negative Testing Scenarios
217 negativeTypes := []struct {
218 negType string
219 verdict common.Verdict
220 name string
221 }{
222 {NegativeL4, common.VerdictBlockedL4, "Simulated_L4_Network_Drop_RST"},
223 {NegativeL7, common.VerdictBlockedL7, "Simulated_L7_Proxy403_TLS_Rejection"},
224 {NegativeDLP, common.VerdictBlockedDLP, "Simulated_DLP_Hash_Tampering_Interception"},
225 }
226
227 for _, neg := range negativeTypes {
228 for _, zone := range zones {
229 sc := Scenario{
230 ID: fmt.Sprintf("SC-NEG-%04d", seq),
231 Name: fmt.Sprintf("%s_%s", zone, neg.name),
232 Zone: zone,
233 Protocol: common.ProtoHTTP2,
234 VolumeBytes: Volume50KB,
235 VolumeStr: "50KB",
236 DLPType: common.DLPTypePCI,
237 CarrierType: common.CarrierCSV,
238 Stego: common.StegoNone,
239 Transforms: common.TransformRaw,
240 Cadence: common.CadenceSteady,
241 TLSFingerprint: common.TLSFingerprintChrome,
242 ProxyMode: ProxyDirect,
243 IsNegative: true,
244 NegativeType: neg.negType,
245 ExpectedVerdict: neg.verdict,
246 }
247 matrix = append(matrix, sc)
248 seq++
249 }
250 }
251
252 return matrix
253}