[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)
146 lines · 5.0 KB
| 1 | package sweep |
| 2 | |
| 3 | import ( |
| 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. |
| 13 | func 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). |
| 31 | func 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). |
| 46 | func 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 |
| 66 | func 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. |
| 103 | func 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. |
| 111 | func 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. |
| 141 | func BuildGenericUDPProbe(token string) []byte { |
| 142 | if token == "" { |
| 143 | token = common.UDPProbeToken |
| 144 | } |
| 145 | return []byte(token) |
| 146 | } |