● 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 / dlp / stream.go
← Back to directory
185 lines · 4.1 KB
Raw
1package dlp
2
3import (
4 "crypto/sha256"
5 "encoding/hex"
6 "hash"
7 "io"
8 "math/rand"
9 "strings"
10 "sync"
11 "time"
12)
13
14const (
15 StreamChunkSize = 64 * 1024 // 64KB chunk buffer
16)
17
18type GeneratorConfig struct {
19 DLPType string // pci, ssn, hipaa, keys, pii, all
20 CarrierType string // csv, json, sql, email, syslog, noise
21 Domain string // e.g. acme-corp.internal
22 MinEntropy float64 // default 3.5
23 MaxEntropy float64 // default 5.5
24 Seed int64 // deterministic seed (0 = random)
25 FormatStyle FormatStyle // raw, hyphenated, space
26}
27
28type DLPStreamer struct {
29 cfg GeneratorConfig
30 targetBytes int64
31 bytesRead int64
32 rng *rand.Rand
33 hasher hash.Hash
34 buf []byte
35 bufOffset int
36 curBufPtr *[]byte
37 pool *sync.Pool
38 tuner *EntropyTuner
39 closed bool
40 headerSent bool
41}
42
43// NewDLPStreamer creates a memory-bounded streaming io.Reader.
44func NewDLPStreamer(targetBytes int64, cfg GeneratorConfig) *DLPStreamer {
45 seed := cfg.Seed
46 if seed == 0 {
47 seed = time.Now().UnixNano()
48 }
49
50 minEnt := cfg.MinEntropy
51 maxEnt := cfg.MaxEntropy
52 if minEnt <= 0 {
53 minEnt = 3.5
54 }
55 if maxEnt <= 0 {
56 maxEnt = 5.5
57 }
58
59 return &DLPStreamer{
60 cfg: cfg,
61 targetBytes: targetBytes,
62 rng: rand.New(rand.NewSource(seed)),
63 hasher: sha256.New(),
64 tuner: NewEntropyTuner(minEnt, maxEnt),
65 pool: &sync.Pool{
66 New: func() any {
67 b := make([]byte, StreamChunkSize)
68 return &b
69 },
70 },
71 }
72}
73
74// Read satisfies io.Reader, generating streaming data on the fly.
75func (s *DLPStreamer) Read(p []byte) (int, error) {
76 if s.closed {
77 return 0, io.EOF
78 }
79 if s.bytesRead >= s.targetBytes {
80 return 0, io.EOF
81 }
82
83 remainingTotal := s.targetBytes - s.bytesRead
84 maxToRead := int64(len(p))
85 if maxToRead > remainingTotal {
86 maxToRead = remainingTotal
87 }
88
89 totalWritten := 0
90
91 for totalWritten < int(maxToRead) {
92 if s.buf == nil || s.bufOffset >= len(s.buf) {
93 s.generateNextChunk()
94 }
95
96 avail := len(s.buf) - s.bufOffset
97 want := int(maxToRead) - totalWritten
98 toCopy := avail
99 if toCopy > want {
100 toCopy = want
101 }
102
103 copy(p[totalWritten:totalWritten+toCopy], s.buf[s.bufOffset:s.bufOffset+toCopy])
104 s.bufOffset += toCopy
105 totalWritten += toCopy
106 s.bytesRead += int64(toCopy)
107 }
108
109 if totalWritten > 0 {
110 s.hasher.Write(p[:totalWritten])
111 }
112
113 if s.bytesRead >= s.targetBytes {
114 return totalWritten, io.EOF
115 }
116 return totalWritten, nil
117}
118
119func (s *DLPStreamer) generateNextChunk() {
120 if s.curBufPtr != nil {
121 s.pool.Put(s.curBufPtr)
122 s.curBufPtr = nil
123 }
124 s.curBufPtr = s.pool.Get().(*[]byte)
125 chunk := (*s.curBufPtr)[:0]
126
127 // Send CSV header on first chunk if CSV carrier
128 if !s.headerSent && strings.ToLower(s.cfg.CarrierType) == "csv" {
129 header := []byte("EmployeeID,FullName,TaxID_SSN,CardNumber,ExpDate,Department,Email,Salary\n")
130 chunk = append(chunk, header...)
131 s.headerSent = true
132 }
133
134 // Fill chunk up to StreamChunkSize
135 dlpTypes := []string{"pci", "ssn", "keys", "hipaa", "pii"}
136 for len(chunk) < StreamChunkSize {
137 typ := s.cfg.DLPType
138 if typ == "" || typ == "all" || typ == "mixed" {
139 typ = dlpTypes[s.rng.Intn(len(dlpTypes))]
140 }
141 rec := GenerateCarrierRecord(s.cfg.CarrierType, typ, s.rng, s.cfg.Domain)
142 chunk = append(chunk, rec...)
143 }
144
145 // Apply entropy tuning if requested
146 if s.cfg.MinEntropy > 0 && s.cfg.MaxEntropy > 0 {
147 chunk = s.tuner.Modulate(chunk, s.rng)
148 }
149
150 s.buf = chunk
151 s.bufOffset = 0
152}
153
154// Checksum returns the SHA-256 hash of all emitted payload bytes.
155func (s *DLPStreamer) Checksum() [32]byte {
156 var sum [32]byte
157 copy(sum[:], s.hasher.Sum(nil))
158 return sum
159}
160
161// ChecksumHex returns the lowercase hex representation of the SHA-256 hash.
162func (s *DLPStreamer) ChecksumHex() string {
163 return hex.EncodeToString(s.hasher.Sum(nil))
164}
165
166// BytesRead returns total bytes streamed so far.
167func (s *DLPStreamer) BytesRead() int64 {
168 return s.bytesRead
169}
170
171// TotalTargetBytes returns the configured target volume.
172func (s *DLPStreamer) TotalTargetBytes() int64 {
173 return s.targetBytes
174}
175
176// Close closes the streamer.
177func (s *DLPStreamer) Close() error {
178 s.closed = true
179 s.buf = nil
180 if s.curBufPtr != nil {
181 s.pool.Put(s.curBufPtr)
182 s.curBufPtr = nil
183 }
184 return nil
185}