Started porting over functionality to the ImGui client via websocket communication.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
switch "o", "bin/client"
|
||||
|
||||
switch "d", "client"
|
||||
switch "d", "ImGuiTextSelect"
|
||||
|
||||
# Select compiler
|
||||
|
||||
77
src/client/event/recv.nim
Normal file
77
src/client/event/recv.nim
Normal file
@@ -0,0 +1,77 @@
|
||||
import whisky
|
||||
import times, tables
|
||||
import ../views/[sessions, listeners, console, eventlog]
|
||||
import ../../common/[types, utils, event]
|
||||
export recvEvent
|
||||
|
||||
#[
|
||||
Server -> Client
|
||||
]#
|
||||
|
||||
|
||||
|
||||
|
||||
# proc getMessageType*(message: Message): EventType =
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
# return cast[EventType](unpacker.getUint8())
|
||||
|
||||
# proc receiveAgentPayload*(message: Message): seq[byte] =
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
|
||||
# discard unpacker.getUint8()
|
||||
# return string.toBytes(unpacker.getDataWithLengthPrefix())
|
||||
|
||||
# proc receiveAgentConnection*(message: Message, sessions: ptr SessionsTableComponent) =
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
|
||||
# discard unpacker.getUint8()
|
||||
# let agent = Agent(
|
||||
# agentId: Uuid.toString(unpacker.getUint32()),
|
||||
# listenerId: Uuid.toString(unpacker.getUint32()),
|
||||
# username: unpacker.getDataWithLengthPrefix(),
|
||||
# hostname: unpacker.getDataWithLengthPrefix(),
|
||||
# domain: unpacker.getDataWithLengthPrefix(),
|
||||
# ip: unpacker.getDataWithLengthPrefix(),
|
||||
# os: unpacker.getDataWithLengthPrefix(),
|
||||
# process: unpacker.getDataWithLengthPrefix(),
|
||||
# pid: int(unpacker.getUint32()),
|
||||
# elevated: unpacker.getUint8() != 0,
|
||||
# sleep: int(unpacker.getUint32()),
|
||||
# tasks: @[],
|
||||
# firstCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||
# latestCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||
# )
|
||||
|
||||
# sessions.agents.add(agent)
|
||||
|
||||
# proc receiveAgentCheckin*(message: Message, sessions: ptr SessionsTableComponent)=
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
|
||||
# discard unpacker.getUint8()
|
||||
# let agentId = Uuid.toString(unpacker.getUint32())
|
||||
# let timestamp = cast[int64](unpacker.getUint32())
|
||||
|
||||
# # TODO: Update checkin
|
||||
|
||||
# proc receiveConsoleItem*(message: Message, consoles: ptr Table[string, ConsoleComponent]) =
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
|
||||
# discard unpacker.getUint8()
|
||||
# let
|
||||
# agentId = Uuid.toString(unpacker.getUint32())
|
||||
# logType = cast[LogType](unpacker.getUint8())
|
||||
# timestamp = cast[int64](unpacker.getUint32())
|
||||
# message = unpacker.getDataWithLengthPrefix()
|
||||
|
||||
# consoles[][agentId].addItem(logType, message, timestamp)
|
||||
|
||||
# proc receiveEventlogItem*(message: Message, eventlog: ptr EventlogComponent) =
|
||||
# var unpacker = Unpacker.init(message.data)
|
||||
|
||||
# discard unpacker.getUint8()
|
||||
# let
|
||||
# logType = cast[LogType](unpacker.getUint8())
|
||||
# timestamp = cast[int64](unpacker.getUint32())
|
||||
# message = unpacker.getDataWithLengthPrefix()
|
||||
|
||||
# eventlog[].addItem(logType, message, timestamp)
|
||||
55
src/client/event/send.nim
Normal file
55
src/client/event/send.nim
Normal file
@@ -0,0 +1,55 @@
|
||||
import whisky
|
||||
import times, tables
|
||||
import ../views/[sessions, listeners, console, eventlog]
|
||||
import ../../common/[types, utils, serialize, event]
|
||||
export sendHeartbeat
|
||||
|
||||
#[
|
||||
Client -> Server
|
||||
]#
|
||||
proc sendStartListener*(ws: WebSocket, listener: UIListener) =
|
||||
var packer = Packer.init()
|
||||
|
||||
packer.add(cast[uint8](CLIENT_LISTENER_START))
|
||||
packer.add(string.toUUid(listener.listenerId))
|
||||
packer.addDataWithLengthPrefix(string.toBytes(listener.address))
|
||||
packer.add(cast[uint16](listener.port))
|
||||
packer.add(cast[uint8](listener.protocol))
|
||||
|
||||
let data = packer.pack()
|
||||
|
||||
ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
proc sendStopListener*(ws: WebSocket, listenerId: string) =
|
||||
discard
|
||||
# var packer = Packer.init()
|
||||
|
||||
# packer.add(cast[uint8](CLIENT_LISTENER_STOP))
|
||||
# packer.add(string.toUuid(listenerId))
|
||||
# let data = packer.pack()
|
||||
|
||||
# ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
# proc sendAgentCommand*(ws: WebSocket, agentId: string, command: string) =
|
||||
# var packer = Packer.init()
|
||||
|
||||
# packer.add(cast[uint8](CLIENT_AGENT_COMMAND))
|
||||
# packer.add(string.toUuid(agentId))
|
||||
# packer.addDataWithLengthPrefix(string.toBytes(command))
|
||||
# let data = packer.pack()
|
||||
|
||||
# ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
# proc sendAgentBuild*(ws: WebSocket, listenerId: string, sleepDelay: int, sleepMask: SleepObfuscationTechnique, spoofStack: bool, modules: uint32) =
|
||||
# var packer = Packer.init()
|
||||
|
||||
# packer.add(cast[uint8](CLIENT_AGENT_BUILD))
|
||||
# packer.add(string.toUuid(listenerId))
|
||||
# packer.add(cast[uint32](sleepDelay))
|
||||
# packer.add(cast[uint8](sleepMask))
|
||||
# packer.add(cast[uint8](spoofStack))
|
||||
# packer.add(modules)
|
||||
# let data = packer.pack()
|
||||
|
||||
# ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
[Window][Sessions [Table View]]
|
||||
Pos=10,43
|
||||
Size=1310,279
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Listeners]
|
||||
Pos=10,324
|
||||
Size=1888,665
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Eventlog]
|
||||
Pos=1322,43
|
||||
Size=576,279
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Dear ImGui Demo]
|
||||
Pos=1322,43
|
||||
Size=576,279
|
||||
Collapsed=0
|
||||
DockId=0x00000004,1
|
||||
|
||||
[Window][Dockspace]
|
||||
Pos=0,0
|
||||
Size=1908,999
|
||||
Collapsed=0
|
||||
|
||||
[Window][[FACEDEAD] bob@LAPTOP-02]
|
||||
Pos=10,395
|
||||
Size=1888,594
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][[C9D8E7F6] charlie@SERVER-03]
|
||||
Pos=10,324
|
||||
Size=1888,665
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][[G1H2I3J5] diana@WORKSTATION-04]
|
||||
Pos=10,125
|
||||
Size=784,665
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][[DEADBEEF] alice@DESKTOP-01]
|
||||
Pos=10,324
|
||||
Size=1888,665
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][Example: Console]
|
||||
Pos=10,661
|
||||
Size=2848,1024
|
||||
Collapsed=0
|
||||
DockId=0x00000006,2
|
||||
|
||||
[Window][Example: Assets Browser]
|
||||
Pos=60,60
|
||||
Size=800,480
|
||||
Collapsed=0
|
||||
|
||||
[Window][Example: Documents]
|
||||
Pos=186,108
|
||||
Size=997,993
|
||||
Collapsed=0
|
||||
|
||||
[Window][Example: Log]
|
||||
Pos=119,266
|
||||
Size=1717,576
|
||||
Collapsed=0
|
||||
|
||||
[Window][Same title as another window##1]
|
||||
Pos=274,278
|
||||
Size=754,103
|
||||
Collapsed=1
|
||||
|
||||
[Window][Same title as another window##2]
|
||||
Pos=100,200
|
||||
Size=754,103
|
||||
Collapsed=0
|
||||
DockId=0x00000009,1
|
||||
|
||||
[Window][###AnimatedTitle]
|
||||
Pos=100,200
|
||||
Size=754,103
|
||||
Collapsed=0
|
||||
DockId=0x00000009,0
|
||||
|
||||
[Window][Delete?]
|
||||
Pos=696,412
|
||||
Size=516,175
|
||||
Collapsed=0
|
||||
|
||||
[Window][Stacked 1]
|
||||
Pos=588,335
|
||||
Size=669,457
|
||||
Collapsed=0
|
||||
|
||||
[Window][StartListener]
|
||||
Pos=753,446
|
||||
Size=76,76
|
||||
Collapsed=0
|
||||
|
||||
[Window][Start Listener]
|
||||
Pos=704,387
|
||||
Size=500,225
|
||||
Collapsed=0
|
||||
|
||||
[Window][Dear ImGui Demo/0_E1BADA21]
|
||||
IsChild=1
|
||||
Size=1363,540
|
||||
|
||||
[Window][Generate Payload]
|
||||
Pos=704,161
|
||||
Size=500,677
|
||||
Collapsed=0
|
||||
|
||||
[Window][Generate Payload/0_B6B17D5F]
|
||||
IsChild=1
|
||||
Size=217,310
|
||||
|
||||
[Table][0x32886A44,8]
|
||||
Column 0 Weight=0.6432
|
||||
Column 1 Weight=0.9647
|
||||
Column 2 Weight=0.6694
|
||||
Column 3 Weight=1.0960
|
||||
Column 4 Weight=1.5816
|
||||
Column 5 Weight=1.1551
|
||||
Column 6 Weight=0.4331
|
||||
Column 7 Weight=1.4570
|
||||
|
||||
[Table][0xB6880529,2]
|
||||
RefScale=27
|
||||
Column 0 Sort=0v
|
||||
|
||||
[Table][0x064A67CC,4]
|
||||
Column 0 Weight=1.2081
|
||||
Column 1 Weight=1.3299
|
||||
Column 2 Weight=0.4873
|
||||
Column 3 Weight=0.9746
|
||||
|
||||
[Docking][Data]
|
||||
DockNode ID=0x00000009 Pos=100,200 Size=754,103 Selected=0x64D005CF
|
||||
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=1888,946 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x85940918 SizeRef=1888,279 Split=X
|
||||
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=1310,159 CentralNode=1 Selected=0x61E02D75
|
||||
DockNode ID=0x00000004 Parent=0x00000005 SizeRef=576,159 Selected=0x5E5F7166
|
||||
DockNode ID=0x00000006 Parent=0x85940918 SizeRef=1888,665 Selected=0x6BE22050
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import whisky
|
||||
import tables, strutils
|
||||
import tables, strutils, json, parsetoml
|
||||
import ./utils/appImGui
|
||||
import ./views/[dockspace, sessions, listeners, eventlog, console]
|
||||
import ../common/[types, utils]
|
||||
import ./websocket
|
||||
import ./event/[send, recv]
|
||||
|
||||
import sugar
|
||||
|
||||
proc main() =
|
||||
var app = createApp(1024, 800, imnodes = true, title = "Conquest", docking = true)
|
||||
defer: app.destroyApp()
|
||||
|
||||
var
|
||||
profile: Profile
|
||||
views: Table[string, ptr bool]
|
||||
showConquest = true
|
||||
showSessionsTable = true
|
||||
showSessionsGraph = false
|
||||
showListeners = true
|
||||
showEventlog = true
|
||||
consoles: Table[string, ConsoleComponent]
|
||||
@@ -25,7 +27,6 @@ proc main() =
|
||||
dockTopRight: ImGuiID = 0
|
||||
|
||||
views["Sessions [Table View]"] = addr showSessionsTable
|
||||
views["Sessions [Graph View]"] = addr showSessionsGraph
|
||||
views["Listeners"] = addr showListeners
|
||||
views["Eventlog"] = addr showEventlog
|
||||
|
||||
@@ -58,12 +59,34 @@ proc main() =
|
||||
ws.sendHeartbeat()
|
||||
|
||||
# Receive and parse websocket response message
|
||||
let message = ws.receiveMessage().get()
|
||||
case message.getMessageType()
|
||||
of CLIENT_EVENT_LOG:
|
||||
message.receiveEventlogItem(addr eventlog)
|
||||
else: discard
|
||||
let event = recvEvent(ws.receiveMessage().get())
|
||||
case event.eventType:
|
||||
of CLIENT_PROFILE:
|
||||
profile = parseString(event.data["profile"].getStr())
|
||||
|
||||
of CLIENT_LISTENER_ADD:
|
||||
let listener = event.data.to(UIListener)
|
||||
dump listener.listenerId
|
||||
listenersTable.listeners.add(listener)
|
||||
|
||||
of CLIENT_AGENT_ADD:
|
||||
let agent = event.data.to(UIAgent)
|
||||
dump agent.agentId
|
||||
sessionsTable.agents.add(agent)
|
||||
|
||||
of CLIENT_AGENT_CHECKIN:
|
||||
discard
|
||||
|
||||
of CLIENT_AGENT_PAYLOAD:
|
||||
discard
|
||||
|
||||
of CLIENT_CONSOLE_ITEM:
|
||||
consoles[event.data["agentId"].getStr()].addItem(cast[LogType](event.data["logType"].getInt()), event.data["message"].getStr(), event.timestamp)
|
||||
|
||||
of CLIENT_EVENTLOG_ITEM:
|
||||
eventlog.addItem(cast[LogType](event.data["logType"].getInt()), event.data["message"].getStr(), event.timestamp)
|
||||
|
||||
else: discard
|
||||
|
||||
# Draw/update UI components/views
|
||||
dockspace.draw(addr showConquest, views, addr dockTop, addr dockBottom, addr dockTopLeft, addr dockTopRight)
|
||||
|
||||
@@ -7,7 +7,7 @@ import ../../common/[types]
|
||||
const MAX_INPUT_LENGTH = 512
|
||||
type
|
||||
ConsoleComponent* = ref object of RootObj
|
||||
agent*: Agent
|
||||
agent*: UIAgent
|
||||
showConsole*: bool
|
||||
inputBuffer: array[MAX_INPUT_LENGTH, char]
|
||||
console*: ConsoleItems
|
||||
@@ -42,7 +42,7 @@ proc getLineAtIndex(i: csize_t, data: pointer, outLen: ptr csize_t): cstring {.c
|
||||
outLen[] = line.len.csize_t
|
||||
return line
|
||||
|
||||
proc Console*(agent: Agent): ConsoleComponent =
|
||||
proc Console*(agent: UIAgent): ConsoleComponent =
|
||||
result = new ConsoleComponent
|
||||
result.agent = agent
|
||||
result.showConsole = true
|
||||
|
||||
@@ -3,41 +3,25 @@ import imguin/[cimgui, glfw_opengl, simple]
|
||||
import ../utils/appImGui
|
||||
import ../../common/[types, utils]
|
||||
import ./modals/[startListener, generatePayload]
|
||||
import ../websocket
|
||||
import ../event/send
|
||||
import whisky
|
||||
|
||||
type
|
||||
ListenersTableComponent* = ref object of RootObj
|
||||
title: string
|
||||
listeners*: seq[Listener]
|
||||
listeners*: seq[UIListener]
|
||||
selection: ptr ImGuiSelectionBasicStorage
|
||||
startListenerModal: ListenerModalComponent
|
||||
generatePayloadModal: AgentModalComponent
|
||||
|
||||
let exampleListeners: seq[Listener] = @[
|
||||
Listener(
|
||||
listenerId: "L1234567",
|
||||
address: "192.168.1.1",
|
||||
port: 8080,
|
||||
protocol: HTTP
|
||||
),
|
||||
Listener(
|
||||
listenerId: "L7654321",
|
||||
address: "10.0.0.2",
|
||||
port: 443,
|
||||
protocol: HTTP
|
||||
)
|
||||
]
|
||||
|
||||
proc ListenersTable*(title: string): ListenersTableComponent =
|
||||
result = new ListenersTableComponent
|
||||
result.title = title
|
||||
result.listeners = exampleListeners
|
||||
result.listeners = @[]
|
||||
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||
result.startListenerModal = ListenerModal()
|
||||
result.generatePayloadModal = AgentModal()
|
||||
|
||||
|
||||
proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebSocket) =
|
||||
igBegin(component.title, showComponent, 0)
|
||||
defer: igEnd()
|
||||
@@ -73,7 +57,7 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebS
|
||||
ImGuiTableFlags_ScrollY.int32 or
|
||||
ImGuiTableFlags_ScrollX.int32 or
|
||||
ImGuiTableFlags_NoBordersInBodyUntilResize.int32 or
|
||||
ImGui_TableFlags_SizingStretchProp.int32
|
||||
ImGui_TableFlags_SizingStretchSame.int32
|
||||
)
|
||||
|
||||
let cols: int32 = 4
|
||||
@@ -114,7 +98,7 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, ws: WebS
|
||||
|
||||
if igMenuItem("Stop", nil, false, true):
|
||||
# Update agents table with only non-selected ones
|
||||
var newListeners: seq[Listener] = @[]
|
||||
var newListeners: seq[UIListener] = @[]
|
||||
for i in 0 ..< component.listeners.len():
|
||||
if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)):
|
||||
newListeners.add(component.listeners[i])
|
||||
|
||||
@@ -39,7 +39,7 @@ proc resetModalValues(component: AgentModalComponent) =
|
||||
component.spoofStack = false
|
||||
component.moduleSelection.reset()
|
||||
|
||||
proc draw*(component: AgentModalComponent, listeners: seq[Listener]) =
|
||||
proc draw*(component: AgentModalComponent, listeners: seq[UIListener]) =
|
||||
|
||||
let textSpacing = igGetStyle().ItemSpacing.x
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ proc resetModalValues(component: ListenerModalComponent) =
|
||||
component.port = DEFAULT_PORT
|
||||
component.protocol = 0
|
||||
|
||||
proc draw*(component: ListenerModalComponent): Listener =
|
||||
proc draw*(component: ListenerModalComponent): UIListener =
|
||||
let textSpacing = igGetStyle().ItemSpacing.x
|
||||
|
||||
# Center modal
|
||||
@@ -76,7 +76,7 @@ proc draw*(component: ListenerModalComponent): Listener =
|
||||
|
||||
if igButton("Start", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||
|
||||
result = Listener(
|
||||
result = UIListener(
|
||||
listenerId: generateUUID(),
|
||||
address: $(addr component.address[0]),
|
||||
port: int(component.port),
|
||||
|
||||
@@ -8,85 +8,14 @@ import ../../common/[types, utils]
|
||||
type
|
||||
SessionsTableComponent* = ref object of RootObj
|
||||
title: string
|
||||
agents*: seq[Agent]
|
||||
agents*: seq[UIAgent]
|
||||
selection: ptr ImGuiSelectionBasicStorage
|
||||
consoles: ptr Table[string, ConsoleComponent]
|
||||
|
||||
let exampleAgents: seq[Agent] = @[
|
||||
Agent(
|
||||
agentId: "DEADBEEF",
|
||||
listenerId: "L1234567",
|
||||
username: "alice",
|
||||
hostname: "DESKTOP-01",
|
||||
domain: "corp.local",
|
||||
ip: "192.168.1.10",
|
||||
os: "Windows 10",
|
||||
process: "explorer.exe",
|
||||
pid: 2340,
|
||||
elevated: true,
|
||||
sleep: 60,
|
||||
tasks: @[],
|
||||
firstCheckin: now() - initDuration(hours = 2),
|
||||
latestCheckin: now(),
|
||||
sessionKey: [byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
|
||||
),
|
||||
Agent(
|
||||
agentId: "FACEDEAD",
|
||||
listenerId: "L7654321",
|
||||
username: "bob",
|
||||
hostname: "LAPTOP-02",
|
||||
domain: "corp.local",
|
||||
ip: "10.0.0.5",
|
||||
os: "Windows 11",
|
||||
process: "cmd.exe",
|
||||
pid: 4567,
|
||||
elevated: false,
|
||||
sleep: 120,
|
||||
tasks: @[],
|
||||
firstCheckin: now() - initDuration(hours = 1, minutes = 30),
|
||||
latestCheckin: now() - initDuration(minutes = 5),
|
||||
sessionKey: [byte 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
||||
),
|
||||
Agent(
|
||||
agentId: "C9D8E7F6",
|
||||
listenerId: "L2468135",
|
||||
username: "charlie",
|
||||
hostname: "SERVER-03",
|
||||
domain: "child.corp.local",
|
||||
ip: "172.16.0.20",
|
||||
os: "Windows Server 2019",
|
||||
process: "powershell.exe",
|
||||
pid: 7890,
|
||||
elevated: true,
|
||||
sleep: 30,
|
||||
tasks: @[],
|
||||
firstCheckin: now() - initDuration(hours = 3, minutes = 15),
|
||||
latestCheckin: now() - initDuration(minutes = 10),
|
||||
sessionKey: [byte 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
),
|
||||
Agent(
|
||||
agentId: "G1H2I3J5",
|
||||
listenerId: "L1357924",
|
||||
username: "diana",
|
||||
hostname: "WORKSTATION-04",
|
||||
domain: "external.local",
|
||||
ip: "192.168.2.15",
|
||||
os: "Windows 10",
|
||||
process: "chrome.exe",
|
||||
pid: 3210,
|
||||
elevated: false,
|
||||
sleep: 90,
|
||||
tasks: @[],
|
||||
firstCheckin: now() - initDuration(hours = 4),
|
||||
latestCheckin: now() - initDuration(minutes = 2),
|
||||
sessionKey: [byte 5, 4, 3, 2, 1, 0, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6]
|
||||
)
|
||||
]
|
||||
|
||||
proc SessionsTable*(title: string, consoles: ptr Table[string, ConsoleComponent]): SessionsTableComponent =
|
||||
result = new SessionsTableComponent
|
||||
result.title = title
|
||||
result.agents = exampleAgents
|
||||
result.agents = @[]
|
||||
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
|
||||
result.consoles = consoles
|
||||
|
||||
@@ -97,6 +26,7 @@ proc interact(component: SessionsTableComponent) =
|
||||
while ImGuiSelectionBasicStorage_GetNextSelectedItem(component.selection, addr it, addr row):
|
||||
let agent = component.agents[cast[int](row)]
|
||||
|
||||
|
||||
# Create a new console window
|
||||
if not component.consoles[].hasKey(agent.agentId):
|
||||
component.consoles[][agent.agentId] = Console(agent)
|
||||
@@ -104,7 +34,9 @@ proc interact(component: SessionsTableComponent) =
|
||||
# Focus the existing console window
|
||||
else:
|
||||
igSetWindowFocus_Str(fmt"[{agent.agentId}] {agent.username}@{agent.hostname}")
|
||||
|
||||
|
||||
# TODO: Clear selection properly
|
||||
ImGuiSelectionBasicStorage_Clear(component.selection)
|
||||
|
||||
proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
||||
igBegin(component.title, showComponent, 0)
|
||||
@@ -121,7 +53,7 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
||||
ImGuiTableFlags_ScrollY.int32 or
|
||||
ImGuiTableFlags_ScrollX.int32 or
|
||||
ImGuiTableFlags_NoBordersInBodyUntilResize.int32 or
|
||||
ImGui_TableFlags_SizingStretchProp.int32
|
||||
ImGui_TableFlags_SizingStretchSame.int32
|
||||
)
|
||||
|
||||
let cols: int32 = 8
|
||||
@@ -134,7 +66,7 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
||||
igTableSetupColumn("OS", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Process", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("PID", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Activity", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Last seen", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
|
||||
igTableSetupScrollFreeze(0, 1)
|
||||
igTableHeadersRow()
|
||||
@@ -170,7 +102,17 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
||||
if igTableSetColumnIndex(6):
|
||||
igText($agent.pid)
|
||||
if igTableSetColumnIndex(7):
|
||||
igText(agent.latestCheckin.format("yyyy-MM-dd HH:mm:ss"))
|
||||
let duration = now() - agent.latestCheckin.fromUnix().utc()
|
||||
let totalSeconds = duration.inSeconds
|
||||
|
||||
let hours = totalSeconds div 3600
|
||||
let minutes = (totalSeconds mod 3600) div 60
|
||||
let seconds = totalSeconds mod 60
|
||||
|
||||
let dummyTime = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int)
|
||||
let timeText = dummyTime.format("HH:mm:ss")
|
||||
|
||||
igText(fmt"{timeText} ago")
|
||||
|
||||
# Handle right-click context menu
|
||||
# Right-clicking the table header to hide/show columns or reset the layout is only possible when no sessions are selected
|
||||
@@ -182,7 +124,7 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
||||
|
||||
if igMenuItem("Remove", nil, false, true):
|
||||
# Update agents table with only non-selected ones
|
||||
var newAgents: seq[Agent] = @[]
|
||||
var newAgents: seq[UIAgent] = @[]
|
||||
for i in 0 ..< component.agents.len():
|
||||
if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)):
|
||||
newAgents.add(component.agents[i])
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import times, tables
|
||||
import ../common/[types, utils, serialize]
|
||||
import views/[sessions, listeners, console, eventlog]
|
||||
import whisky
|
||||
|
||||
#[
|
||||
[ Sending Functions ]
|
||||
Client -> Server
|
||||
- Heartbeat
|
||||
- ListenerStart
|
||||
- ListenerStop
|
||||
- AgentBuild
|
||||
- AgentCommand
|
||||
]#
|
||||
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 sendStartListener*(ws: WebSocket, listener: Listener) =
|
||||
var packer = Packer.init()
|
||||
|
||||
packer.add(cast[uint8](CLIENT_LISTENER_START))
|
||||
packer.add(string.toUUid(listener.listenerId))
|
||||
packer.addDataWithLengthPrefix(string.toBytes(listener.address))
|
||||
packer.add(cast[uint16](listener.port))
|
||||
packer.add(cast[uint8](listener.protocol))
|
||||
|
||||
let data = packer.pack()
|
||||
|
||||
ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
proc sendStopListener*(ws: WebSocket, listenerId: string) =
|
||||
var packer = Packer.init()
|
||||
|
||||
packer.add(cast[uint8](CLIENT_LISTENER_STOP))
|
||||
packer.add(string.toUuid(listenerId))
|
||||
let data = packer.pack()
|
||||
|
||||
ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
proc sendAgentCommand*(ws: WebSocket, agentId: string, command: string) =
|
||||
var packer = Packer.init()
|
||||
|
||||
packer.add(cast[uint8](CLIENT_AGENT_COMMAND))
|
||||
packer.add(string.toUuid(agentId))
|
||||
packer.addDataWithLengthPrefix(string.toBytes(command))
|
||||
let data = packer.pack()
|
||||
|
||||
ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
proc sendAgentBuild*(ws: WebSocket, listenerId: string, sleepDelay: int, sleepMask: SleepObfuscationTechnique, spoofStack: bool, modules: uint32) =
|
||||
var packer = Packer.init()
|
||||
|
||||
packer.add(cast[uint8](CLIENT_AGENT_BUILD))
|
||||
packer.add(string.toUuid(listenerId))
|
||||
packer.add(cast[uint32](sleepDelay))
|
||||
packer.add(cast[uint8](sleepMask))
|
||||
packer.add(cast[uint8](spoofStack))
|
||||
packer.add(modules)
|
||||
let data = packer.pack()
|
||||
|
||||
ws.send(Bytes.toString(data), BinaryMessage)
|
||||
|
||||
#[
|
||||
[ Retrieval Functions ]
|
||||
Server -> Client
|
||||
]#
|
||||
proc getMessageType*(message: Message): WsPacketType =
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
return cast[WsPacketType](unpacker.getUint8())
|
||||
|
||||
proc receiveAgentPayload*(message: Message): seq[byte] =
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
|
||||
discard unpacker.getUint8()
|
||||
return string.toBytes(unpacker.getDataWithLengthPrefix())
|
||||
|
||||
proc receiveAgentConnection*(message: Message, sessions: ptr SessionsTableComponent) =
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
|
||||
discard unpacker.getUint8()
|
||||
let agent = Agent(
|
||||
agentId: Uuid.toString(unpacker.getUint32()),
|
||||
listenerId: Uuid.toString(unpacker.getUint32()),
|
||||
username: unpacker.getDataWithLengthPrefix(),
|
||||
hostname: unpacker.getDataWithLengthPrefix(),
|
||||
domain: unpacker.getDataWithLengthPrefix(),
|
||||
ip: unpacker.getDataWithLengthPrefix(),
|
||||
os: unpacker.getDataWithLengthPrefix(),
|
||||
process: unpacker.getDataWithLengthPrefix(),
|
||||
pid: int(unpacker.getUint32()),
|
||||
elevated: unpacker.getUint8() != 0,
|
||||
sleep: int(unpacker.getUint32()),
|
||||
tasks: @[],
|
||||
firstCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||
latestCheckin: cast[int64](unpacker.getUint32()).fromUnix().utc(),
|
||||
)
|
||||
|
||||
sessions.agents.add(agent)
|
||||
|
||||
proc receiveAgentCheckin*(message: Message, sessions: ptr SessionsTableComponent)=
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
|
||||
discard unpacker.getUint8()
|
||||
let agentId = Uuid.toString(unpacker.getUint32())
|
||||
let timestamp = cast[int64](unpacker.getUint32())
|
||||
|
||||
# TODO: Update checkin
|
||||
|
||||
proc receiveConsoleItem*(message: Message, consoles: ptr Table[string, ConsoleComponent]) =
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
|
||||
discard unpacker.getUint8()
|
||||
let
|
||||
agentId = Uuid.toString(unpacker.getUint32())
|
||||
logType = cast[LogType](unpacker.getUint8())
|
||||
timestamp = cast[int64](unpacker.getUint32())
|
||||
message = unpacker.getDataWithLengthPrefix()
|
||||
|
||||
consoles[][agentId].addItem(logType, message, timestamp)
|
||||
|
||||
proc receiveEventlogItem*(message: Message, eventlog: ptr EventlogComponent) =
|
||||
var unpacker = Unpacker.init(message.data)
|
||||
|
||||
discard unpacker.getUint8()
|
||||
let
|
||||
logType = cast[LogType](unpacker.getUint8())
|
||||
timestamp = cast[int64](unpacker.getUint32())
|
||||
message = unpacker.getDataWithLengthPrefix()
|
||||
|
||||
eventlog[].addItem(logType, message, timestamp)
|
||||
Reference in New Issue
Block a user