● 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 / evasion / stego_bmp.go
← Back to directory
164 lines · 4.9 KB
Raw
1package evasion
2
3import (
4 "encoding/binary"
5 "errors"
6 "fmt"
7 "math/rand"
8)
9
10// GenerateProceduralBMP synthesizes a valid 24-bit uncompressed BMP image.
11func GenerateProceduralBMP(width, height int, seed int64) []byte {
12 rowSize := ((width*3 + 3) / 4) * 4
13 imageSize := rowSize * height
14 fileSize := 14 + 40 + imageSize
15
16 buf := make([]byte, fileSize)
17
18 // BITMAPFILEHEADER (14 bytes)
19 buf[0] = 'B'
20 buf[1] = 'M'
21 binary.LittleEndian.PutUint32(buf[2:6], uint32(fileSize))
22 binary.LittleEndian.PutUint32(buf[10:14], 54) // offset to pixel data
23
24 // BITMAPINFOHEADER (40 bytes)
25 binary.LittleEndian.PutUint32(buf[14:18], 40)
26 binary.LittleEndian.PutUint32(buf[18:22], uint32(width))
27 binary.LittleEndian.PutUint32(buf[22:26], uint32(height))
28 binary.LittleEndian.PutUint16(buf[26:28], 1) // planes
29 binary.LittleEndian.PutUint16(buf[28:30], 24) // 24-bit BGR
30 binary.LittleEndian.PutUint32(buf[30:34], 0) // BI_RGB uncompressed
31 binary.LittleEndian.PutUint32(buf[34:38], uint32(imageSize))
32 binary.LittleEndian.PutUint32(buf[38:42], 2835)
33 binary.LittleEndian.PutUint32(buf[42:46], 2835)
34
35 // Fill pixel array with smooth deterministic procedural color gradient
36 rng := rand.New(rand.NewSource(seed))
37 baseR := uint8(rng.Intn(100) + 50)
38 baseG := uint8(rng.Intn(100) + 50)
39 baseB := uint8(rng.Intn(100) + 50)
40
41 pixelStart := 54
42 for y := 0; y < height; y++ {
43 rowOffset := pixelStart + y*rowSize
44 for x := 0; x < width; x++ {
45 idx := rowOffset + x*3
46 buf[idx] = uint8((int(baseB) + x*255/width) % 256) // Blue
47 buf[idx+1] = uint8((int(baseG) + y*255/height) % 256) // Green
48 buf[idx+2] = uint8((int(baseR) + (x+y)*128/width) % 256) // Red
49 }
50 // Row padding is already 0x00
51 }
52
53 return buf
54}
55
56// EmbedBMP embeds payload into 24-bit BMP pixels using 1-bit LSB steganography.
57func EmbedBMP(bmpData []byte, payload []byte) ([]byte, error) {
58 if len(bmpData) < 54 || bmpData[0] != 'B' || bmpData[1] != 'M' {
59 return nil, errors.New("invalid BMP header")
60 }
61
62 width := int(binary.LittleEndian.Uint32(bmpData[18:22]))
63 height := int(binary.LittleEndian.Uint32(bmpData[22:26]))
64 bitCount := binary.LittleEndian.Uint16(bmpData[28:30])
65 compression := binary.LittleEndian.Uint32(bmpData[30:34])
66
67 if bitCount != 24 || compression != 0 {
68 return nil, fmt.Errorf("unsupported BMP format: bitCount=%d, compression=%d (requires 24-bit uncompressed)", bitCount, compression)
69 }
70
71 usablePixels := width * height * 3
72 maxCapacity := (usablePixels / 8) - 4 // minus 4 bytes for length header
73 if len(payload) > maxCapacity {
74 return nil, fmt.Errorf("payload size (%d bytes) exceeds BMP capacity (%d bytes)", len(payload), maxCapacity)
75 }
76
77 // Prepare framed payload: [Length uint32 (4B)][Payload]
78 framed := make([]byte, 4+len(payload))
79 binary.BigEndian.PutUint32(framed[0:4], uint32(len(payload)))
80 copy(framed[4:], payload)
81
82 out := make([]byte, len(bmpData))
83 copy(out, bmpData)
84
85 rowSize := ((width*3 + 3) / 4) * 4
86 pixelStart := int(binary.LittleEndian.Uint32(bmpData[10:14]))
87
88 bitTotal := len(framed) * 8
89 bitIdx := 0
90
91outer:
92 for y := 0; y < height; y++ {
93 rowOffset := pixelStart + y*rowSize
94 for x := 0; x < width*3; x++ {
95 if bitIdx >= bitTotal {
96 break outer
97 }
98 byteVal := framed[bitIdx/8]
99 bit := (byteVal >> (7 - (bitIdx % 8))) & 0x01
100
101 targetByte := out[rowOffset+x]
102 out[rowOffset+x] = (targetByte & 0xFE) | bit
103 bitIdx++
104 }
105 }
106
107 return out, nil
108}
109
110// ExtractBMP extracts payload embedded via EmbedBMP.
111func ExtractBMP(bmpData []byte) ([]byte, error) {
112 if len(bmpData) < 54 || bmpData[0] != 'B' || bmpData[1] != 'M' {
113 return nil, errors.New("invalid BMP header")
114 }
115
116 width := int(binary.LittleEndian.Uint32(bmpData[18:22]))
117 height := int(binary.LittleEndian.Uint32(bmpData[22:26]))
118 rowSize := ((width*3 + 3) / 4) * 4
119 pixelStart := int(binary.LittleEndian.Uint32(bmpData[10:14]))
120
121 // First extract 32 bits (4 bytes) to read length header
122 lengthBits := 32
123 var lengthBuf [4]byte
124 bitIdx := 0
125
126 for y := 0; y < height && bitIdx < lengthBits; y++ {
127 rowOffset := pixelStart + y*rowSize
128 for x := 0; x < width*3 && bitIdx < lengthBits; x++ {
129 bit := bmpData[rowOffset+x] & 0x01
130 lengthBuf[bitIdx/8] |= (bit << (7 - (bitIdx % 8)))
131 bitIdx++
132 }
133 }
134
135 payloadLen := int(binary.BigEndian.Uint32(lengthBuf[:]))
136 usablePixels := width * height * 3
137 maxCapacity := (usablePixels / 8) - 4
138 if payloadLen <= 0 || payloadLen > maxCapacity {
139 return nil, fmt.Errorf("invalid extracted payload length %d (capacity: %d)", payloadLen, maxCapacity)
140 }
141
142 // Extract payload bits
143 totalBits := (4 + payloadLen) * 8
144 payload := make([]byte, payloadLen)
145
146outerExtract:
147 for y := 0; y < height; y++ {
148 rowOffset := pixelStart + y*rowSize
149 for x := 0; x < width*3; x++ {
150 currBit := y*(width*3) + x
151 if currBit < 32 {
152 continue
153 }
154 if currBit >= totalBits {
155 break outerExtract
156 }
157 bit := bmpData[rowOffset+x] & 0x01
158 targetBit := currBit - 32
159 payload[targetBit/8] |= (bit << (7 - (targetBit % 8)))
160 }
161 }
162
163 return payload, nil
164}