[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)
253 lines · 7.6 KB
| 1 | package soak |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | |
| 6 | "github.com/shehzade/contraband/pkg/common" |
| 7 | ) |
| 8 | |
| 9 | // Standard Multi-Zone Identifiers |
| 10 | const ( |
| 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. |
| 19 | func 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. |
| 30 | func 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) |
| 59 | const ( |
| 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. |
| 71 | func 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. |
| 82 | func ValidationVolumeTiers() []int64 { |
| 83 | return []int64{ |
| 84 | Volume50KB, |
| 85 | Volume500KB, |
| 86 | Volume5MB, |
| 87 | Volume50MB, |
| 88 | Volume100MB, |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // Proxy Modes |
| 93 | const ( |
| 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. |
| 102 | func AllProxyModes() []string { |
| 103 | return []string{ |
| 104 | ProxyDirect, |
| 105 | ProxyWPAD, |
| 106 | ProxyPAC, |
| 107 | ProxyAuthNTLM, |
| 108 | ProxyAuthBasic, |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Negative Test Injection Types |
| 113 | const ( |
| 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. |
| 121 | type 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). |
| 141 | func 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. |
| 152 | func 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 | } |