Added more websocket commands and started agent generation modal window.
This commit is contained in:
@@ -1,43 +1,43 @@
|
|||||||
[Window][Sessions [Table View]]
|
[Window][Sessions [Table View]]
|
||||||
Pos=10,43
|
Pos=10,43
|
||||||
Size=2016,548
|
Size=2101,474
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000003,0
|
DockId=0x00000003,0
|
||||||
|
|
||||||
[Window][Listeners]
|
[Window][Listeners]
|
||||||
Pos=10,593
|
Pos=10,519
|
||||||
Size=2528,804
|
Size=2848,1166
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,0
|
DockId=0x00000006,0
|
||||||
|
|
||||||
[Window][Eventlog]
|
[Window][Eventlog]
|
||||||
Pos=2028,43
|
Pos=2113,43
|
||||||
Size=510,548
|
Size=745,474
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,0
|
DockId=0x00000004,0
|
||||||
|
|
||||||
[Window][Dear ImGui Demo]
|
[Window][Dear ImGui Demo]
|
||||||
Pos=2028,43
|
Pos=2113,43
|
||||||
Size=510,548
|
Size=745,474
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,1
|
DockId=0x00000004,1
|
||||||
|
|
||||||
[Window][Dockspace]
|
[Window][Dockspace]
|
||||||
Pos=0,0
|
Pos=0,0
|
||||||
Size=2548,1407
|
Size=2868,1695
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][[FACEDEAD] bob@LAPTOP-02]
|
[Window][[FACEDEAD] bob@LAPTOP-02]
|
||||||
Pos=10,593
|
Pos=10,661
|
||||||
Size=2528,804
|
Size=2848,1024
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,1
|
DockId=0x00000006,3
|
||||||
|
|
||||||
[Window][[C9D8E7F6] charlie@SERVER-03]
|
[Window][[C9D8E7F6] charlie@SERVER-03]
|
||||||
Pos=10,593
|
Pos=10,661
|
||||||
Size=2528,804
|
Size=2848,1024
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,1
|
DockId=0x00000006,4
|
||||||
|
|
||||||
[Window][Debug##Default]
|
[Window][Debug##Default]
|
||||||
Pos=60,60
|
Pos=60,60
|
||||||
@@ -45,22 +45,22 @@ Size=400,400
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][[G1H2I3J5] diana@WORKSTATION-04]
|
[Window][[G1H2I3J5] diana@WORKSTATION-04]
|
||||||
Pos=10,593
|
Pos=10,372
|
||||||
Size=2528,804
|
Size=1888,617
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,1
|
DockId=0x00000006,1
|
||||||
|
|
||||||
[Window][[DEADBEEF] alice@DESKTOP-01]
|
[Window][[DEADBEEF] alice@DESKTOP-01]
|
||||||
Pos=10,716
|
Pos=10,661
|
||||||
Size=2848,969
|
Size=2848,1024
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,2
|
DockId=0x00000006,2
|
||||||
|
|
||||||
[Window][Example: Console]
|
[Window][Example: Console]
|
||||||
Pos=10,572
|
Pos=10,661
|
||||||
Size=2848,1113
|
Size=2848,1024
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000005,2
|
DockId=0x00000006,2
|
||||||
|
|
||||||
[Window][Example: Assets Browser]
|
[Window][Example: Assets Browser]
|
||||||
Pos=60,60
|
Pos=60,60
|
||||||
@@ -110,8 +110,17 @@ Size=76,76
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Start Listener]
|
[Window][Start Listener]
|
||||||
Pos=955,591
|
Pos=713,369
|
||||||
Size=637,225
|
Size=500,225
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Dear ImGui Demo/0_E1BADA21]
|
||||||
|
IsChild=1
|
||||||
|
Size=1363,540
|
||||||
|
|
||||||
|
[Window][Generate Payload]
|
||||||
|
Pos=704,337
|
||||||
|
Size=500,325
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Table][0x32886A44,8]
|
[Table][0x32886A44,8]
|
||||||
@@ -136,9 +145,9 @@ Column 3 Weight=0.9746
|
|||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockNode ID=0x00000009 Pos=100,200 Size=754,103 Selected=0x64D005CF
|
DockNode ID=0x00000009 Pos=100,200 Size=754,103 Selected=0x64D005CF
|
||||||
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=2528,1354 Split=Y
|
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=2848,1642 Split=Y
|
||||||
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,548 Split=X
|
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,474 Split=X
|
||||||
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=1376,159 CentralNode=1 Selected=0x61E02D75
|
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=2101,159 CentralNode=1 Selected=0x61E02D75
|
||||||
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=510,159 Selected=0x5E5F7166
|
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=745,159 Selected=0x0FA43D88
|
||||||
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,804 Selected=0x6BE22050
|
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,1166 Selected=0x6BE22050
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import strutils
|
|||||||
import imguin/[cimgui, glfw_opengl, simple]
|
import imguin/[cimgui, glfw_opengl, simple]
|
||||||
import ../utils/appImGui
|
import ../utils/appImGui
|
||||||
import ../../common/[types, utils]
|
import ../../common/[types, utils]
|
||||||
import ./modals/startListener
|
import ./modals/[startListener, generatePayload]
|
||||||
|
import ../websocket
|
||||||
import whisky
|
import whisky
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -11,6 +12,7 @@ type
|
|||||||
listeners*: seq[Listener]
|
listeners*: seq[Listener]
|
||||||
selection: ptr ImGuiSelectionBasicStorage
|
selection: ptr ImGuiSelectionBasicStorage
|
||||||
startListenerModal: ListenerModalComponent
|
startListenerModal: ListenerModalComponent
|
||||||
|
generatePayloadModal: AgentModalComponent
|
||||||
|
|
||||||
let exampleListeners: seq[Listener] = @[
|
let exampleListeners: seq[Listener] = @[
|
||||||
Listener(
|
Listener(
|
||||||
@@ -33,6 +35,8 @@ proc ListenersTable*(title: string): ListenersTableComponent =
|
|||||||
result.listeners = exampleListeners
|
result.listeners = exampleListeners
|
||||||
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||||
result.startListenerModal = ListenerModal()
|
result.startListenerModal = ListenerModal()
|
||||||
|
result.generatePayloadModal = AgentModal(result.listeners)
|
||||||
|
|
||||||
|
|
||||||
proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebSocket) =
|
proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebSocket) =
|
||||||
igBegin(component.title, showComponent, 0)
|
igBegin(component.title, showComponent, 0)
|
||||||
@@ -43,13 +47,21 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebS
|
|||||||
# Listener creation modal
|
# Listener creation modal
|
||||||
if igButton("Start Listener", vec2(0.0f, 0.0f)):
|
if igButton("Start Listener", vec2(0.0f, 0.0f)):
|
||||||
igOpenPopup_str("Start Listener", ImGui_PopupFlags_None.int32)
|
igOpenPopup_str("Start Listener", ImGui_PopupFlags_None.int32)
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
# Payload generation modal
|
||||||
|
if igButton("Generate Payload", vec2(0.0f, 0.0f)):
|
||||||
|
igOpenPopup_str("Generate Payload", ImGui_PopupFlags_None.int32)
|
||||||
|
|
||||||
let listener = component.startListenerModal.draw()
|
let listener = component.startListenerModal.draw()
|
||||||
if listener != nil:
|
if listener != nil:
|
||||||
# TODO: Start listener
|
ws.sendStartListener(listener)
|
||||||
ws.send("Starting listener: " & listener.listenerId)
|
|
||||||
component.listeners.add(listener)
|
component.listeners.add(listener)
|
||||||
|
|
||||||
|
component.generatePayloadModal.draw()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Listener table
|
Listener table
|
||||||
]#
|
]#
|
||||||
@@ -109,8 +121,8 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebS
|
|||||||
for i in 0 ..< component.listeners.len():
|
for i in 0 ..< component.listeners.len():
|
||||||
if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)):
|
if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)):
|
||||||
newListeners.add(component.listeners[i])
|
newListeners.add(component.listeners[i])
|
||||||
|
else:
|
||||||
# TODO: Stop/kill listener
|
ws.sendStopListener(component.listeners[i].listenerId)
|
||||||
|
|
||||||
component.listeners = newListeners
|
component.listeners = newListeners
|
||||||
ImGuiSelectionBasicStorage_Clear(component.selection)
|
ImGuiSelectionBasicStorage_Clear(component.selection)
|
||||||
|
|||||||
107
src/client/views/modals/generatePayload.nim
Normal file
107
src/client/views/modals/generatePayload.nim
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import strutils
|
||||||
|
import imguin/[cimgui, glfw_opengl, simple]
|
||||||
|
import ../../utils/appImGui
|
||||||
|
import ../../../common/[types, utils]
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
AgentModalComponent* = ref object of RootObj
|
||||||
|
listener: int32
|
||||||
|
sleepDelay: uint32
|
||||||
|
sleepMask: int32
|
||||||
|
spoofStack: bool
|
||||||
|
listeners: seq[string]
|
||||||
|
sleepMaskTechniques: seq[string]
|
||||||
|
|
||||||
|
proc AgentModal*(listeners: seq[Listener]): AgentModalComponent =
|
||||||
|
result = new AgentModalComponent
|
||||||
|
result.listener = 0
|
||||||
|
result.sleepDelay = 5
|
||||||
|
result.sleepMask = 0
|
||||||
|
result.spoofStack = false
|
||||||
|
|
||||||
|
for l in listeners:
|
||||||
|
result.listeners.add(l.listenerId)
|
||||||
|
|
||||||
|
for s in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
|
||||||
|
result.sleepMaskTechniques.add($s)
|
||||||
|
|
||||||
|
proc resetModalValues(component: AgentModalComponent) =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc draw*(component: AgentModalComponent) =
|
||||||
|
let textSpacing = igGetStyle().ItemSpacing.x
|
||||||
|
|
||||||
|
# Center modal
|
||||||
|
let vp = igGetMainViewport()
|
||||||
|
var center: ImVec2
|
||||||
|
ImGuiViewport_GetCenter(addr center, vp)
|
||||||
|
igSetNextWindowPos(center, ImGuiCond_Appearing.int32, vec2(0.5f, 0.5f))
|
||||||
|
|
||||||
|
let modalWidth = max(500.0f, vp.Size.x * 0.25)
|
||||||
|
igSetNextWindowSize(vec2(modalWidth, 0.0f), ImGuiCond_Always.int32)
|
||||||
|
|
||||||
|
var show = true
|
||||||
|
let windowFlags = ImGuiWindowFlags_None.int32 # or ImGuiWindowFlags_NoMove.int32
|
||||||
|
if igBeginPopupModal("Generate Payload", addr show, windowFlags):
|
||||||
|
defer: igEndPopup()
|
||||||
|
|
||||||
|
var availableSize: ImVec2
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
|
||||||
|
# Listener selection
|
||||||
|
igText("Listener: ")
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
igSetNextItemWidth(availableSize.x)
|
||||||
|
igCombo_Str("##InputListener", addr component.listener, (component.listeners.join("\0") & "\0").cstring , component.listeners.len().int32)
|
||||||
|
|
||||||
|
# Sleep delay
|
||||||
|
let step: uint32 = 1
|
||||||
|
igText("Sleep delay: ")
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
igSetNextItemWidth(availableSize.x)
|
||||||
|
igInputScalar("##InputSleepDelay", ImGuiDataType_U32.int32, addr component.sleepDelay, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
||||||
|
|
||||||
|
# Agent sleep obfuscation technique dropdown selection
|
||||||
|
igText("Sleep mask: ")
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
igSetNextItemWidth(availableSize.x)
|
||||||
|
igCombo_Str("##InputSleepMask", addr component.sleepMask, (component.sleepMaskTechniques.join("\0") & "\0").cstring , component.sleepMaskTechniques.len().int32)
|
||||||
|
|
||||||
|
# Stack spoofing checkbox (only for EKKO/ZILEAN)
|
||||||
|
igText("Stack spoofing: ")
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
igSetNextItemWidth(availableSize.x)
|
||||||
|
|
||||||
|
igBeginDisabled((component.sleepMaskTechniques[component.sleepMask] != $EKKO and component.sleepMaskTechniques[component.sleepMask] != $ZILEAN))
|
||||||
|
if (component.sleepMaskTechniques[component.sleepMask] != $EKKO and component.sleepMaskTechniques[component.sleepMask] != $ZILEAN):
|
||||||
|
component.spoofStack = false
|
||||||
|
igCheckbox("##InputSpoofStack", addr component.spoofStack)
|
||||||
|
igEndDisabled()
|
||||||
|
|
||||||
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
igSeparator()
|
||||||
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
|
||||||
|
igText("Modules: ")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
igGetContentRegionAvail(addr availableSize)
|
||||||
|
|
||||||
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
igSeparator()
|
||||||
|
igDummy(vec2(0.0f, 10.0f))
|
||||||
|
|
||||||
|
if igButton("Build", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||||
|
|
||||||
|
|
||||||
|
component.resetModalValues()
|
||||||
|
igCloseCurrentPopup()
|
||||||
|
|
||||||
|
igSameLine(0.0f, textSpacing)
|
||||||
|
|
||||||
|
if igButton("Close", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||||
|
component.resetModalValues()
|
||||||
|
igCloseCurrentPopup()
|
||||||
@@ -89,6 +89,5 @@ proc draw*(component: ListenerModalComponent): Listener =
|
|||||||
igSameLine(0.0f, textSpacing)
|
igSameLine(0.0f, textSpacing)
|
||||||
|
|
||||||
if igButton("Close", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
if igButton("Close", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||||
|
|
||||||
component.resetModalValues()
|
component.resetModalValues()
|
||||||
igCloseCurrentPopup()
|
igCloseCurrentPopup()
|
||||||
@@ -97,7 +97,7 @@ proc receiveAgentConnection*(message: Message, sessions: ptr SessionsTableCompon
|
|||||||
sleep: int(unpacker.getUint32()),
|
sleep: int(unpacker.getUint32()),
|
||||||
tasks: @[],
|
tasks: @[],
|
||||||
firstCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
firstCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||||
latestCheckin: now(),
|
latestCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||||
)
|
)
|
||||||
|
|
||||||
sessions.agents.add(agent)
|
sessions.agents.add(agent)
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ type
|
|||||||
interactAgent*: Agent
|
interactAgent*: Agent
|
||||||
keyPair*: KeyPair
|
keyPair*: KeyPair
|
||||||
profile*: Profile
|
profile*: Profile
|
||||||
|
ws*: WebSocket
|
||||||
|
|
||||||
AgentCtx* = ref object
|
AgentCtx* = ref object
|
||||||
agentId*: string
|
agentId*: string
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import ../api/routes
|
|||||||
import ../db/database
|
import ../db/database
|
||||||
import ../core/logger
|
import ../core/logger
|
||||||
import ../../common/[types, utils, profile]
|
import ../../common/[types, utils, profile]
|
||||||
|
import ../websocket/send
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Listener management
|
Listener management
|
||||||
@@ -34,20 +35,14 @@ proc listenerList*(cq: Conquest) =
|
|||||||
proc serve(listener: Listener) {.thread.} =
|
proc serve(listener: Listener) {.thread.} =
|
||||||
try:
|
try:
|
||||||
listener.server.serve(Port(listener.port), listener.address)
|
listener.server.serve(Port(listener.port), listener.address)
|
||||||
except Exception:
|
except Exception as err:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc listenerStart*(cq: Conquest, host: string, portStr: string) =
|
proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protocol: Protocol) =
|
||||||
|
|
||||||
# Validate arguments
|
# Validate arguments
|
||||||
try:
|
try:
|
||||||
if not validatePort(portStr):
|
|
||||||
raise newException(CatchableError, fmt"[ - ] Invalid port number: {portStr}")
|
|
||||||
|
|
||||||
let port = portStr.parseInt
|
|
||||||
|
|
||||||
# Create new listener
|
# Create new listener
|
||||||
let name: string = generateUUID()
|
|
||||||
var router: Router
|
var router: Router
|
||||||
router.notFoundHandler = routes.error404
|
router.notFoundHandler = routes.error404
|
||||||
router.methodNotAllowedHandler = routes.error405
|
router.methodNotAllowedHandler = routes.error405
|
||||||
@@ -78,7 +73,7 @@ proc listenerStart*(cq: Conquest, host: string, portStr: string) =
|
|||||||
listenerId: name,
|
listenerId: name,
|
||||||
address: host,
|
address: host,
|
||||||
port: port,
|
port: port,
|
||||||
protocol: HTTP
|
protocol: protocol
|
||||||
)
|
)
|
||||||
|
|
||||||
# Start serving
|
# Start serving
|
||||||
@@ -90,10 +85,12 @@ proc listenerStart*(cq: Conquest, host: string, portStr: string) =
|
|||||||
if not cq.dbStoreListener(listener):
|
if not cq.dbStoreListener(listener):
|
||||||
raise newException(CatchableError, "Failed to store listener in database.")
|
raise newException(CatchableError, "Failed to store listener in database.")
|
||||||
|
|
||||||
cq.success("Started listener", fgGreen, fmt" {name} ", resetStyle, fmt"on {host}:{portStr}.")
|
cq.success("Started listener", fgGreen, fmt" {name} ", resetStyle, fmt"on {host}:{$port}.")
|
||||||
|
cq.ws.sendEventlogItem(LOG_SUCCESS_SHORT, fmt"Started listener {name} on {host}:{$port}.")
|
||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
cq.error("Failed to start listener: ", err.msg)
|
cq.error("Failed to start listener: ", err.msg)
|
||||||
|
cq.ws.sendEventlogItem(LOG_ERROR_SHORT, fmt"Failed to start listener: {err.msg}.")
|
||||||
|
|
||||||
proc restartListeners*(cq: Conquest) =
|
proc restartListeners*(cq: Conquest) =
|
||||||
var listeners: seq[Listener] = cq.dbGetAllListeners()
|
var listeners: seq[Listener] = cq.dbGetAllListeners()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ../globals
|
|||||||
import ../db/database
|
import ../db/database
|
||||||
import ../core/logger
|
import ../core/logger
|
||||||
import ../../common/[types, crypto, profile]
|
import ../../common/[types, crypto, profile]
|
||||||
import ../protocol/websocket
|
import ../websocket/[receive, send]
|
||||||
import mummy, mummy/routers
|
import mummy, mummy/routers
|
||||||
|
|
||||||
#[
|
#[
|
||||||
@@ -88,9 +88,11 @@ proc handleConsoleCommand(cq: Conquest, args: string) =
|
|||||||
of "list":
|
of "list":
|
||||||
cq.listenerList()
|
cq.listenerList()
|
||||||
of "start":
|
of "start":
|
||||||
cq.listenerStart(opts.listener.get.start.get.ip, opts.listener.get.start.get.port)
|
#cq.listenerStart(opts.listener.get.start.get.ip, opts.listener.get.start.get.port)
|
||||||
|
discard
|
||||||
of "stop":
|
of "stop":
|
||||||
cq.listenerStop(opts.listener.get.stop.get.name)
|
#cq.listenerStop(opts.listener.get.stop.get.name)
|
||||||
|
discard
|
||||||
else:
|
else:
|
||||||
cq.listenerUsage()
|
cq.listenerUsage()
|
||||||
|
|
||||||
@@ -143,18 +145,30 @@ proc init*(T: type Conquest, profile: Profile): Conquest =
|
|||||||
WebSocket
|
WebSocket
|
||||||
]#
|
]#
|
||||||
proc upgradeHandler(request: Request) =
|
proc upgradeHandler(request: Request) =
|
||||||
|
{.cast(gcsafe).}:
|
||||||
let ws = request.upgradeToWebSocket()
|
let ws = request.upgradeToWebSocket()
|
||||||
|
cq.ws = ws
|
||||||
# Send client connection message
|
# Send client connection message
|
||||||
ws.sendEventlogItem(LOG_SUCCESS_SHORT, now().toTime().toUnix(), "CQ-V1")
|
ws.sendEventlogItem(LOG_SUCCESS_SHORT, "CQ-V1")
|
||||||
|
|
||||||
|
proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.gcsafe.} =
|
||||||
proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) =
|
{.cast(gcsafe).}:
|
||||||
case event:
|
case event:
|
||||||
of OpenEvent:
|
of OpenEvent:
|
||||||
discard
|
discard
|
||||||
of MessageEvent:
|
of MessageEvent:
|
||||||
ws.sendHeartbeat()
|
ws.sendHeartbeat()
|
||||||
|
|
||||||
|
case message.getMessageType():
|
||||||
|
of CLIENT_AGENT_COMMAND:
|
||||||
|
discard
|
||||||
|
of CLIENT_LISTENER_START:
|
||||||
|
message.receiveStartListener()
|
||||||
|
of CLIENT_LISTENER_STOP:
|
||||||
|
message.receiveStopListener()
|
||||||
|
of CLIENT_AGENT_BUILD:
|
||||||
|
discard
|
||||||
|
else: discard
|
||||||
of ErrorEvent:
|
of ErrorEvent:
|
||||||
discard
|
discard
|
||||||
of CloseEvent:
|
of CloseEvent:
|
||||||
@@ -196,6 +210,7 @@ proc startServer*(profilePath: string) =
|
|||||||
cq.restartListeners()
|
cq.restartListeners()
|
||||||
cq.addMultiple(cq.dbGetAllAgents())
|
cq.addMultiple(cq.dbGetAllAgents())
|
||||||
|
|
||||||
|
# Start websocket server
|
||||||
var router: Router
|
var router: Router
|
||||||
router.get("/*", upgradeHandler)
|
router.get("/*", upgradeHandler)
|
||||||
let server = newServer(router, websocketHandler)
|
let server = newServer(router, websocketHandler)
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import times, tables
|
|
||||||
import ../../common/[types, utils, serialize]
|
|
||||||
import mummy
|
|
||||||
|
|
||||||
#[
|
|
||||||
[ Sending functions ]
|
|
||||||
Server -> Client
|
|
||||||
]#
|
|
||||||
proc sendHeartbeat*(ws: WebSocket) =
|
|
||||||
var packer = Packer.init()
|
|
||||||
|
|
||||||
packer.add(cast[uint8](CLIENT_HEARTBEAT))
|
|
||||||
let data = packer.pack()
|
|
||||||
|
|
||||||
ws.send(Bytes.toString(data), BinaryMessage)
|
|
||||||
|
|
||||||
proc sendEventlogItem*(ws: WebSocket, logType: LogType, timestamp: int64, message: string) =
|
|
||||||
var packer = Packer.init()
|
|
||||||
|
|
||||||
packer.add(cast[uint8](CLIENT_EVENT_LOG))
|
|
||||||
packer.add(cast[uint8](logType))
|
|
||||||
packer.add(cast[uint32](timestamp))
|
|
||||||
packer.addDataWithLengthPrefix(string.toBytes(message))
|
|
||||||
let data = packer.pack()
|
|
||||||
|
|
||||||
ws.send(Bytes.toString(data), BinaryMessage)
|
|
||||||
|
|
||||||
#[
|
|
||||||
[ Retrieval functions ]
|
|
||||||
Client -> Server
|
|
||||||
]#
|
|
||||||
proc getMessageType*(message: Message): WsMessageAction =
|
|
||||||
var unpacker = Unpacker.init(message.data)
|
|
||||||
return cast[WsMessageAction](unpacker.getUint8())
|
|
||||||
|
|
||||||
proc receiveStartListener*(message: Message): Listener =
|
|
||||||
var unpacker = Unpacker.init(message.data)
|
|
||||||
|
|
||||||
discard unpacker.getUint8()
|
|
||||||
|
|
||||||
return Listener(
|
|
||||||
server: nil,
|
|
||||||
listenerId: Uuid.toString(unpacker.getUint32()),
|
|
||||||
address: unpacker.getDataWithLengthPrefix(),
|
|
||||||
port: int(unpacker.getUint16()),
|
|
||||||
protocol: cast[Protocol](unpacker.getUint8())
|
|
||||||
)
|
|
||||||
42
src/server/websocket/receive.nim
Normal file
42
src/server/websocket/receive.nim
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import times, tables
|
||||||
|
import ../globals
|
||||||
|
import ../../common/[types, utils, serialize]
|
||||||
|
import mummy
|
||||||
|
import ./send
|
||||||
|
import ../core/[task, listener]
|
||||||
|
|
||||||
|
#[
|
||||||
|
[ Retrieval functions ]
|
||||||
|
Client -> Server
|
||||||
|
]#
|
||||||
|
proc getMessageType*(message: Message): WsMessageAction =
|
||||||
|
var unpacker = Unpacker.init(message.data)
|
||||||
|
return cast[WsMessageAction](unpacker.getUint8())
|
||||||
|
|
||||||
|
proc receiveStartListener*(message: Message) =
|
||||||
|
var unpacker = Unpacker.init(message.data)
|
||||||
|
|
||||||
|
discard unpacker.getUint8()
|
||||||
|
let
|
||||||
|
listenerId = Uuid.toString(unpacker.getUint32())
|
||||||
|
address = unpacker.getDataWithLengthPrefix()
|
||||||
|
port = int(unpacker.getUint16())
|
||||||
|
protocol = cast[Protocol](unpacker.getUint8())
|
||||||
|
cq.ws.sendEventlogItem(LOG_INFO_SHORT, "Attempting to start listener.")
|
||||||
|
cq.listenerStart(listenerId, address, port, protocol)
|
||||||
|
|
||||||
|
proc receiveStopListener*(message: Message) =
|
||||||
|
var unpacker = Unpacker.init(message.data)
|
||||||
|
|
||||||
|
discard unpacker.getUint8()
|
||||||
|
let listenerId = Uuid.toString(unpacker.getUint32())
|
||||||
|
cq.listenerStop(listenerId)
|
||||||
|
|
||||||
|
proc receiveAgentCommand*(message: Message) =
|
||||||
|
var unpacker = Unpacker.init(message.data)
|
||||||
|
|
||||||
|
discard unpacker.getUint8()
|
||||||
|
let
|
||||||
|
agentId = Uuid.toString(unpacker.getUint32())
|
||||||
|
command = unpacker.getDataWithLengthPrefix()
|
||||||
|
|
||||||
79
src/server/websocket/send.nim
Normal file
79
src/server/websocket/send.nim
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import times, tables
|
||||||
|
import ../../common/[types, utils, serialize]
|
||||||
|
import mummy
|
||||||
|
|
||||||
|
#[
|
||||||
|
[ Sending functions ]
|
||||||
|
Server -> Client
|
||||||
|
]#
|
||||||
|
proc sendHeartbeat*(ws: WebSocket) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_HEARTBEAT))
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
|
proc sendEventlogItem*(ws: WebSocket, logType: LogType, message: string, timestamp: int64 = now().toTime().toUnix()) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_EVENT_LOG))
|
||||||
|
packer.add(cast[uint8](logType))
|
||||||
|
packer.add(cast[uint32](timestamp))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(message))
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
|
proc sendConsoleItem*(ws: WebSocket, agentId: string, logType: LogType, message: string, timestamp: int64 = now().toTime().toUnix()) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_CONSOLE_LOG))
|
||||||
|
packer.add(string.toUUid(agentId))
|
||||||
|
packer.add(cast[uint8](logType))
|
||||||
|
packer.add(cast[uint32](timestamp))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(message))
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
|
proc sendAgentCheckin*(ws: WebSocket, agentId: string, timestamp: int64) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_AGENT_CHECKIN))
|
||||||
|
packer.add(string.toUUid(agentId))
|
||||||
|
packer.add(cast[uint32](timestamp))
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
|
proc sendAgentPayload*(ws: WebSocket, payload: seq[byte]) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_AGENT_BINARY))
|
||||||
|
packer.addDataWithLengthPrefix(payload)
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
|
proc sendAgentConnection*(ws: WebSocket, agent: Agent) =
|
||||||
|
var packer = Packer.init()
|
||||||
|
|
||||||
|
packer.add(cast[uint8](CLIENT_AGENT_CONNECTION))
|
||||||
|
packer.add(string.toUuid(agent.agentId))
|
||||||
|
packer.add(string.toUuid(agent.listenerId))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.username))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.hostname))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.domain))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.ip))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.os))
|
||||||
|
packer.addDataWithLengthPrefix(string.toBytes(agent.process))
|
||||||
|
packer.add(uint32(agent.pid))
|
||||||
|
packer.add(uint8(agent.elevated))
|
||||||
|
packer.add(uint32(agent.sleep))
|
||||||
|
packer.add(cast[uint32](agent.firstCheckin))
|
||||||
|
packer.add(cast[uint32](agent.latestCheckin))
|
||||||
|
let data = packer.pack()
|
||||||
|
|
||||||
|
ws.send(Bytes.toString(data), BinaryMessage)
|
||||||
|
|
||||||
Reference in New Issue
Block a user