From bcf845288c0f6359bfc6d1449fa8fd2a1af0ffcf Mon Sep 17 00:00:00 2001 From: Jakob Friedl <71284620+jakobfriedl@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:16:17 +0200 Subject: [PATCH] Implemented widgets for showing loot: Downloads & Screenshots. Textures are read from a byte sequence and displayed in the UI. Currently tested using hard-coded values. --- src/agent/nim.cfg | 4 +- src/client/main.nim | 11 +- src/client/utils/opengl/loadImage.nim | 49 ++++++++ src/client/views/dockspace.nim | 20 ++-- src/client/views/loot/downloads.nim | 107 +++++++++++++++-- src/client/views/loot/screenshots.nim | 125 ++++++++++++++++++-- src/client/views/modals/generatePayload.nim | 2 +- src/common/types.nim | 35 ++++-- 8 files changed, 302 insertions(+), 51 deletions(-) diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index c885968..025ec32 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -3,6 +3,6 @@ -d:release --opt:size --passL:"-s" # Strip symbols, such as sensitive function names --d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" --d:MODULES="127" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:MODULES="255" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/client/main.nim b/src/client/main.nim index d719f41..9052503 100644 --- a/src/client/main.nim +++ b/src/client/main.nim @@ -2,8 +2,8 @@ import whisky import tables, strutils, strformat, json, parsetoml, base64, os # native_dialogs import ./utils/[appImGui, globals] import ./views/[dockspace, sessions, listeners, eventlog, console] +import ./views/loot/[screenshots, downloads] import ./views/modals/generatePayload -import ./views/loot/[downloads, screenshots] import ../common/[types, utils, crypto] import ./core/websocket @@ -33,8 +33,8 @@ proc main(ip: string = "localhost", port: int = 37573) = views["Sessions [Table View]"] = addr showSessionsTable views["Listeners"] = addr showListeners views["Eventlog"] = addr showEventlog - views["Loot::Downloads"] = addr showDownloads - views["Loot::Screenshots"] = addr showScreenshots + views["Loot:Downloads"] = addr showDownloads + views["Loot:Screenshots"] = addr showScreenshots # Create components var @@ -43,7 +43,8 @@ proc main(ip: string = "localhost", port: int = 37573) = listenersTable = ListenersTable("Listeners") eventlog = Eventlog("Eventlog") lootDownloads = LootDownloads("Downloads") - lootScreenshots = LootScreenshots("Screenshots") + lootScreenshots = LootScreenshots("Screenshots") + let io = igGetIO() @@ -174,7 +175,7 @@ proc main(ip: string = "localhost", port: int = 37573) = # This is done to ensure that closed console windows can be opened again consoles = newConsoleTable - # igShowDemoWindow(nil) + igShowDemoWindow(nil) # render app.render() diff --git a/src/client/utils/opengl/loadImage.nim b/src/client/utils/opengl/loadImage.nim index a9eb715..6a49404 100644 --- a/src/client/utils/opengl/loadImage.nim +++ b/src/client/utils/opengl/loadImage.nim @@ -147,3 +147,52 @@ when not defined(SDL): else: echo "Not found: ",iconName glfw.setWindowIcon(window, 0, nil) + +# Load a texture from a byte sequence, as this is the data type that is received by the team server +proc loadTextureFromBytes*(imageBytes: seq[byte], textureID: var uint32): tuple[width: int, height: int] = + var width, height, channels: int + + var imageLen = imageBytes.len() + + # Decode image from memory + let imageData = stbi.load_from_memory( + imageBytes, + width, + height, + channels, + stbi.RGBA + ) + + if imageData == @[]: + raise newException(IOError, "Failed to decode image from bytes") + + # Create texture if needed + if textureID == 0: + glGenTextures(1, addr textureID) + + glBindTexture(GL_TEXTURE_2D, textureID) + + # Setup filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR.GLint) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR.GLint) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE.GLint) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE.GLint) + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) + + # Upload texture + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA.GLint, + width.GLSizei, + height.GLSizei, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + addr imageData[0]) + + let err = glGetError().int + if err != 0: + raise newException(IOError, fmt"OpenGL Error [0x{err:X}]: glTexImage2D()") + + result = (width: width, height: height) diff --git a/src/client/views/dockspace.nim b/src/client/views/dockspace.nim index 037e298..2f67746 100644 --- a/src/client/views/dockspace.nim +++ b/src/client/views/dockspace.nim @@ -76,18 +76,18 @@ proc draw*(component: DockspaceComponent, showComponent: ptr bool, views: Table[ if igBeginMenu("Views", true): # Create a menu item to toggle each of the main views of the application for view, showView in views: - if not view.contains("::"): + if not view.startsWith("Loot:"): if igMenuItem(view, nil, showView[], showView != nil): - showView[] = not showView[] - - if igBeginMenu("Loot", true): - for view, showView in views: - if view.startsWith("Loot"): - let item = view.split("::", 1)[1].strip() - if igMenuItem(item, nil, showView[], showView != nil): - showView[] = not showView[] - igEndMenu() + showView[] = not showView[] + if igBeginMenu("Loot", true): + for view, showView in views: + if view.startsWith("Loot:"): + let itemName = view.split(":")[1] + if igMenuItem(itemName, nil, showView[], showView != nil): + showView[] = not showView[] + igEndMenu() + igEndMenu() igEndMenuBar() \ No newline at end of file diff --git a/src/client/views/loot/downloads.nim b/src/client/views/loot/downloads.nim index 77aed0c..9855153 100644 --- a/src/client/views/loot/downloads.nim +++ b/src/client/views/loot/downloads.nim @@ -1,19 +1,106 @@ import strformat, strutils, times import imguin/[cimgui, glfw_opengl, simple] import ../../utils/[appImGui, colors] -import ../../../common/types +import ../../../common/[types, utils] -type - LootDownloadsComponent* = ref object of RootObj - title: string +type + DownloadsComponent* = ref object of RootObj + title: string + items: seq[LootItem] + selectedIndex: int + - -proc LootDownloads*(title: string): LootDownloadsComponent = - result = new LootDownloadsComponent +proc LootDownloads*(title: string): DownloadsComponent = + result = new DownloadsComponent result.title = title + result.items = @[] + result.selectedIndex = -1 -proc draw*(component: LootDownloadsComponent, showComponent: ptr bool) = + result.items.add(@[LootItem( + agentId: "DEADBEEF", + path: "C:\\Software\\Conquest\\README.md", + timestamp: now().toTime().toUnix(), + size: 1000, + host: "WKS-1", + data: string.toBytes("README.md\nPreview\nHello world.") + ), + LootItem( + agentId: "DEADBEEF", + path: "C:\\Software\\Conquest\\README.md", + timestamp: now().toTime().toUnix(), + size: 1000, + host: "WKS-1", + data: string.toBytes("README.md\nPreview\nHello world.") + ) + ]) + +proc draw*(component: DownloadsComponent, showComponent: ptr bool) = igBegin(component.title, showComponent, 0) - defer: igEnd() + defer: igEnd() - igText("asd") + var availableSize: ImVec2 + igGetContentRegionAvail(addr availableSize) + let textSpacing = igGetStyle().ItemSpacing.x + + # Left panel (file table) + let childFlags = ImGui_ChildFlags_ResizeX.int32 or ImGui_ChildFlags_NavFlattened.int32 + if igBeginChild_Str("##Left", vec2(availableSize.x * 0.66f, 0.0f), childFlags, ImGui_WindowFlags_None.int32): + + let tableFlags = ( + ImGui_TableFlags_Resizable.int32 or + ImGui_TableFlags_Reorderable.int32 or + ImGui_TableFlags_Hideable.int32 or + ImGui_TableFlags_HighlightHoveredColumn.int32 or + ImGui_TableFlags_RowBg.int32 or + ImGui_TableFlags_BordersV.int32 or + ImGui_TableFlags_BordersH.int32 or + ImGui_TableFlags_ScrollY.int32 or + ImGui_TableFlags_ScrollX.int32 or + ImGui_TableFlags_NoBordersInBodyUntilResize.int32 or + ImGui_TableFlags_SizingStretchSame.int32 + ) + + let cols: int32 = 4 + if igBeginTable("##Items", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f): + igTableSetupColumn("Path", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Creation Date", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Size", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Host", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupScrollFreeze(0, 1) + igTableHeadersRow() + + for i, item in component.items: + igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f) + + if igTableSetColumnIndex(0): + igPushID_Int(i.int32) + let isSelected = component.selectedIndex == i + if igSelectable_Bool(item.path.cstring, isSelected, ImGuiSelectableFlags_SpanAllColumns.int32 or ImGuiSelectableFlags_AllowOverlap.int32, vec2(0, 0)): + component.selectedIndex = i + igPopID() + + if igTableSetColumnIndex(1): + igText(item.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")) + + if igTableSetColumnIndex(2): + igText($item.size) + + if igTableSetColumnIndex(3): + igText(item.host.cstring) + + igEndTable() + + igEndChild() + igSameLine(0.0f, 0.0f) + + # Right panel (file content) + if igBeginChild_Str("##Preview", vec2(0.0f, 0.0f), ImGui_ChildFlags_Borders.int32, ImGui_WindowFlags_None.int32): + + if component.selectedIndex >= 0 and component.selectedIndex < component.items.len: + let item = component.items[component.selectedIndex] + + igText(item.path) + + else: + igText("Select item to preview contents") + igEndChild() \ No newline at end of file diff --git a/src/client/views/loot/screenshots.nim b/src/client/views/loot/screenshots.nim index f894371..55b31b2 100644 --- a/src/client/views/loot/screenshots.nim +++ b/src/client/views/loot/screenshots.nim @@ -1,19 +1,124 @@ -import strformat, strutils, times +import strformat, strutils, times, os, tables import imguin/[cimgui, glfw_opengl, simple] import ../../utils/[appImGui, colors] -import ../../../common/types +import ../../../common/[types, utils] -type - LootScreenshotsComponent* = ref object of RootObj - title: string +type + ScreenshotTexture* = ref object + textureId*: GLuint + width: int + height: int + ScreenshotsComponent* = ref object of RootObj + title: string + items: seq[LootItem] + selectedIndex: int + textures: Table[string, ScreenshotTexture] -proc LootScreenshots*(title: string): LootScreenshotsComponent = - result = new LootScreenshotsComponent +proc LootScreenshots*(title: string): ScreenshotsComponent = + result = new ScreenshotsComponent result.title = title + result.items = @[] + result.selectedIndex = -1 -proc draw*(component: LootScreenshotsComponent, showComponent: ptr bool) = + result.items.add(@[LootItem( + agentId: "DEADBEEF", + timestamp: now().toTime().toUnix(), + size: 1000, + path: "/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/570DCB57/screenshot_1757769346.bmp", + host: "WKS-1", + data: string.toBytes(readFile("/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/570DCB57/screenshot_1757769346.bmp")) + ), + LootItem( + agentId: "DEADBEEF", + timestamp: now().toTime().toUnix(), + path: "/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/C2468819/screenshot_1759238569.png", + size: 1000, + host: "WKS-1", + data: string.toBytes(readFile("/mnt/c/Users/jakob/Documents/Projects/conquest/data/loot/C2468819/screenshot_1759238569.png")) + ) + ]) + + result.textures = initTable[string, ScreenshotTexture]() + + for item in result.items: + var textureId: GLuint + let (width, height) = loadTextureFromBytes(item.data, textureId) + + result.textures[item.path] = ScreenshotTexture( + textureId: textureId, + width: width, + height: height + ) + +proc draw*(component: ScreenshotsComponent, showComponent: ptr bool) = igBegin(component.title, showComponent, 0) - defer: igEnd() + defer: igEnd() - igText("asd") + var availableSize: ImVec2 + igGetContentRegionAvail(addr availableSize) + let textSpacing = igGetStyle().ItemSpacing.x + + # Left panel (file table) + let childFlags = ImGui_ChildFlags_ResizeX.int32 or ImGui_ChildFlags_NavFlattened.int32 + if igBeginChild_Str("##Left", vec2(availableSize.x * 0.66f, 0.0f), childFlags, ImGui_WindowFlags_None.int32): + + let tableFlags = ( + ImGui_TableFlags_Resizable.int32 or + ImGui_TableFlags_Reorderable.int32 or + ImGui_TableFlags_Hideable.int32 or + ImGui_TableFlags_HighlightHoveredColumn.int32 or + ImGui_TableFlags_RowBg.int32 or + ImGui_TableFlags_BordersV.int32 or + ImGui_TableFlags_BordersH.int32 or + ImGui_TableFlags_ScrollY.int32 or + ImGui_TableFlags_ScrollX.int32 or + ImGui_TableFlags_NoBordersInBodyUntilResize.int32 or + ImGui_TableFlags_SizingStretchSame.int32 + ) + + let cols: int32 = 4 + if igBeginTable("##Items", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f): + igTableSetupColumn("Path", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Creation Date", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Size", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupColumn("Host", ImGuiTableColumnFlags_None.int32, 0.0f, 0) + igTableSetupScrollFreeze(0, 1) + igTableHeadersRow() + + for i, item in component.items: + igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f) + + if igTableSetColumnIndex(0): + igPushID_Int(i.int32) + let isSelected = component.selectedIndex == i + if igSelectable_Bool(item.path.cstring, isSelected, ImGuiSelectableFlags_SpanAllColumns.int32 or ImGuiSelectableFlags_AllowOverlap.int32, vec2(0, 0)): + component.selectedIndex = i + igPopID() + + if igTableSetColumnIndex(1): + igText(item.timestamp.fromUnix().local().format("dd-MM-yyyy HH:mm:ss")) + + if igTableSetColumnIndex(2): + igText($item.size) + + if igTableSetColumnIndex(3): + igText(item.host.cstring) + + igEndTable() + + igEndChild() + igSameLine(0.0f, 0.0f) + + # Right panel (file content) + if igBeginChild_Str("##Preview", vec2(0.0f, 0.0f), ImGui_ChildFlags_Borders.int32, ImGui_WindowFlags_None.int32): + + if component.selectedIndex >= 0 and component.selectedIndex < component.items.len: + let item = component.items[component.selectedIndex] + let texture = component.textures[item.path] + + igImage(ImTextureRef(internal_TexData: nil, internal_TexID: texture.textureId), vec2(texture.width, texture.height), vec2(0, 0), vec2(1, 1)) + + else: + igText("Select item to preview contents") + igEndChild() \ No newline at end of file diff --git a/src/client/views/modals/generatePayload.nim b/src/client/views/modals/generatePayload.nim index aa0314e..d181fda 100644 --- a/src/client/views/modals/generatePayload.nim +++ b/src/client/views/modals/generatePayload.nim @@ -143,7 +143,7 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui igText("Build log: ") try: - # Set styles of the eventlog window + # Set styles of the log window igPushStyleColor_Vec4(ImGui_Col_FrameBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f)) igPushStyleColor_Vec4(ImGui_Col_ScrollbarBg.int32, vec4(0.1f, 0.1f, 0.1f, 1.0f)) igPushStyleColor_Vec4(ImGui_Col_Border.int32, vec4(0.2f, 0.2f, 0.2f, 1.0f)) diff --git a/src/common/types.nim b/src/common/types.nim index 05fcfe1..e96916e 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -53,17 +53,6 @@ type CMD_DOTNET = 16'u16 CMD_SLEEPMASK = 17'u16 - ModuleType* = enum - MODULE_ALL = 0'u32 - MODULE_SLEEP = 1'u32 - MODULE_SHELL = 2'u32 - MODULE_BOF = 4'u32 - MODULE_DOTNET = 8'u32 - MODULE_FILESYSTEM = 16'u32 - MODULE_FILETRANSFER = 32'u32 - MODULE_SCREENSHOT = 64'u32 - MODULE_SITUATIONAL_AWARENESS = 128'u32 - StatusType* = enum STATUS_COMPLETED = 0'u8 STATUS_FAILED = 1'u8 @@ -100,6 +89,17 @@ type ZILEAN = 2'u8 FOLIAGE = 3'u8 + ModuleType* = enum + MODULE_ALL = 0'u32 + MODULE_SLEEP = 1'u32 + MODULE_SHELL = 2'u32 + MODULE_BOF = 4'u32 + MODULE_DOTNET = 8'u32 + MODULE_FILESYSTEM = 16'u32 + MODULE_FILETRANSFER = 32'u32 + MODULE_SCREENSHOT = 64'u32 + MODULE_SITUATIONAL_AWARENESS = 128'u32 + # Custom iterator for ModuleType, as it uses powers of 2 instead of standard increments iterator items*(e: typedesc[ModuleType]): ModuleType = yield MODULE_SLEEP @@ -264,8 +264,9 @@ type CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary CLIENT_CONSOLE_ITEM = 105'u8 # Add entry to a agent's console CLIENT_EVENTLOG_ITEM = 106'u8 # Add entry to the eventlog - CLIENT_BUILDLOG_ITEM = 107'u8 # Add entry to the build log - CLIENT_LOOT = 108'u8 # Download file or screenshot to the operator desktop + CLIENT_BUILDLOG_ITEM = 107'u8 # Add entry to the build log + CLIENT_LOOT_ADD = 108'u8 # Add file or screenshot stored on the team server to preview on the client + CLIENT_SYNC_LOOT = 109'u8 # Download a file/screenshot to the operator desktop Event* = object eventType*: EventType @@ -347,3 +348,11 @@ type sleepTechnique*: SleepObfuscationTechnique spoofStack*: bool modules*: uint32 + + LootItem* = ref object + agentId*: string + path*: string + timestamp*: int64 + size*: int + host*: string + data*: seq[byte]