diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index 02d118e..e4784a2 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="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="511" -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 b8d6f6e..2e2cd98 100644 --- a/src/client/main.nim +++ b/src/client/main.nim @@ -96,6 +96,9 @@ proc main(ip: string = "localhost", port: int = 37573) = sessionsTable.agents.add(agent) sessionsTable.agentActivity[agent.agentId] = agent.latestCheckin + if not agent.impersonationToken.isEmptyOrWhitespace(): + sessionsTable.agentImpersonation[agent.agentId] = agent.impersonationToken + # Initialize position of console windows to bottom by drawing them once when they are added # By default, the consoles are attached to the same DockNode as the Listeners table (Default: bottom), # so if you place your listeners somewhere else, the console windows show up somewhere else too @@ -171,6 +174,16 @@ proc main(ip: string = "localhost", port: int = 37573) = of SCREENSHOT: lootScreenshots.addTexture(lootItem.lootId, data) else: discard + + of CLIENT_IMPERSONATE_TOKEN: + let + agentId = event.data["agentId"].getStr() + impersonationToken = event.data["username"].getStr() + sessionsTable.agentImpersonation[agentId] = impersonationToken + + of CLIENT_REVERT_TOKEN: + echo event.data["agentId"].getStr() + sessionsTable.agentImpersonation.del(event.data["agentId"].getStr()) else: discard diff --git a/src/client/views/sessions.nim b/src/client/views/sessions.nim index a3dd5ba..340f8de 100644 --- a/src/client/views/sessions.nim +++ b/src/client/views/sessions.nim @@ -9,7 +9,8 @@ type SessionsTableComponent* = ref object of RootObj title: string agents*: seq[UIAgent] - agentActivity*: Table[string, int64] # Direct O(1) access to latest checkin + agentActivity*: Table[string, int64] # Direct O(1) access to latest checkin + agentImpersonation*: Table[string, string] selection: ptr ImGuiSelectionBasicStorage consoles: ptr Table[string, ConsoleComponent] @@ -45,6 +46,8 @@ proc interact(component: SessionsTableComponent) = proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = igBegin(component.title, showComponent, 0) + let textSpacing = igGetStyle().ItemSpacing.x + let tableFlags = ( ImGuiTableFlags_Resizable.int32 or ImGuiTableFlags_Reorderable.int32 or @@ -59,7 +62,7 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = ImGui_TableFlags_SizingStretchSame.int32 ) - let cols: int32 = 12 + let cols: int32 = 11 if igBeginTable("Sessions", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f): igTableSetupColumn("AgentID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0) @@ -68,7 +71,6 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = igTableSetupColumn("IP (External)", ImGuiTableColumnFlags_DefaultHide.int32, 0.0f, 0) igTableSetupColumn("Username", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0) - igTableSetupColumn("Domain", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("OS", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Process", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("PID", ImGuiTableColumnFlags_None.int32, 0.0f, 0) @@ -104,18 +106,26 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = if igTableSetColumnIndex(3): igText(agent.ipExternal) if igTableSetColumnIndex(4): + + if not agent.domain.isEmptyOrWhitespace(): + igText(agent.domain & "\\") + igSameLine(0.0f, 0.0f) + igText(agent.username) + + if component.agentImpersonation.hasKey(agent.agentId): + igSameLine(0.0f, textSpacing) + igText(fmt"[{component.agentImpersonation[agent.agentId]}]") + if igTableSetColumnIndex(5): igText(agent.hostname) if igTableSetColumnIndex(6): - igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain) - if igTableSetColumnIndex(7): igText(agent.os) - if igTableSetColumnIndex(8): + if igTableSetColumnIndex(7): igText(agent.process) - if igTableSetColumnIndex(9): + if igTableSetColumnIndex(8): igText($agent.pid) - if igTableSetColumnIndex(10): + if igTableSetColumnIndex(9): let duration = now() - agent.firstCheckin.fromUnix().local() let totalSeconds = duration.inSeconds @@ -126,7 +136,7 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = let timeText = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int).format("HH:mm:ss") igText(fmt"{timeText} ago") - if igTableSetColumnIndex(11): + if igTableSetColumnIndex(10): let duration = now() - component.agentActivity[agent.agentId].fromUnix().local() let totalSeconds = duration.inSeconds diff --git a/src/common/types.nim b/src/common/types.nim index 77c9f0c..2821ba4 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -55,6 +55,8 @@ type CMD_MAKE_TOKEN = 18'u16 CMD_STEAL_TOKEN = 19'u16 CMD_REV2SELF = 20'u16 + CMD_TOKEN_GET_PRIV = 21'u16 + CMD_TOKEN_SET_PRIV = 22'u16 StatusType* = enum STATUS_COMPLETED = 0'u8 @@ -195,6 +197,7 @@ type agentId*: string listenerId*: string username*: string + impersonationToken*: string hostname*: string domain*: string ipInternal*: string @@ -215,6 +218,7 @@ type agentId*: string listenerId*: string username*: string + impersonationToken*: string hostname*: string domain*: string ipInternal*: string @@ -275,6 +279,8 @@ type 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, only sends metadata and not the actual file content CLIENT_LOOT_DATA = 109'u8 # Send file/screenshot bytes to the client to display as preview or to download to the client desktop + CLIENT_IMPERSONATE_TOKEN = 110'u8 # Access token impersonated + CLIENT_REVERT_TOKEN = 111'u8 # Revert to original logon session Event* = object eventType*: EventType diff --git a/src/modules/token.nim b/src/modules/token.nim index c90aded..0795c1a 100644 --- a/src/modules/token.nim +++ b/src/modules/token.nim @@ -16,7 +16,7 @@ let module* = Module( description: protect("Create an access token from username and password."), example: protect("make-token LAB\\john Password123!"), arguments: @[ - Argument(name: protect("domain\\username"), description: protect("Account domain and username."), argumentType: STRING, isRequired: true), + Argument(name: protect("domain\\username"), description: protect("Account domain and username. For impersonating local users, use .\\username."), argumentType: STRING, isRequired: true), Argument(name: protect("password"), description: protect("Account password."), argumentType: STRING, isRequired: true), Argument(name: protect("logonType"), description: protect("Logon type (https://learn.microsoft.com/en-us/windows-server/identity/securing-privileged-access/reference-tools-logon-types)."), argumentType: INT, isRequired: false) ], @@ -63,6 +63,9 @@ when defined(agent): if task.argCount == 3: logonType = cast[DWORD](Bytes.toUint32(task.args[2].data)) + # Revert current token before creating a new one + discard rev2self() + if not makeToken(userParts[1], password, userParts[0], logonType): return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(protect("Failed to create token."))) return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(fmt"Impersonated {username}.")) diff --git a/src/server/api/handlers.nim b/src/server/api/handlers.nim index 230b29f..96165fc 100644 --- a/src/server/api/handlers.nim +++ b/src/server/api/handlers.nim @@ -99,6 +99,20 @@ proc handleResult*(resultData: seq[byte]) = cq.client.sendConsoleItem(agentId, LOG_SUCCESS, fmt"Task {taskId} completed.") cq.success(fmt"Task {taskId} completed.") cq.agents[agentId].tasks = cq.agents[agentId].tasks.filterIt(it.taskId != taskResult.taskId) + + # Handle additional actions or UI-events based on command type (only when command succeeded) + case cast[CommandType](taskResult.command): + of CMD_MAKE_TOKEN: + let impersonationToken: string = Bytes.toString(taskResult.data).split(" ")[1][0..^2] # Remove trailing '.' character from the domain\username string + if cq.dbUpdateTokenImpersonation(agentId, impersonationToken): + cq.agents[agentId].impersonationToken = impersonationToken + cq.client.sendImpersonateToken(agentId, impersonationToken) + of CMD_REV2SELF: + if cq.dbUpdateTokenImpersonation(agentId, ""): + cq.agents[agentId].impersonationToken.setLen(0) + cq.client.sendRevertToken(agentId) + else: discard + of STATUS_FAILED: cq.client.sendConsoleItem(agentId, LOG_ERROR, fmt"Task {taskId} failed.") cq.error(fmt"Task {taskId} failed.") @@ -138,11 +152,8 @@ proc handleResult*(resultData: seq[byte]) = host: cq.agents[agentId].hostname ) - # Store loot in database - if not cq.dbStoreLoot(lootItem): - raise newException(ValueError, fmt"Failed to store loot in database." & "\n") - # Send loot to client to display file/screenshot in the UI + discard cq.dbStoreLoot(lootItem) cq.client.sendLoot(lootItem) cq.output(fmt"File downloaded to {downloadPath} ({$fileData.len()} bytes).", "\n") diff --git a/src/server/core/packer.nim b/src/server/core/packer.nim index 840ae9c..879c6aa 100644 --- a/src/server/core/packer.nim +++ b/src/server/core/packer.nim @@ -114,6 +114,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string): agentId: Uuid.toString(header.agentId), listenerId: Uuid.toString(listenerId), username: username, + impersonationToken: "", hostname: hostname, domain: domain, ipInternal: ipInternal, diff --git a/src/server/core/websocket.nim b/src/server/core/websocket.nim index 3b9cfbf..d0577d6 100644 --- a/src/server/core/websocket.nim +++ b/src/server/core/websocket.nim @@ -9,6 +9,7 @@ proc `%`*(agent: Agent): JsonNode = result["agentId"] = %agent.agentId result["listenerId"] = %agent.listenerId result["username"] = %agent.username + result["impersonationToken"] = %agent.impersonationToken result["hostname"] = %agent.hostname result["domain"] = %agent.domain result["ipInternal"] = %agent.ipInternal @@ -188,5 +189,28 @@ proc sendLootData*(client: WsConnection, loot: LootItem, data: string) = "data": encode(data) } ) + if client != nil: + client.ws.sendEvent(event, client.sessionKey) + +proc sendImpersonateToken*(client: WsConnection, agentId: string, username: string) = + let event = Event( + eventType: CLIENT_IMPERSONATE_TOKEN, + timestamp: now().toTime().toUnix(), + data: %*{ + "agentId": agentId, + "username": username + } + ) + if client != nil: + client.ws.sendEvent(event, client.sessionKey) + +proc sendRevertToken*(client: WsConnection, agentId: string) = + let event = Event( + eventType: CLIENT_REVERT_TOKEN, + timestamp: now().toTime().toUnix(), + data: %*{ + "agentId": agentId + } + ) if client != nil: client.ws.sendEvent(event, client.sessionKey) \ No newline at end of file diff --git a/src/server/db/database.nim b/src/server/db/database.nim index 2fc360c..9042e06 100644 --- a/src/server/db/database.nim +++ b/src/server/db/database.nim @@ -28,6 +28,7 @@ proc dbInit*(cq: Conquest) = process TEXT NOT NULL, pid INTEGER NOT NULL, username TEXT NOT NULL, + impersonationToken TEXT NOT NULL, hostname TEXT NOT NULL, domain TEXT NOT NULL, ipInternal TEXT NOT NULL, diff --git a/src/server/db/dbAgent.nim b/src/server/db/dbAgent.nim index 789bf48..16d7351 100644 --- a/src/server/db/dbAgent.nim +++ b/src/server/db/dbAgent.nim @@ -15,9 +15,9 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool = let sessionKeyBlob = agent.sessionKey.toSeq() conquestDb.exec(""" - INSERT INTO agents (agentId, listenerId, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - """, agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.hostname, agent.domain, agent.ipInternal, agent.ipExternal, agent.os, agent.elevated, agent.sleep, agent.modules, agent.firstCheckin, agent.latestCheckin, sessionKeyBlob) + INSERT INTO agents (agentId, listenerId, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + """, agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.impersonationToken, agent.hostname, agent.domain, agent.ipInternal, agent.ipExternal, agent.os, agent.elevated, agent.sleep, agent.modules, agent.firstCheckin, agent.latestCheckin, sessionKeyBlob) conquestDb.close() except: @@ -32,8 +32,8 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] = try: let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) - for row in conquestDb.iterate("SELECT agentId, listenerId, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents;"): - let (agentId, listenerId, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte])) + for row in conquestDb.iterate("SELECT agentId, listenerId, sleep, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents;"): + let (agentId, listenerId, sleep, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte])) # Convert session key blob back to array var sessionKey: Key @@ -49,6 +49,7 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] = sleep: sleep, pid: pid, username: username, + impersonationToken: impersonationToken, hostname: hostname, domain: domain, ipInternal: ipInternal, @@ -128,11 +129,11 @@ proc dbDeleteAgentByName*(cq: Conquest, agentId: string): bool = return true -proc dbAgentExists*(cq: Conquest, agentName: string): bool = +proc dbAgentExists*(cq: Conquest, agentId: string): bool = try: let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) - let res = conquestDb.one("SELECT 1 FROM agents WHERE agentId = ? LIMIT 1", agentName) + let res = conquestDb.one("SELECT 1 FROM agents WHERE agentId = ? LIMIT 1", agentId) conquestDb.close() @@ -141,11 +142,11 @@ proc dbAgentExists*(cq: Conquest, agentName: string): bool = cq.error(getCurrentExceptionMsg()) return false -proc dbUpdateSleep*(cq: Conquest, agentName: string, delay: int): bool = +proc dbUpdateTokenImpersonation*(cq: Conquest, agentId: string, impersonationToken: string): bool = try: let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) - conquestDb.exec("UPDATE agents SET sleep = ? WHERE agentId = ?", delay, agentName) + conquestDb.exec("UPDATE agents SET impersonationToken = ? WHERE agentId = ?", impersonationToken, agentId) conquestDb.close() return true diff --git a/src/server/db/dbListener.nim b/src/server/db/dbListener.nim index fc034d9..bb5b5cc 100644 --- a/src/server/db/dbListener.nim +++ b/src/server/db/dbListener.nim @@ -1,4 +1,4 @@ -import strformat, strutils, system, terminal, tiny_sqlite +import strformat, system, terminal, tiny_sqlite import ../core/logger import ../../common/types