Implemented callback host system to support HTTP redirectors
This commit is contained in:
@@ -179,72 +179,69 @@ proc addItem*(component: ConsoleComponent, itemType: LogType, data: string, time
|
||||
itemType: itemType,
|
||||
text: line
|
||||
))
|
||||
|
||||
#[
|
||||
Handling console commands
|
||||
]#
|
||||
proc displayHelp(component: ConsoleComponent) =
|
||||
for module in getModules(component.agent.modules):
|
||||
for cmd in module.commands:
|
||||
component.addItem(LOG_OUTPUT, fmt" * {cmd.name:<15}{cmd.description}")
|
||||
proc displayHelp(component: ConsoleComponent) =
|
||||
for module in getModules(component.agent.modules):
|
||||
for cmd in module.commands:
|
||||
component.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(15) & cmd.description)
|
||||
component.addItem(LOG_OUTPUT, "")
|
||||
|
||||
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
|
||||
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
|
||||
var usage = command.name & " " & command.arguments.mapIt(
|
||||
if it.isRequired: fmt"<{it.name}>" else: fmt"[{it.name}]"
|
||||
if it.isRequired: "<" & it.name & ">" else: "[" & it.name & "]"
|
||||
).join(" ")
|
||||
|
||||
if command.example != "":
|
||||
usage &= "\nExample : " & command.example
|
||||
|
||||
component.addItem(LOG_OUTPUT, fmt"""
|
||||
{command.description}
|
||||
|
||||
Usage : {usage}
|
||||
""")
|
||||
|
||||
|
||||
component.addItem(LOG_OUTPUT, command.description)
|
||||
component.addItem(LOG_OUTPUT, "Usage : " & usage)
|
||||
|
||||
if command.example != "":
|
||||
component.addItem(LOG_OUTPUT, "Example : " & command.example)
|
||||
|
||||
if command.arguments.len > 0:
|
||||
component.addItem(LOG_OUTPUT, "Arguments:\n")
|
||||
|
||||
let header = @["Name", "Type", "Required", "Description"]
|
||||
component.addItem(LOG_OUTPUT, fmt" {header[0]:<15} {header[1]:<6} {header[2]:<8} {header[3]}")
|
||||
component.addItem(LOG_OUTPUT, fmt" {'-'.repeat(15)} {'-'.repeat(6)} {'-'.repeat(8)} {'-'.repeat(20)}")
|
||||
component.addItem(LOG_OUTPUT, "Arguments:")
|
||||
|
||||
for arg in command.arguments:
|
||||
let header = @["Name", "Type", "Required", "Description"]
|
||||
component.addItem(LOG_OUTPUT, " " & header[0].alignLeft(15) & " " & header[1].alignLeft(6) & " " & header[2].alignLeft(8) & " " & header[3])
|
||||
component.addItem(LOG_OUTPUT, " " & '-'.repeat(15) & " " & '-'.repeat(6) & " " & '-'.repeat(8) & " " & '-'.repeat(20))
|
||||
|
||||
for arg in command.arguments:
|
||||
let isRequired = if arg.isRequired: "YES" else: "NO"
|
||||
component.addItem(LOG_OUTPUT, fmt" * {arg.name:<15} {($arg.argumentType).toUpperAscii():<6} {isRequired:>8} {arg.description}")
|
||||
component.addItem(LOG_OUTPUT, " * " & arg.name.alignLeft(15) & " " & ($arg.argumentType).toUpperAscii().alignLeft(6) & " " & isRequired.align(8) & " " & arg.description)
|
||||
component.addItem(LOG_OUTPUT, "")
|
||||
|
||||
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
|
||||
try:
|
||||
proc handleHelp(component: ConsoleComponent, parsed: seq[string]) =
|
||||
try:
|
||||
# Try parsing the first argument passed to 'help' as a command
|
||||
component.displayCommandHelp(getCommandByName(parsed[1]))
|
||||
except IndexDefect:
|
||||
# 'help' command is called without additional parameters
|
||||
component.displayHelp()
|
||||
except ValueError:
|
||||
except ValueError:
|
||||
# Command was not found
|
||||
component.addItem(LOG_ERROR, fmt"The command '{parsed[1]}' does not exist.")
|
||||
|
||||
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
|
||||
component.addItem(LOG_ERROR, "The command '" & parsed[1] & "' does not exist.")
|
||||
|
||||
proc handleAgentCommand*(component: ConsoleComponent, connection: WsConnection, input: string) =
|
||||
# Convert user input into sequence of string arguments
|
||||
let parsedArgs = parseInput(input)
|
||||
|
||||
# Handle 'help' command
|
||||
if parsedArgs[0] == "help":
|
||||
# Handle 'help' command
|
||||
if parsedArgs[0] == "help":
|
||||
component.handleHelp(parsedArgs)
|
||||
return
|
||||
|
||||
# Handle commands with actions on the agent
|
||||
try:
|
||||
try:
|
||||
let
|
||||
command = getCommandByName(parsedArgs[0])
|
||||
task = createTask(component.agent.agentId, component.agent.listenerId, command, parsedArgs[1..^1])
|
||||
|
||||
connection.sendAgentTask(component.agent.agentId, input, task)
|
||||
component.addItem(LOG_INFO, fmt"Tasked agent to {command.description.toLowerAscii()} ({Uuid.toString(task.taskId)})")
|
||||
component.addItem(LOG_INFO, "Tasked agent to " & command.description.toLowerAscii() & " (" & Uuid.toString(task.taskId) & ")")
|
||||
|
||||
except CatchableError:
|
||||
except CatchableError:
|
||||
component.addItem(LOG_ERROR, getCurrentExceptionMsg())
|
||||
|
||||
#[
|
||||
@@ -254,7 +251,7 @@ proc print(item: ConsoleItem) =
|
||||
|
||||
if item.timestamp > 0:
|
||||
let timestamp = item.timestamp.fromUnix().format("dd-MM-yyyy HH:mm:ss")
|
||||
igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), fmt"[{timestamp}]".cstring)
|
||||
igTextColored(vec4(0.6f, 0.6f, 0.6f, 1.0f), "[" & timestamp & "]")
|
||||
igSameLine(0.0f, 0.0f)
|
||||
|
||||
case item.itemType:
|
||||
|
||||
@@ -64,12 +64,13 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, connecti
|
||||
ImGui_TableFlags_SizingStretchSame.int32
|
||||
)
|
||||
|
||||
let cols: int32 = 4
|
||||
let cols: int32 = 5
|
||||
if igBeginTable("Listeners", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
|
||||
|
||||
igTableSetupColumn("ListenerID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Port", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Callback Hosts", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
igTableSetupColumn("Protocol", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||
|
||||
igTableSetupScrollFreeze(0, 1)
|
||||
@@ -93,6 +94,9 @@ proc draw*(component: ListenersTableComponent, showComponent: ptr bool, connecti
|
||||
if igTableSetColumnIndex(2):
|
||||
igText($listener.port)
|
||||
if igTableSetColumnIndex(3):
|
||||
for host in listener.hosts.split(";"):
|
||||
igText(host)
|
||||
if igTableSetColumnIndex(4):
|
||||
igText($listener.protocol)
|
||||
|
||||
# Handle right-click context menu
|
||||
|
||||
@@ -7,22 +7,25 @@ const DEFAULT_PORT = 8080'u16
|
||||
|
||||
type
|
||||
ListenerModalComponent* = ref object of RootObj
|
||||
address: array[256, char]
|
||||
port: uint16
|
||||
callbackHosts: array[256 * 32, char]
|
||||
bindAddress: array[256, char]
|
||||
bindPort: uint16
|
||||
protocol: int32
|
||||
protocols: seq[string]
|
||||
|
||||
proc ListenerModal*(): ListenerModalComponent =
|
||||
result = new ListenerModalComponent
|
||||
zeroMem(addr result.address[0], 256)
|
||||
result.port = DEFAULT_PORT
|
||||
zeroMem(addr result.callbackHosts[0], 256 * 32)
|
||||
zeroMem(addr result.bindAddress[0], 256)
|
||||
result.bindPort = DEFAULT_PORT
|
||||
result.protocol = 0
|
||||
for p in Protocol.low .. Protocol.high:
|
||||
result.protocols.add($p)
|
||||
|
||||
proc resetModalValues(component: ListenerModalComponent) =
|
||||
zeroMem(addr component.address[0], 256)
|
||||
component.port = DEFAULT_PORT
|
||||
zeroMem(addr component.callbackHosts[0], 256 * 32)
|
||||
zeroMem(addr component.bindAddress[0], 256)
|
||||
component.bindPort = DEFAULT_PORT
|
||||
component.protocol = 0
|
||||
|
||||
proc draw*(component: ListenerModalComponent): UIListener =
|
||||
@@ -43,27 +46,40 @@ proc draw*(component: ListenerModalComponent): UIListener =
|
||||
defer: igEndPopup()
|
||||
|
||||
var availableSize: ImVec2
|
||||
igGetContentRegionAvail(addr availableSize)
|
||||
|
||||
# Listener address
|
||||
igText("Host: ")
|
||||
# Listener protocol/type dropdown selection
|
||||
igText("Protocol: ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igGetContentRegionAvail(addr availableSize)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igInputTextWithHint("##InputAddress", "127.0.0.1", addr component.address[0], 256, ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
|
||||
|
||||
# Listener port
|
||||
let step: uint16 = 1
|
||||
igText("Port: ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igInputScalar("##InputPort", ImGuiDataType_U16.int32, addr component.port, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
||||
|
||||
# Listener protocol dropdown selection
|
||||
igText("Protocol: ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igCombo_Str("##InputProtocol", addr component.protocol, (component.protocols.join("\0") & "\0").cstring , component.protocols.len().int32)
|
||||
|
||||
igDummy(vec2(0.0f, 10.0f))
|
||||
igSeparator()
|
||||
igDummy(vec2(0.0f, 10.0f))
|
||||
|
||||
# HTTP Listener settings
|
||||
if component.protocols[component.protocol] == $HTTP:
|
||||
# Callback hosts
|
||||
igText("Hosts (Callback): ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igGetContentRegionAvail(addr availableSize)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igInputTextMultiline("##InputCallbackHosts", addr component.callbackHosts[0], 256 * 32, vec2(0.0f, 3.0f * igGetTextLineHeightWithSpacing()), ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
|
||||
|
||||
# Listener bindAddress
|
||||
igText("Host (Bind): ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igGetContentRegionAvail(addr availableSize)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igInputTextWithHint("##InputAddressBind", "0.0.0.0", addr component.bindAddress[0], 256, ImGui_InputTextFlags_CharsNoBlank.int32, nil, nil)
|
||||
|
||||
# Listener bindPort
|
||||
let step: uint16 = 1
|
||||
igText("Port (Bind): ")
|
||||
igSameLine(0.0f, textSpacing)
|
||||
igSetNextItemWidth(availableSize.x)
|
||||
igInputScalar("##InputPortBind", ImGuiDataType_U16.int32, addr component.bindPort, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
||||
|
||||
igGetContentRegionAvail(addr availableSize)
|
||||
|
||||
@@ -72,13 +88,40 @@ proc draw*(component: ListenerModalComponent): UIListener =
|
||||
igDummy(vec2(0.0f, 10.0f))
|
||||
|
||||
# Only enabled the start button when valid values have been entered
|
||||
igBeginDisabled(($(addr component.address[0]) == "") or (component.port <= 0))
|
||||
igBeginDisabled(($(addr component.bindAddress[0]) == "") or (component.bindPort <= 0))
|
||||
|
||||
if igButton("Start", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||
if igButton("Start", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
|
||||
|
||||
# Process input values
|
||||
var hosts: string = ""
|
||||
let
|
||||
callbackHosts = $(addr component.callbackHosts[0])
|
||||
bindAddress = $(addr component.bindAddress[0])
|
||||
bindPort = int(component.bindPort)
|
||||
|
||||
if callbackHosts.isEmptyOrWhitespace():
|
||||
hosts &= bindAddress & ":" & $bindPort
|
||||
|
||||
else:
|
||||
for host in callbackHosts.splitLines():
|
||||
hosts &= ";"
|
||||
let hostParts = host.split(":")
|
||||
if hostParts.len() == 2:
|
||||
if not hostParts[1].isEmptyOrWhitespace():
|
||||
hosts &= hostParts[0] & ":" & hostParts[1]
|
||||
else:
|
||||
hosts &= hostParts[0] & ":" & $bindPort
|
||||
elif hostParts.len() == 1 and not hostParts[0].isEmptyOrWhitespace():
|
||||
hosts &= hostParts[0] & ":" & $bindPort
|
||||
|
||||
hosts.removePrefix(";")
|
||||
|
||||
# Return new listener object
|
||||
result = UIListener(
|
||||
listenerId: generateUUID(),
|
||||
address: $(addr component.address[0]),
|
||||
port: int(component.port),
|
||||
hosts: hosts,
|
||||
address: bindAddress,
|
||||
port: bindPort,
|
||||
protocol: cast[Protocol](component.protocol)
|
||||
)
|
||||
component.resetModalValues()
|
||||
|
||||
Reference in New Issue
Block a user