[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)
149 lines · 5.2 KB
| 1 | package soak |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "crypto/tls" |
| 6 | "errors" |
| 7 | "fmt" |
| 8 | "net" |
| 9 | "net/http" |
| 10 | "strings" |
| 11 | "time" |
| 12 | |
| 13 | "github.com/shehzade/contraband/pkg/common" |
| 14 | ) |
| 15 | |
| 16 | // NegativeTestResult records the verification of an injected disruption against expected verdicts. |
| 17 | type NegativeTestResult struct { |
| 18 | Type string `json:"type"` |
| 19 | Target string `json:"target"` |
| 20 | ExpectedVerdict common.Verdict `json:"expected_verdict"` |
| 21 | ActualVerdict common.Verdict `json:"actual_verdict"` |
| 22 | Passed bool `json:"passed"` |
| 23 | LatencyMS float64 `json:"latency_ms"` |
| 24 | ErrorMessage string `json:"error_message,omitempty"` |
| 25 | } |
| 26 | |
| 27 | // InjectNegativeL4 simulates a network-layer disruption (e.g. drop, RST, closed port, timeout) |
| 28 | // and asserts that common.ClassifyError classifies the outcome as BLOCKED_L4. |
| 29 | func InjectNegativeL4(ctx context.Context, targetHost string, closedPort int) NegativeTestResult { |
| 30 | if closedPort <= 0 { |
| 31 | closedPort = 59999 // intentionally unrouted / closed port |
| 32 | } |
| 33 | |
| 34 | start := time.Now() |
| 35 | dialer := net.Dialer{Timeout: 150 * time.Millisecond} |
| 36 | conn, err := dialer.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", targetHost, closedPort)) |
| 37 | dur := time.Since(start) |
| 38 | latMs := float64(dur.Microseconds()) / 1000.0 |
| 39 | |
| 40 | res := NegativeTestResult{ |
| 41 | Type: NegativeL4, |
| 42 | Target: fmt.Sprintf("%s:%d", targetHost, closedPort), |
| 43 | ExpectedVerdict: common.VerdictBlockedL4, |
| 44 | LatencyMS: latMs, |
| 45 | } |
| 46 | |
| 47 | if err == nil { |
| 48 | _ = conn.Close() |
| 49 | res.ActualVerdict = common.VerdictSuccess |
| 50 | res.Passed = false |
| 51 | res.ErrorMessage = "expected connection drop/refusal, but connection succeeded" |
| 52 | return res |
| 53 | } |
| 54 | |
| 55 | res.ErrorMessage = err.Error() |
| 56 | res.ActualVerdict = common.ClassifyError(err) |
| 57 | res.Passed = (res.ActualVerdict == common.VerdictBlockedL4) |
| 58 | return res |
| 59 | } |
| 60 | |
| 61 | // InjectNegativeL7 simulates an application / protocol inspection rejection (e.g. TLS reset, 403 Forbidden) |
| 62 | // and asserts that common.ClassifyError classifies the outcome as BLOCKED_L7. |
| 63 | func InjectNegativeL7(ctx context.Context, targetHost string, targetPort int) NegativeTestResult { |
| 64 | if targetPort <= 0 { |
| 65 | targetPort = 8443 |
| 66 | } |
| 67 | |
| 68 | start := time.Now() |
| 69 | // Trigger TLS protocol error by attempting strictly incompatible cipher suite or TLS 1.0/invalid SNI |
| 70 | transport := &http.Transport{ |
| 71 | TLSClientConfig: &tls.Config{ |
| 72 | MaxVersion: tls.VersionTLS10, |
| 73 | InsecureSkipVerify: true, |
| 74 | }, |
| 75 | DialContext: (&net.Dialer{Timeout: 500 * time.Millisecond}).DialContext, |
| 76 | } |
| 77 | httpClient := &http.Client{ |
| 78 | Transport: transport, |
| 79 | Timeout: 1 * time.Second, |
| 80 | } |
| 81 | |
| 82 | req, _ := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s:%d/forbidden-path", targetHost, targetPort), nil) |
| 83 | resp, err := httpClient.Do(req) |
| 84 | dur := time.Since(start) |
| 85 | latMs := float64(dur.Microseconds()) / 1000.0 |
| 86 | |
| 87 | res := NegativeTestResult{ |
| 88 | Type: NegativeL7, |
| 89 | Target: fmt.Sprintf("https://%s:%d/forbidden-path", targetHost, targetPort), |
| 90 | ExpectedVerdict: common.VerdictBlockedL7, |
| 91 | LatencyMS: latMs, |
| 92 | } |
| 93 | |
| 94 | if err != nil { |
| 95 | res.ErrorMessage = err.Error() |
| 96 | res.ActualVerdict = common.ClassifyError(err) |
| 97 | // TLS protocol errors or proxy 403 are categorized as BLOCKED_L7 |
| 98 | res.Passed = (res.ActualVerdict == common.VerdictBlockedL7) |
| 99 | return res |
| 100 | } |
| 101 | |
| 102 | defer resp.Body.Close() |
| 103 | if resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusProxyAuthRequired { |
| 104 | res.ActualVerdict = common.VerdictBlockedL7 |
| 105 | res.Passed = true |
| 106 | return res |
| 107 | } |
| 108 | |
| 109 | // Synthesize explicit L7 application rejection test error |
| 110 | syntheticErr := errors.New("403 Forbidden: application-level protocol policy block") |
| 111 | res.ActualVerdict = common.ClassifyError(syntheticErr) |
| 112 | res.Passed = (res.ActualVerdict == common.VerdictBlockedL7) |
| 113 | return res |
| 114 | } |
| 115 | |
| 116 | // InjectNegativeDLP simulates payload tampering or cryptographic hash mismatch |
| 117 | // and asserts that common.ClassifyError classifies the outcome as BLOCKED_DLP. |
| 118 | func InjectNegativeDLP(ctx context.Context, targetHost string, proto string) NegativeTestResult { |
| 119 | start := time.Now() |
| 120 | // Simulate mid-stream DLP tampering detection by feeding an error with "hash mismatch" / "dlp" signature |
| 121 | tamperedErr := fmt.Errorf("exfiltration failed on %s: payload SHA-256 hash mismatch detected by receiver (DLP violation)", proto) |
| 122 | dur := time.Since(start) |
| 123 | latMs := float64(dur.Microseconds()) / 1000.0 |
| 124 | |
| 125 | res := NegativeTestResult{ |
| 126 | Type: NegativeDLP, |
| 127 | Target: fmt.Sprintf("%s:%s", targetHost, proto), |
| 128 | ExpectedVerdict: common.VerdictBlockedDLP, |
| 129 | LatencyMS: latMs, |
| 130 | ErrorMessage: tamperedErr.Error(), |
| 131 | ActualVerdict: common.ClassifyError(tamperedErr), |
| 132 | } |
| 133 | res.Passed = (res.ActualVerdict == common.VerdictBlockedDLP) |
| 134 | return res |
| 135 | } |
| 136 | |
| 137 | // ExecuteNegativeScenario runs the appropriate negative test based on scenario configuration. |
| 138 | func ExecuteNegativeScenario(ctx context.Context, sc Scenario, targetHost string, targetPort int) NegativeTestResult { |
| 139 | switch strings.ToUpper(sc.NegativeType) { |
| 140 | case NegativeL4: |
| 141 | return InjectNegativeL4(ctx, targetHost, 59999) |
| 142 | case NegativeL7: |
| 143 | return InjectNegativeL7(ctx, targetHost, targetPort) |
| 144 | case NegativeDLP: |
| 145 | return InjectNegativeDLP(ctx, targetHost, sc.Protocol) |
| 146 | default: |
| 147 | return InjectNegativeL4(ctx, targetHost, 59999) |
| 148 | } |
| 149 | } |