Implemented agent registration to match new binary structure instead of json.

This commit is contained in:
Jakob Friedl
2025-07-21 22:07:25 +02:00
parent 99f55cc04f
commit 9f15026fd1
28 changed files with 452 additions and 327 deletions

View File

@@ -1,6 +1,5 @@
import streams, strutils
import ./types
import ./[types, utils]
type
Packer* = ref object
stream: StringStream
@@ -34,6 +33,19 @@ proc addArgument*(packer: Packer, arg: TaskArg): Packer {.discardable.} =
packer.addData(arg.data)
return packer
proc addVarLengthMetadata*(packer: Packer, metadata: seq[byte]): Packer {.discardable.} =
# Add length of metadata field
packer.add(cast[uint32](metadata.len))
if metadata.len <= 0:
# Field is empty (e.g. not domain joined)
return packer
# Add content
packer.addData(metadata)
return packer
proc pack*(packer: Packer): seq[byte] =
packer.stream.setPosition(0)
let data = packer.stream.readAll()
@@ -102,4 +114,15 @@ proc getArgument*(unpacker: Unpacker): TaskArg =
of BOOL:
result.data = unpacker.getBytes(1)
else:
discard
discard
proc getVarLengthMetadata*(unpacker: Unpacker): string =
# Read length of metadata field
let length = unpacker.getUint32()
if length <= 0:
return ""
# Read content
return unpacker.getBytes(int(length)).toString()

View File

@@ -13,7 +13,8 @@ type
PacketType* = enum
MSG_TASK = 0'u8
MSG_RESPONSE = 1'u8
MSG_REGISTER = 100'u8
MSG_REGISTER = 2'u8
MSG_CHECKIN = 100'u8
ArgType* = enum
STRING = 0'u8
@@ -101,27 +102,36 @@ type
# Agent structure
type
# All variable length fields are stored as seq[byte], prefixed with 4 bytes indicating the length of the following data
AgentMetadata* = object
agentId*: uint32
listenerId*: uint32
username*: seq[byte]
hostname*: seq[byte]
domain*: seq[byte]
ip*: seq[byte]
os*: seq[byte]
process*: seq[byte]
pid*: uint32
isElevated*: uint8
sleep*: uint32
AgentRegistrationData* = object
username*: string
hostname*: string
domain*: string
ip*: string
os*: string
process*: string
pid*: int
elevated*: bool
sleep*: int
header*: Header
# encMaterial*: seq[byte] # Encryption material for the agent registration
metadata*: AgentMetadata
Agent* = ref object
name*: string
listener*: string
agentId*: string
listenerId*: string
username*: string
hostname*: string
domain*: string
process*: string
pid*: int
ip*: string
os*: string
process*: string
pid*: int
elevated*: bool
sleep*: int
jitter*: float

53
src/common/utils.nim Normal file
View File

@@ -0,0 +1,53 @@
import strutils, sequtils, random, strformat
proc generateUUID*(): string =
# Create a 4-byte HEX UUID string (8 characters)
(0..<4).mapIt(rand(255)).mapIt(fmt"{it:02X}").join()
proc uuidToUint32*(uuid: string): uint32 =
return fromHex[uint32](uuid)
proc uuidToString*(uuid: uint32): string =
return uuid.toHex(8)
proc toString*(data: seq[byte]): string =
result = newString(data.len)
for i, b in data:
result[i] = char(b)
proc toBytes*(data: string): seq[byte] =
result = newSeq[byte](data.len)
for i, c in data:
result[i] = byte(c.ord)
proc toUint32*(data: seq[byte]): uint32 =
if data.len != 4:
raise newException(ValueError, "Expected 4 bytes for uint32")
return uint32(data[0]) or
(uint32(data[1]) shl 8) or
(uint32(data[2]) shl 16) or
(uint32(data[3]) shl 24)
proc toHexDump*(data: seq[byte]): string =
for i, b in data:
result.add(b.toHex(2))
if i < data.len - 1:
if (i + 1) mod 4 == 0:
result.add(" | ") # Add | every 4 bytes
else:
result.add(" ") # Regular space
proc toBytes*(value: uint16): seq[byte] =
return @[
byte(value and 0xFF),
byte((value shr 8) and 0xFF)
]
proc toBytes*(value: uint32): seq[byte] =
return @[
byte(value and 0xFF),
byte((value shr 8) and 0xFF),
byte((value shr 16) and 0xFF),
byte((value shr 24) and 0xFF)
]