● 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 / sweep / probes.go
← Back to directory
146 lines · 5.0 KB
Raw
1package sweep
2
3import (
4 "crypto/rand"
5 "encoding/binary"
6 "fmt"
7 "time"
8
9 "github.com/shehzade/contraband/pkg/common"
10)
11
12// BuildProbeForPort dispatches to the port-specific binary probe builder.
13func BuildProbeForPort(port int) []byte {
14 switch port {
15 case 53:
16 return BuildDNSProbe(0x1337)
17 case 123:
18 return BuildNTPProbe(time.Now().UTC())
19 case 161:
20 return BuildSNMPProbe("public", 0x1337)
21 case 514:
22 return BuildSyslogProbe("contraband", common.UDPProbeToken)
23 case 443, 8443:
24 return BuildQUICProbe()
25 default:
26 return BuildGenericUDPProbe(common.UDPProbeToken)
27 }
28}
29
30// BuildDNSProbe crafts an RFC 1035 root query packet (. IN NS) (17 bytes).
31func BuildDNSProbe(queryID uint16) []byte {
32 buf := make([]byte, 17)
33 binary.BigEndian.PutUint16(buf[0:2], queryID) // ID
34 binary.BigEndian.PutUint16(buf[2:4], 0x0100) // Flags: Standard query, Recursion Desired
35 binary.BigEndian.PutUint16(buf[4:6], 0x0001) // QDCOUNT: 1
36 binary.BigEndian.PutUint16(buf[6:8], 0x0000) // ANCOUNT: 0
37 binary.BigEndian.PutUint16(buf[8:10], 0x0000) // NSCOUNT: 0
38 binary.BigEndian.PutUint16(buf[10:12], 0x0000) // ARCOUNT: 0
39 buf[12] = 0x00 // QNAME: root "."
40 binary.BigEndian.PutUint16(buf[13:15], 0x0002) // QTYPE: NS (type 2)
41 binary.BigEndian.PutUint16(buf[15:17], 0x0001) // QCLASS: IN (class 1)
42 return buf
43}
44
45// BuildNTPProbe crafts an RFC 5905 NTPv4 client request packet (48 bytes).
46func BuildNTPProbe(transmitTime time.Time) []byte {
47 buf := make([]byte, 48)
48 // Byte 0: LI=0 (no warning), VN=4 (NTPv4), Mode=3 (Client) -> 00 100 011 = 0x23
49 buf[0] = 0x23
50 buf[1] = 0x00 // Stratum: unspecified
51 buf[2] = 0x04 // Poll: 16 seconds
52 buf[3] = 0xfa // Precision: -6 (approx 15ms)
53 // Bytes 4-39: Root delay, dispersion, refid, timestamps initialized to 0
54
55 // Bytes 40-47: Transmit Timestamp (seconds since 1900 + fraction)
56 const ntpEpochOffset = 2208988800
57 sec := uint32(transmitTime.Unix() + ntpEpochOffset)
58 frac := uint32((uint64(transmitTime.Nanosecond()) << 32) / 1000000000)
59 binary.BigEndian.PutUint32(buf[40:44], sec)
60 binary.BigEndian.PutUint32(buf[44:48], frac)
61 return buf
62}
63
64// BuildSNMPProbe crafts an RFC 1905 SNMPv2c GetRequest packet for sysDescr.0 (43 bytes).
65// OID 1.3.6.1.2.1.1.1.0 in ASN.1 BER: 2b 06 01 02 01 01 01 00
66func BuildSNMPProbe(community string, reqID int32) []byte {
67 commBytes := []byte(community)
68 commLen := byte(len(commBytes))
69
70 // Pre-assembled OID VarBind sequence for sysDescr.0 (1.3.6.1.2.1.1.1.0):
71 // SEQUENCE (12B contents, 14B total TLV): OID TLV (10B) + NULL TLV (2B)
72 varBind := []byte{
73 0x30, 0x0c,
74 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00,
75 0x05, 0x00,
76 }
77
78 // VarBindList SEQUENCE (16B)
79 varBindList := append([]byte{0x30, byte(len(varBind))}, varBind...)
80
81 // GetRequest-PDU (0xa0)
82 // reqID (INTEGER 4B), error-status (0), error-index (0), VarBindList
83 pduPayload := make([]byte, 0, 10+len(varBindList))
84 pduPayload = append(pduPayload, 0x02, 0x04)
85 pduPayload = binary.BigEndian.AppendUint32(pduPayload, uint32(reqID))
86 pduPayload = append(pduPayload, 0x02, 0x01, 0x00) // error-status = 0
87 pduPayload = append(pduPayload, 0x02, 0x01, 0x00) // error-index = 0
88 pduPayload = append(pduPayload, varBindList...)
89
90 pdu := append([]byte{0xa0, byte(len(pduPayload))}, pduPayload...)
91
92 // Outer Message SEQUENCE: version (INTEGER 1 = v2c), community, PDU
93 msgPayload := make([]byte, 0, 3+2+int(commLen)+len(pdu))
94 msgPayload = append(msgPayload, 0x02, 0x01, 0x01) // version 1 (SNMPv2c)
95 msgPayload = append(msgPayload, 0x04, commLen)
96 msgPayload = append(msgPayload, commBytes...)
97 msgPayload = append(msgPayload, pdu...)
98
99 return append([]byte{0x30, byte(len(msgPayload))}, msgPayload...)
100}
101
102// BuildSyslogProbe crafts an RFC 5424 test probe frame.
103func BuildSyslogProbe(host, msg string) []byte {
104 // PRI 134: Facility local0 (16) * 8 + Severity info (6) = 134
105 ts := time.Now().UTC().Format(time.RFC3339Nano)
106 frame := fmt.Sprintf("<134>1 %s %s contraband 1 CTRB-PROBE - %s", ts, host, msg)
107 return []byte(frame)
108}
109
110// BuildQUICProbe crafts an RFC 9000 QUIC Initial probe packet padded to 1200 bytes.
111func BuildQUICProbe() []byte {
112 pkt := make([]byte, 1200)
113
114 // Long Header Initial: 0xc0 (Header Form=1, Fixed=1, Type=0x00 Initial, Reserved=0, PN Len=1)
115 pkt[0] = 0xc0
116 binary.BigEndian.PutUint32(pkt[1:5], 0x00000001) // Version: QUIC v1 (RFC 9000)
117
118 // Destination Connection ID (DCID): 8 bytes
119 pkt[5] = 0x08
120 _, _ = rand.Read(pkt[6:14])
121
122 // Source Connection ID (SCID): 8 bytes
123 pkt[14] = 0x08
124 _, _ = rand.Read(pkt[15:23])
125
126 // Token Length: 0
127 pkt[23] = 0x00
128
129 // Length (remaining packet length: 1200 - 26 = 1174 bytes)
130 // Varint encoding: 2-byte prefix 0x40
131 binary.BigEndian.PutUint16(pkt[24:26], 0x4496) // 0x4000 | 1174
132
133 // Packet Number: 1 byte
134 pkt[26] = 0x00
135
136 // Remaining 1173 bytes (pkt[27:1200]) are initialized to 0x00 (RFC 9000 PADDING frames)
137 return pkt
138}
139
140// BuildGenericUDPProbe crafts a standard fallback probe datagram.
141func BuildGenericUDPProbe(token string) []byte {
142 if token == "" {
143 token = common.UDPProbeToken
144 }
145 return []byte(token)
146}