● 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 / report / json.go
← Back to directory
352 lines · 10.5 KB
Raw
1package report
2
3import (
4 "encoding/json"
5 "fmt"
6 "strings"
7
8 "github.com/shehzade/contraband/pkg/common"
9)
10
11// ExportJSON generates a full machine-readable JSON document of the assessment.
12func ExportJSON(report *AssessmentReport) ([]byte, error) {
13 if report == nil {
14 return nil, fmt.Errorf("nil report provided")
15 }
16 return json.MarshalIndent(report, "", " ")
17}
18
19// -----------------------------------------------------------------------------
20// OASIS SARIF v2.1.0 Data Structures
21// -----------------------------------------------------------------------------
22
23type SARIFLog struct {
24 Schema string `json:"$schema"`
25 Version string `json:"version"`
26 Runs []SARIFRun `json:"runs"`
27}
28
29type SARIFRun struct {
30 Tool SARIFTool `json:"tool"`
31 Artifacts []SARIFArtifact `json:"artifacts,omitempty"`
32 Results []SARIFResult `json:"results"`
33}
34
35type SARIFTool struct {
36 Driver SARIFDriver `json:"driver"`
37}
38
39type SARIFDriver struct {
40 Name string `json:"name"`
41 FullName string `json:"fullName"`
42 Version string `json:"version"`
43 InformationURI string `json:"informationUri"`
44 Rules []SARIFRule `json:"rules"`
45}
46
47type SARIFRule struct {
48 ID string `json:"id"`
49 Name string `json:"name"`
50 ShortDescription SARIFMessage `json:"shortDescription"`
51 FullDescription SARIFMessage `json:"fullDescription"`
52 DefaultConfiguration SARIFRuleConfiguration `json:"defaultConfiguration"`
53 HelpURI string `json:"helpUri,omitempty"`
54}
55
56type SARIFRuleConfiguration struct {
57 Level string `json:"level"` // "error", "warning", "note"
58}
59
60type SARIFMessage struct {
61 Text string `json:"text"`
62}
63
64type SARIFLocation struct {
65 PhysicalLocation SARIFPhysicalLocation `json:"physicalLocation"`
66}
67
68type SARIFPhysicalLocation struct {
69 ArtifactLocation SARIFArtifactLocation `json:"artifactLocation"`
70 Region *SARIFRegion `json:"region,omitempty"`
71}
72
73type SARIFArtifactLocation struct {
74 URI string `json:"uri"`
75}
76
77type SARIFRegion struct {
78 StartLine int `json:"startLine"`
79}
80
81type SARIFArtifact struct {
82 Location SARIFArtifactLocation `json:"location"`
83}
84
85type SARIFResult struct {
86 RuleID string `json:"ruleId"`
87 Level string `json:"level"`
88 Message SARIFMessage `json:"message"`
89 Locations []SARIFLocation `json:"locations,omitempty"`
90 Properties map[string]interface{} `json:"properties,omitempty"`
91}
92
93// GetStandardSARIFRules returns the canonical rule catalog for Contraband.
94func GetStandardSARIFRules() []SARIFRule {
95 return []SARIFRule{
96 {
97 ID: "CTRB-001",
98 Name: "UnfilteredOutboundPort",
99 ShortDescription: SARIFMessage{
100 Text: "Unfiltered Outbound Layer 4 Port",
101 },
102 FullDescription: SARIFMessage{
103 Text: "An outbound Layer 4 TCP or UDP port is unfiltered by the perimeter firewall, permitting arbitrary egress traffic.",
104 },
105 DefaultConfiguration: SARIFRuleConfiguration{
106 Level: "warning",
107 },
108 HelpURI: "https://github.com/shehzade/contraband#remediation",
109 },
110 {
111 ID: "CTRB-002",
112 Name: "L7SmugglingSuccess",
113 ShortDescription: SARIFMessage{
114 Text: "Layer 7 Protocol Smuggling / Evasion Success",
115 },
116 FullDescription: SARIFMessage{
117 Text: "Data exfiltration succeeded over a non-standard Layer 7 protocol, uTLS masquerader, or covert channel, bypassing proxy and deep packet inspection.",
118 },
119 DefaultConfiguration: SARIFRuleConfiguration{
120 Level: "error",
121 },
122 HelpURI: "https://github.com/shehzade/contraband#remediation",
123 },
124 {
125 ID: "CTRB-003",
126 Name: "UninspectedDLPLeakage",
127 ShortDescription: SARIFMessage{
128 Text: "Uninspected Sensitive Data Exfiltration (DLP Interception Failure)",
129 },
130 FullDescription: SARIFMessage{
131 Text: "Mathematically valid sensitive secrets (PCI credit cards, PII SSNs, HIPAA records, or cloud API tokens) were exfiltrated without DLP interception.",
132 },
133 DefaultConfiguration: SARIFRuleConfiguration{
134 Level: "error",
135 },
136 HelpURI: "https://github.com/shehzade/contraband#remediation",
137 },
138 {
139 ID: "CTRB-004",
140 Name: "CleartextNetNTLMv2Exposure",
141 ShortDescription: SARIFMessage{
142 Text: "Outbound NetNTLMv2 Authentication Hash Exposure",
143 },
144 FullDescription: SARIFMessage{
145 Text: "Outbound SMB or WebDAV connection initiated an NTLMSSP handshake, leaking cleartext NetNTLMv2 authentication challenge-response hashes to an external collector.",
146 },
147 DefaultConfiguration: SARIFRuleConfiguration{
148 Level: "error",
149 },
150 HelpURI: "https://github.com/shehzade/contraband#remediation",
151 },
152 }
153}
154
155// ExportSARIF converts assessment findings into OASIS SARIF v2.1.0 standard format.
156func ExportSARIF(report *AssessmentReport) ([]byte, error) {
157 if report == nil {
158 return nil, fmt.Errorf("nil report provided")
159 }
160
161 version := report.Version
162 if version == "" {
163 version = common.Version
164 }
165
166 log := SARIFLog{
167 Schema: "https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/schemas/sarif-schema-2.1.0.json",
168 Version: "2.1.0",
169 Runs: []SARIFRun{
170 {
171 Tool: SARIFTool{
172 Driver: SARIFDriver{
173 Name: "Contraband",
174 FullName: "Contraband Network Egress Assessment Framework",
175 Version: version,
176 InformationURI: "https://github.com/shehzade/contraband",
177 Rules: GetStandardSARIFRules(),
178 },
179 },
180 Results: make([]SARIFResult, 0),
181 },
182 },
183 }
184
185 for _, probe := range report.Probes {
186 targetHost := probe.TargetHost
187 if targetHost == "" {
188 targetHost = report.TargetHost
189 }
190
191 // 1. Check for NetNTLMv2 Hash Exposure (CTRB-004)
192 if probe.CapturedHash != "" || probe.Protocol == "smb_hash" {
193 res := SARIFResult{
194 RuleID: "CTRB-004",
195 Level: "error",
196 Message: SARIFMessage{
197 Text: fmt.Sprintf("Outbound NetNTLMv2 authentication hash exposed via %s on port %d", probe.Protocol, probe.TargetPort),
198 },
199 Locations: []SARIFLocation{
200 {
201 PhysicalLocation: SARIFPhysicalLocation{
202 ArtifactLocation: SARIFArtifactLocation{
203 URI: fmt.Sprintf("network://%s:%d/%s", targetHost, probe.TargetPort, probe.Protocol),
204 },
205 },
206 },
207 },
208 Properties: map[string]interface{}{
209 "captured_hash": probe.CapturedHash,
210 "stage": probe.Stage,
211 "verdict": string(probe.Verdict),
212 },
213 }
214 log.Runs[0].Results = append(log.Runs[0].Results, res)
215 }
216
217 // Only generate vulnerability results for successful vectors
218 if probe.Verdict != common.VerdictSuccess {
219 continue
220 }
221
222 durationMs := float64(probe.Timestamps.TotalDuration.Microseconds()) / 1000.0
223 durationFormatted := fmt.Sprintf("%.2fms", durationMs)
224
225 // 2. DLP Secret Leakage (CTRB-003)
226 if probe.PayloadType != "" {
227 res := SARIFResult{
228 RuleID: "CTRB-003",
229 Level: "error",
230 Message: SARIFMessage{
231 Text: fmt.Sprintf("DLP failure: %s secret exfiltrated uninspected over %s port %d (%d bytes)",
232 strings.ToUpper(probe.PayloadType), probe.Protocol, probe.TargetPort, probe.BytesSent),
233 },
234 Locations: []SARIFLocation{
235 {
236 PhysicalLocation: SARIFPhysicalLocation{
237 ArtifactLocation: SARIFArtifactLocation{
238 URI: fmt.Sprintf("network://%s:%d/%s", targetHost, probe.TargetPort, probe.Protocol),
239 },
240 },
241 },
242 },
243 Properties: map[string]interface{}{
244 "payload_type": probe.PayloadType,
245 "carrier_type": probe.CarrierType,
246 "payload_hash": probe.PayloadHash,
247 "wire_hash": probe.WireHash,
248 "bytes_sent": probe.BytesSent,
249 "duration_ms": durationFormatted,
250 "ja4_string": probe.JA4String,
251 "raw_evidence": probe.RawEvidence,
252 "verdict": string(probe.Verdict),
253 },
254 }
255 log.Runs[0].Results = append(log.Runs[0].Results, res)
256 continue
257 }
258
259 // 3. Port Sweep Exposure (CTRB-001)
260 if probe.Stage == "sweep" || probe.Protocol == "tcp" || probe.Protocol == "udp" {
261 level := "warning"
262 switch probe.TargetPort {
263 case 22, 23, 135, 139, 445, 1433, 3389:
264 level = "error"
265 }
266
267 res := SARIFResult{
268 RuleID: "CTRB-001",
269 Level: level,
270 Message: SARIFMessage{
271 Text: fmt.Sprintf("Unfiltered outbound port %d/%s accessible through perimeter firewall (Latency: %s)",
272 probe.TargetPort, probe.Protocol, durationFormatted),
273 },
274 Locations: []SARIFLocation{
275 {
276 PhysicalLocation: SARIFPhysicalLocation{
277 ArtifactLocation: SARIFArtifactLocation{
278 URI: fmt.Sprintf("network://%s:%d/%s", targetHost, probe.TargetPort, probe.Protocol),
279 },
280 },
281 },
282 },
283 Properties: map[string]interface{}{
284 "target_port": probe.TargetPort,
285 "protocol": probe.Protocol,
286 "duration_ms": durationFormatted,
287 "verdict": string(probe.Verdict),
288 },
289 }
290 log.Runs[0].Results = append(log.Runs[0].Results, res)
291 continue
292 }
293
294 // 4. Layer 7 Smuggling / Evasion (CTRB-002)
295 res := SARIFResult{
296 RuleID: "CTRB-002",
297 Level: "error",
298 Message: SARIFMessage{
299 Text: fmt.Sprintf("Layer 7 exfiltration channel %s succeeded on port %d (TLS: %s, JA4: %s)",
300 probe.Protocol, probe.TargetPort, probe.TLSProfile, probe.JA4String),
301 },
302 Locations: []SARIFLocation{
303 {
304 PhysicalLocation: SARIFPhysicalLocation{
305 ArtifactLocation: SARIFArtifactLocation{
306 URI: fmt.Sprintf("network://%s:%d/%s", targetHost, probe.TargetPort, probe.Protocol),
307 },
308 },
309 },
310 },
311 Properties: map[string]interface{}{
312 "protocol": probe.Protocol,
313 "tls_profile": probe.TLSProfile,
314 "ja3_string": probe.JA3String,
315 "ja4_string": probe.JA4String,
316 "payload_hash": probe.PayloadHash,
317 "bytes_sent": probe.BytesSent,
318 "duration_ms": durationFormatted,
319 "verdict": string(probe.Verdict),
320 },
321 }
322 log.Runs[0].Results = append(log.Runs[0].Results, res)
323 }
324
325 for _, cred := range report.Credentials {
326 res := SARIFResult{
327 RuleID: "CTRB-004",
328 Level: "error",
329 Message: SARIFMessage{
330 Text: fmt.Sprintf("Outbound NetNTLMv2 authentication hash exposed for user %s\\%s", cred.Domain, cred.Username),
331 },
332 Locations: []SARIFLocation{
333 {
334 PhysicalLocation: SARIFPhysicalLocation{
335 ArtifactLocation: SARIFArtifactLocation{
336 URI: fmt.Sprintf("network://%s:445/%s", report.TargetHost, cred.Protocol),
337 },
338 },
339 },
340 },
341 Properties: map[string]interface{}{
342 "username": cred.Username,
343 "domain": cred.Domain,
344 "hash": cred.Hash,
345 "protocol": cred.Protocol,
346 },
347 }
348 log.Runs[0].Results = append(log.Runs[0].Results, res)
349 }
350
351 return json.MarshalIndent(log, "", " ")
352}