Adversarial C2 Protocol Implemented in Zig
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

construct full message

+60 -36
+60 -36
src/main.zig
··· 99 99 // std.debug.print("Interface: {s}\n", .{(try net_interface.name(init.io)).toSlice()}); 100 100 const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336 101 101 // --- UDP (Last in memory, defined first for LSB->MSB) --- 102 - checksum: u16 = 0, 103 - udp_len: u16, 104 - dst_port: u16, 105 - src_port: u16, 102 + udp: packed struct { 103 + checksum: u16 = 0, 104 + len: u16, 105 + dst_port: u16, 106 + src_port: u16, 107 + }, 106 108 107 109 // --- IP --- 108 - dst_addr: u32, 109 - src_addr: u32, 110 - header_checksum: u16 = 0, 111 - protocol: u8 = 17, // udp 112 - ttl: u8 = 0x40, 110 + ip: packed struct { 111 + dst_addr: u32, 112 + src_addr: u32, 113 + header_checksum: u16 = 0, 114 + protocol: u8 = 17, // udp 115 + ttl: u8 = 0x40, 113 116 114 - // fragment_offset (13 bits) + flags (3 bits) = 16 bits 115 - // In Big Endian, flags are the high bits of the first byte. 116 - // To have flags appear first in the stream, define them last here. 117 - fragment_offset: u13 = 0, 118 - flags: packed struct(u3) { 119 - reserved: u1 = 0, 120 - dont_fragment: u1 = 0, 121 - more_fragments: u1 = 0, 122 - } = .{}, 117 + // fragment_offset (13 bits) + flags (3 bits) = 16 bits 118 + // In Big Endian, flags are the high bits of the first byte. 119 + // To have flags appear first in the stream, define them last here. 120 + fragment_offset: u13 = 0, 121 + flags: packed struct(u3) { 122 + reserved: u1 = 0, 123 + dont_fragment: u1 = 0, 124 + more_fragments: u1 = 0, 125 + } = .{}, 123 126 124 - id: u16, 125 - total_length: u16, 126 - tos: u8 = undefined, 127 + id: u16, 128 + len: u16, 129 + tos: u8 = undefined, 127 130 128 - // ip_version (4 bits) + ihl (4 bits) = 8 bits 129 - // To have version appear first (high nibble), define it last. 130 - ihl: u4 = 5, 131 - ip_version: u4 = 4, 131 + // ip_version (4 bits) + ihl (4 bits) = 8 bits 132 + // To have version appear first (high nibble), define it last. 133 + ihl: u4 = 5, 134 + ip_version: u4 = 4, 135 + }, 132 136 133 137 // --- Ethernet --- 134 138 eth_type: u16 = std.os.linux.ETH.P.IP, ··· 141 145 w.writeStruct(self, .big) catch unreachable; 142 146 return res; 143 147 } 148 + 149 + fn setPayloadLen(self: *@This(), len: usize) void { 150 + self.ip.len = @intCast(len + @sizeOf(@TypeOf(self.udp)) + @sizeOf(@TypeOf(self.ip))); 151 + self.udp.len = @intCast(len + @sizeOf(@TypeOf(self.udp))); 152 + } 144 153 }; 145 154 146 - const headers: EthIpUdp = .{ 155 + var headers: EthIpUdp = .{ 147 156 .src_mac = @splat(0x0e), 148 - .id = 0, 149 - .src_addr = 0, 150 - .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }), 151 - .src_port = undefined, // TODO: change this? 152 - .dst_port = 8888, 153 - 154 - .total_length = undefined, 155 - .udp_len = undefined, 157 + .ip = .{ 158 + .id = 0, 159 + .src_addr = 0, 160 + .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }), 161 + .len = undefined, 162 + }, 163 + .udp = .{ 164 + .src_port = undefined, // TODO: change this? 165 + .dst_port = 8888, 166 + .len = undefined, 167 + }, 156 168 }; 157 169 std.debug.print("headers: {any}\n", .{&headers.toBytes()}); 158 170 ··· 163 175 }, 164 176 }; 165 177 166 - var relay_bytes: [2048]u8 = undefined; 167 - std.debug.print("payload: {any}\n", .{relay.toBytes(&relay_bytes)}); 178 + var relay_buf: [2048]u8 = undefined; 179 + const relay_bytes = relay.toBytes(&relay_buf); 180 + std.debug.print("payload: {any}\n", .{relay_bytes}); 181 + headers.setPayloadLen(relay_bytes.len); 182 + 183 + const full_msg = blk: { 184 + var msg_buf: [2048]u8 = undefined; 185 + var msg_w: Writer = .fixed(&msg_buf); 186 + msg_w.writeAll(&headers.toBytes()) catch unreachable; 187 + msg_w.writeAll(relay_bytes) catch unreachable; 188 + break :blk msg_w.buffered(); 189 + }; 190 + 191 + std.debug.print("full message = {any}\n", .{full_msg}); 168 192 } 169 193 170 194 fn parseDest(in: ?[]const u8) [4]u8 {