Skip to content

Commit 721792b

Browse files
committed
feat(ui): surface grpc operation status
1 parent f257780 commit 721792b

14 files changed

Lines changed: 309 additions & 39 deletions

C2Client/C2Client/ConsolePanel.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from .ScriptPanel import Script
2626
from .AssistantPanel import Assistant
2727
from .TerminalModules.Credentials import credentials
28+
from .grpc_status import is_response_ok, response_message
2829

2930

3031
#
@@ -598,8 +599,12 @@ def runCommand(self):
598599
command=commandLine,
599600
)
600601
response = self.grpcClient.getCommandHelp(command)
601-
self.printInTerminal(response.command, "", "")
602-
self.printInTerminal("", response.command, response.help)
602+
command_text = getattr(response, "command", commandLine) or commandLine
603+
self.printInTerminal(command_text, "", "")
604+
if is_response_ok(response):
605+
self.printInTerminal("", command_text, response.help)
606+
else:
607+
self.printInTerminal("", command_text, response_message(response, "No help available."))
603608

604609
else:
605610
self.printInTerminal(commandLine, "", "")
@@ -614,10 +619,20 @@ def runCommand(self):
614619
)
615620
result = self.grpcClient.sendSessionCommand(command)
616621
command_id = getattr(result, "command_id", command_id) or command_id
622+
if not is_response_ok(result):
623+
message = response_message(result, "Command was rejected by TeamServer.")
624+
self.printInTerminal("", commandLine, message)
625+
with open(os.path.join(logsDir, self.logFileName), 'a') as logFile:
626+
logFile.write('[+] rejected: \"' + commandLine + '\"')
627+
logFile.write('\n' + message + '\n')
628+
self.setCursorEditorAtEnd()
629+
return
630+
617631
context = "Host " + self.hostname + " - Username " + self.username
618632
self.consoleScriptSignal.emit("send", self.beaconHash, self.listenerHash, context, commandLine, "", command_id)
619-
if result.message:
620-
self.printInTerminal("", commandLine, result.message)
633+
ack_message = response_message(result)
634+
if ack_message:
635+
self.printInTerminal("", commandLine, ack_message)
621636

622637
self.setCursorEditorAtEnd()
623638

@@ -630,6 +645,8 @@ def displayResponse(self):
630645
listener_hash = response.session.listener_hash or self.listenerHash
631646
command_text = response.command or response.instruction
632647
decoded_response = response.output.decode('utf-8', 'replace')
648+
if not is_response_ok(response):
649+
decoded_response = response_message(response) or decoded_response or "Command failed."
633650
self.consoleScriptSignal.emit("receive", self.beaconHash, listener_hash, context, command_text, decoded_response, command_id)
634651
self.setCursorEditorAtEnd()
635652
# check the response for mimikatz and not the cmd line ???

C2Client/C2Client/ListenerPanel.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020

2121
from .grpcClient import TeamServerApi_pb2
22+
from .grpc_status import is_response_ok, operation_ack_text
2223

2324

2425
#
@@ -76,6 +77,8 @@ def __init__(self, parent, grpcClient):
7677

7778
self.label = QLabel(ListenerTabTitle)
7879
self.layout.addWidget(self.label)
80+
self.statusLabel = QLabel("")
81+
self.layout.addWidget(self.statusLabel)
7982

8083
# List of sessions
8184
self.listListener = QTableWidget()
@@ -106,6 +109,13 @@ def __init__(self, parent, grpcClient):
106109

107110
self.setLayout(self.layout)
108111

112+
def setStatusMessage(self, ack, successFallback):
113+
message = operation_ack_text(ack, successFallback)
114+
self.statusLabel.setText(message)
115+
if is_response_ok(ack):
116+
self.statusLabel.setStyleSheet("color: #0a7f2e;")
117+
else:
118+
self.statusLabel.setStyleSheet("color: #b00020;")
109119

110120
def __del__(self):
111121
self.getListenerWorker.quit()
@@ -166,14 +176,16 @@ def addListener(self, message):
166176
type=message[0],
167177
ip=message[1],
168178
port=int(message[2]))
169-
self.grpcClient.addListener(listener)
179+
ack = self.grpcClient.addListener(listener)
180+
self.setStatusMessage(ack, "Listener command accepted.")
170181

171182

172183
# send message for stoping a listener
173184
def stopListener(self, listenerHash):
174185
listener = TeamServerApi_pb2.ListenerSelector(
175186
listener_hash=listenerHash)
176-
self.grpcClient.stopListener(listener)
187+
ack = self.grpcClient.stopListener(listener)
188+
self.setStatusMessage(ack, "Listener stop command accepted.")
177189

178190

179191
# query the server to get the list of listeners

C2Client/C2Client/Scripts/checkSandbox.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import uuid
22

33
from ..grpcClient import TeamServerApi_pb2
4+
from ..grpc_status import is_response_ok, response_message
45

56

