Skip to content

Commit c8dcd21

Browse files
authored
Maj client (#20)
1 parent e6d5b8c commit c8dcd21

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1338
-272
lines changed

.github/workflows/Release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
2020
# You can convert this to a matrix build if you need cross-platform coverage.
2121
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
22-
runs-on: ubuntu-latest
22+
runs-on: ubuntu-20.04
2323

2424
steps:
2525
- uses: actions/checkout@v4

.github/workflows/Tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
1212
# You can convert this to a matrix build if you need cross-platform coverage.
1313
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
14-
runs-on: ubuntu-latest
14+
runs-on: ubuntu-20.04
1515

1616
steps:
1717
- uses: actions/checkout@v4

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
build*
21
Tests
3-
.vscode/
2+
C2Client/build/
3+
.vscode
4+
build/

C2Client/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
C2Client.egg-info
2+
C2Client/__pycache__

C2Client/C2Client/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.termHistory
2+
.cmdHistory
3+
*.exe
4+
*.dll
Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,29 @@
1010
from grpcClient import *
1111

1212
from TerminalPanel import *
13+
from ScriptPanel import *
1314

1415
sys.path.insert(1, './Credentials')
1516
import credentials
1617

18+
19+
#
20+
# Log
21+
#
22+
try:
23+
import pkg_resources
24+
logsDir = pkg_resources.resource_filename(
25+
'C2Client',
26+
'logs'
27+
)
28+
29+
except ImportError:
30+
logsDir = os.path.join(os.path.dirname(__file__), 'logs')
31+
32+
if not os.path.exists(logsDir):
33+
os.makedirs(logsDir)
34+
35+
1736
#
1837
# Constant
1938
#
@@ -270,14 +289,10 @@
270289
#
271290
class ConsolesTab(QWidget):
272291

273-
def __init__(self, parent, ip, port, devMode):
292+
def __init__(self, parent, grpcClient):
274293
super(QWidget, self).__init__(parent)
275294
widget = QWidget(self)
276295
self.layout = QHBoxLayout(widget)
277-
278-
self.ip = ip
279-
self.port = port
280-
self.devMode = devMode
281296

282297
# Initialize tab screen
283298
self.tabs = QTabWidget()
@@ -288,11 +303,21 @@ def __init__(self, parent, ip, port, devMode):
288303
self.layout.addWidget(self.tabs)
289304
self.setLayout(self.layout)
290305

306+
self.grpcClient = grpcClient
307+
291308
tab = QWidget()
292309
self.tabs.addTab(tab, TerminalTabTitle)
293310
tab.layout = QVBoxLayout(self.tabs)
294-
terminal = Terminal(self, self.ip, self.port, self.devMode)
295-
tab.layout.addWidget(terminal)
311+
self.terminal = Terminal(self, self.grpcClient)
312+
tab.layout.addWidget(self.terminal)
313+
tab.setLayout(tab.layout)
314+
self.tabs.setCurrentIndex(self.tabs.count()-1)
315+
316+
tab = QWidget()
317+
self.tabs.addTab(tab, "Script")
318+
tab.layout = QVBoxLayout(self.tabs)
319+
self.script = Script(self, self.grpcClient)
320+
tab.layout.addWidget(self.script)
296321
tab.setLayout(tab.layout)
297322
self.tabs.setCurrentIndex(self.tabs.count()-1)
298323

@@ -314,7 +339,8 @@ def addConsole(self, beaconHash, listenerHash, hostname, username):
314339
tab = QWidget()
315340
self.tabs.addTab(tab, beaconHash[0:8])
316341
tab.layout = QVBoxLayout(self.tabs)
317-
console = Console(self, self.ip, self.port, self.devMode, beaconHash, listenerHash, hostname, username)
342+
console = Console(self, self.grpcClient, beaconHash, listenerHash, hostname, username)
343+
console.consoleScriptSignal.connect(self.script.consoleScriptMethod)
318344
tab.layout.addWidget(console)
319345
tab.setLayout(tab.layout)
320346
self.tabs.setCurrentIndex(self.tabs.count()-1)
@@ -328,18 +354,21 @@ def closeTab(self, currentIndex):
328354

329355

330356
class Console(QWidget):
357+
358+
consoleScriptSignal = pyqtSignal(str, str, str, str, str)
359+
331360
tabPressed = pyqtSignal()
332361
beaconHash=""
333362
hostname=""
334363
username=""
335364
logFileName=""
336365
listenerHash=""
337366

338-
def __init__(self, parent, ip, port, devMode, beaconHash, listenerHash, hostname, username):
367+
def __init__(self, parent, grpcClient, beaconHash, listenerHash, hostname, username):
339368
super(QWidget, self).__init__(parent)
340369
self.layout = QVBoxLayout(self)
341370

342-
self.grpcClient = GrpcClient(ip, port, devMode)
371+
self.grpcClient = grpcClient
343372

344373
self.beaconHash=beaconHash
345374
self.listenerHash=listenerHash
@@ -412,7 +441,7 @@ def runCommand(self):
412441
cmdHistoryFile.write('\n')
413442
cmdHistoryFile.close()
414443

415-
logFile = open("./logs/"+self.logFileName, 'a')
444+
logFile = open(logsDir+"/"+self.logFileName, 'a')
416445
logFile.write('[+] send: \"' + commandLine + '\"')
417446
logFile.write('\n')
418447
logFile.close()
@@ -429,6 +458,7 @@ def runCommand(self):
429458
self.printInTerminal(commandLine, "", "")
430459
command = TeamServerApi_pb2.Command(beaconHash=self.beaconHash, listenerHash=self.listenerHash, cmd=commandLine)
431460
result = self.grpcClient.sendCmdToSession(command)
461+
self.consoleScriptSignal.emit("send", self.beaconHash, self.listenerHash, commandLine, "")
432462
if result.message:
433463
self.printInTerminal("", commandLine, result.message.decode(encoding="latin1", errors="ignore"))
434464

@@ -438,14 +468,15 @@ def displayResponse(self):
438468
session = TeamServerApi_pb2.Session(beaconHash=self.beaconHash)
439469
responses = self.grpcClient.getResponseFromSession(session)
440470
for response in responses:
471+
self.consoleScriptSignal.emit("receive", "", "", response.cmd, response.response.decode(encoding="latin1", errors="ignore"))
441472
self.setCursorEditorAtEnd()
442473
# check the response for mimikatz and not the cmd line ???
443474
if "-e mimikatz.exe" in response.cmd:
444475
credentials.handleMimikatzCredentials(response.response.decode(encoding="latin1", errors="ignore"), self.grpcClient, TeamServerApi_pb2)
445476
self.printInTerminal("", response.instruction + " " + response.cmd, response.response.decode(encoding="latin1", errors="ignore"))
446477
self.setCursorEditorAtEnd()
447478

448-
logFile = open("./logs/"+self.logFileName, 'a')
479+
logFile = open(logsDir+"/"+self.logFileName, 'a')
449480
logFile.write('[+] result: \"' + response.instruction + " " + response.cmd + '\"')
450481
logFile.write('\n' + response.response.decode(encoding="latin1", errors="ignore") + '\n')
451482
logFile.write('\n')
File renamed without changes.

client/GUI.py renamed to C2Client/C2Client/GUI.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import sys
2+
import os
23
import signal
34
import argparse
4-
from threading import Thread, Lock
5+
import logging
6+
57
from PyQt5.QtWidgets import *
68
from PyQt5.QtGui import *
79
from PyQt5.QtCore import *
810

11+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
12+
913
from grpcClient import *
1014
from ListenerPanel import *
1115
from SessionPanel import *
@@ -14,6 +18,7 @@
1418

1519
import qdarktheme
1620

21+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
1722

1823
signal.signal(signal.SIGINT, signal.SIG_DFL)
1924

@@ -27,6 +32,11 @@ def __init__(self, ip, port, devMode):
2732
self.port = port
2833
self.devMode = devMode
2934

35+
try:
36+
self.grpcClient = GrpcClient(self.ip, self.port, self.devMode)
37+
except ValueError as e:
38+
raise e
39+
3040
self.createPayloadWindow = None
3141

3242
self.title = 'Exploration C2'
@@ -51,7 +61,12 @@ def __init__(self, ip, port, devMode):
5161
self.topLayout()
5262
self.botLayout()
5363

64+
self.sessionsWidget.sessionScriptSignal.connect(self.consoleWidget.script.sessionScriptMethod)
65+
self.listenersWidget.listenerScriptSignal.connect(self.consoleWidget.script.listenerScriptMethod)
66+
5467
self.sessionsWidget.interactWithSession.connect(self.consoleWidget.addConsole)
68+
69+
self.consoleWidget.script.mainScriptMethod("start", "", "", "")
5570

5671
self.show()
5772

@@ -64,27 +79,28 @@ def topLayout(self):
6479

6580
self.m_main.layout = QHBoxLayout(self.m_main)
6681
self.m_main.layout.setContentsMargins(0, 0, 0, 0)
67-
self.sessionsWidget = Sessions(self, self.ip, self.port, self.devMode)
82+
self.sessionsWidget = Sessions(self, self.grpcClient)
6883
self.m_main.layout.addWidget(self.sessionsWidget)
69-
self.listenersWidget = Listeners(self, self.ip, self.port, self.devMode)
84+
self.listenersWidget = Listeners(self, self.grpcClient)
7085
self.m_main.layout.addWidget( self.listenersWidget)
7186

7287
self.topWidget.addTab(self.m_main, "Main")
7388

74-
self.graphWidget = Graph(self, self.ip, self.port, self.devMode)
89+
self.graphWidget = Graph(self, self.grpcClient)
7590
self.topWidget.addTab(self.graphWidget, "Graph")
7691

7792
self.mainLayout.addWidget(self.topWidget, 1, 1, 1, 1)
7893

7994

8095
def botLayout(self):
8196

82-
self.consoleWidget = ConsolesTab(self, self.ip, self.port, self.devMode)
97+
self.consoleWidget = ConsolesTab(self, self.grpcClient)
8398
self.mainLayout.addWidget(self.consoleWidget, 2, 0, 1, 2)
8499

85100

86101
def __del__(self):
87-
print("Exit")
102+
if hasattr(self, 'consoleWidget'):
103+
self.consoleWidget.script.mainScriptMethod("stop", "", "", "")
88104

89105

90106
def payloadForm(self):
@@ -93,8 +109,7 @@ def payloadForm(self):
93109
self.createPayloadWindow.show()
94110

95111

96-
if __name__ == '__main__':
97-
112+
def main():
98113
parser = argparse.ArgumentParser(description='TeamServer IP and port.')
99114
parser.add_argument('--ip', default='127.0.0.1', help='IP address (default: 127.0.0.1)')
100115
parser.add_argument('--port', type=int, default=50051, help='Port number (default: 50051)')
@@ -105,5 +120,12 @@ def payloadForm(self):
105120
app = QApplication(sys.argv)
106121
app.setStyleSheet(qdarktheme.load_stylesheet())
107122

108-
ex = App(args.ip, args.port, args.dev)
123+
try:
124+
ex = App(args.ip, args.port, args.dev)
125+
except ValueError as e:
126+
sys.exit(1)
109127
sys.exit(app.exec_())
128+
129+
130+
if __name__ == "__main__":
131+
main()

0 commit comments

Comments
 (0)