67
def OnSessionStart(grpcClient, beaconHash, listenerHash, hostname, username, arch, privilege, os, lastProofOfLife, killed):
@@ -18,5 +19,7 @@ def OnSessionStart(grpcClient, beaconHash, listenerHash, hostname, username, arc
1819
command_id=uuid.uuid4().hex,
1920
)
2021
result = grpcClient.sendSessionCommand(command)
22+
if not is_response_ok(result):
23+
output += response_message(result, "Command was rejected by TeamServer.") + "\n"
2124

2225
return output

C2Client/C2Client/Scripts/listDirectory.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import uuid
22

33
from ..grpcClient import TeamServerApi_pb2
4+
from ..grpc_status import is_response_ok, response_message
45

56

67
def OnSessionStart(grpcClient, beaconHash, listenerHash, hostname, username, arch, privilege, os, lastProofOfLife, killed):
@@ -17,6 +18,8 @@ def OnSessionStart(grpcClient, beaconHash, listenerHash, hostname, username, arc
1718
command_id=uuid.uuid4().hex,
1819
)
1920
result = grpcClient.sendSessionCommand(command)
21+
if not is_response_ok(result):
22+
output += response_message(result, "Command was rejected by TeamServer.") + "\n"
2023

2124
# commandLine = "ls"
2225
# command = TeamServerApi_pb2.SessionCommandRequest(session=TeamServerApi_pb2.SessionSelector(beacon_hash=beaconHash, listener_hash=listenerHash), command=commandLine, command_id=uuid.uuid4().hex)

C2Client/C2Client/Scripts/startListenerHttp8443.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from ..grpcClient import TeamServerApi_pb2
2+
from ..grpc_status import operation_ack_text
23

34

45
def OnStart(grpcClient):
@@ -9,7 +10,9 @@ def OnStart(grpcClient):
910
ip="0.0.0.0",
1011
port=8443)
1112

12-
grpcClient.addListener(listener)
13+
ack = grpcClient.addListener(listener)
14+
message = operation_ack_text(ack, "Listener command accepted.")
15+
if message:
16+
output += message + "\n"
1317

1418
return output
15-

C2Client/C2Client/SessionPanel.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616

1717
from .grpcClient import TeamServerApi_pb2
18+
from .grpc_status import is_response_ok, operation_ack_text
1819

1920

2021
#
@@ -57,6 +58,8 @@ def __init__(self, parent, grpcClient):
5758

5859
self.label = QLabel('Sessions')
5960
self.layout.addWidget(self.label)
61+
self.statusLabel = QLabel("")
62+
self.layout.addWidget(self.statusLabel)
6063

6164
# List of sessions
6265
self.listSession = QTableWidget()
@@ -86,6 +89,13 @@ def __init__(self, parent, grpcClient):
8689

8790
self.setLayout(self.layout)
8891

92+
def setStatusMessage(self, ack, successFallback):
93+
message = operation_ack_text(ack, successFallback)
94+
self.statusLabel.setText(message)
95+
if is_response_ok(ack):
96+
self.statusLabel.setStyleSheet("color: #0a7f2e;")
97+
else:
98+
self.statusLabel.setStyleSheet("color: #b00020;")
8999

90100
def resizeEvent(self, event):
91101
super().resizeEvent(event)
@@ -140,7 +150,8 @@ def actionClicked(self, action):
140150
def stopSession(self, beaconHash, listenerHash):
141151
session = TeamServerApi_pb2.SessionSelector(
142152
beacon_hash=beaconHash, listener_hash=listenerHash)
143-
self.grpcClient.stopSession(session)
153+
ack = self.grpcClient.stopSession(session)
154+
self.setStatusMessage(ack, "Session stop command accepted.")
144155
self.listSessions()
145156

146157

C2Client/C2Client/TerminalModules/Credentials/credentials.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import re
33

44
from ...grpcClient import GrpcClient
5+
from ...grpc_status import is_response_ok, terminal_response_text
56

67
GetCredentialsInstruction = "getCred"
78
AddCredentialsInstruction = "addCred"
@@ -11,7 +12,9 @@ def getCredentials(grpcClient: GrpcClient, TeamServerApi_pb2):
1112
commandTeamServer = GetCredentialsInstruction
1213
termCommand = TeamServerApi_pb2.TerminalCommandRequest(command=commandTeamServer, data=b"")
1314
resultTermCommand = grpcClient.executeTerminalCommand(termCommand)
14-
result = resultTermCommand.result
15+
result = terminal_response_text(resultTermCommand)
16+
if not is_response_ok(resultTermCommand):
17+
raise RuntimeError(result)
1518
return result
1619

1720

@@ -25,7 +28,9 @@ def addCredentials(grpcClient: GrpcClient,TeamServerApi_pb2, cred: str):
2528
commandTeamServer = AddCredentialsInstruction
2629
termCommand = TeamServerApi_pb2.TerminalCommandRequest(command=commandTeamServer, data=cred.encode())
2730
resultTermCommand = grpcClient.executeTerminalCommand(termCommand)
28-
result = resultTermCommand.result
31+
result = terminal_response_text(resultTermCommand)
32+
if not is_response_ok(resultTermCommand):
33+
raise RuntimeError(result)
2934
return result
3035

3136

0 commit comments

Comments
 (0)