1
+ import sys , socket , getopt , threading , subprocess , signal , time
2
+
3
+
4
+ class NetCat :
5
+ def __init__ (self , target , port ):
6
+ self .listen = False
7
+ self .command = False
8
+ self .upload = False
9
+ self .execute = ""
10
+ self .target = target
11
+ self .upload_destination = ""
12
+ self .port = port
13
+ self .running = True
14
+ self .threads = []
15
+
16
+ def signal_handler (self , signum , frame ):
17
+ print ('\n [*] User requested an interrupt. Exiting gracefully.' )
18
+ self .running = False
19
+ time .sleep (0.5 )
20
+ sys .exit (0 )
21
+
22
+ def run_command (self , cmd ):
23
+ cmd = cmd .rstrip ()
24
+ try :
25
+ output = subprocess .check_output (cmd , stderr = subprocess .STDOUT , shell = True )
26
+ except subprocess .CalledProcessError as e :
27
+ output = e .output
28
+ except Exception as e :
29
+ output = str (e ).encode ()
30
+ return output
31
+
32
+ def handle_client (self , client_socket ):
33
+ try :
34
+ if len (self .upload_destination ):
35
+ file_buffer = ""
36
+ while self .running :
37
+ try :
38
+ data = client_socket .recv (1024 )
39
+ if not data :
40
+ break
41
+ else :
42
+ file_buffer += data .decode ('utf-8' )
43
+ except (ConnectionResetError , BrokenPipeError ) as e :
44
+ print (f"[!] Connection error during upload: { str (e )} " )
45
+ break
46
+ except Exception as e :
47
+ print (f"[!] Error receiving data: { str (e )} " )
48
+ break
49
+
50
+ try :
51
+ with open (self .upload_destination , "wb" ) as file_descriptor :
52
+ file_descriptor .write (file_buffer .encode ('utf-8' ))
53
+ try :
54
+ client_socket .send (
55
+ f"Successfully saved file to { self .upload_destination } \r \n " .encode ('utf-8' ))
56
+ except (BrokenPipeError , ConnectionResetError ):
57
+ print ("[!] Couldn't send success message - connection lost" )
58
+ except OSError as e :
59
+ print (f"[!] File operation failed: { str (e )} " )
60
+ try :
61
+ client_socket .send (
62
+ f"Failed to save file to { self .upload_destination } \r \n " .encode ('utf-8' ))
63
+ except (BrokenPipeError , ConnectionResetError ):
64
+ print ("[!] Couldn't send error message - connection lost" )
65
+
66
+ if len (self .execute ) and self .running :
67
+ try :
68
+ output = self .run_command (self .execute )
69
+ client_socket .send (output )
70
+ except (BrokenPipeError , ConnectionResetError ):
71
+ print ("[!] Couldn't send command output - connection lost" )
72
+ except Exception as e :
73
+ print (f"[!] Error executing command: { str (e )} " )
74
+
75
+ if self .command :
76
+ while self .running :
77
+ try :
78
+ # Send prompt
79
+ client_socket .send (b"<Target:#> " )
80
+
81
+ # Receive command
82
+ cmd_buffer = b''
83
+ while b"\n " not in cmd_buffer and self .running :
84
+ try :
85
+ data = client_socket .recv (1024 )
86
+ if not data :
87
+ raise ConnectionResetError ("No data received" )
88
+ cmd_buffer += data
89
+ except socket .timeout :
90
+ continue
91
+ except (ConnectionResetError , BrokenPipeError ):
92
+ raise
93
+
94
+ if not self .running :
95
+ break
96
+
97
+ # Execute command and send response
98
+ try :
99
+ cmd = cmd_buffer .decode ().strip ()
100
+ if cmd .lower () in ['exit' , 'quit' ]:
101
+ print ("[*] User requested exit" )
102
+ break
103
+
104
+ output = self .run_command (cmd )
105
+ if output :
106
+ client_socket .send (output + b"\n " )
107
+ else :
108
+ client_socket .send (b"Command completed without output\n " )
109
+
110
+ except (BrokenPipeError , ConnectionResetError ):
111
+ print ("[!] Connection lost while sending response" )
112
+ break
113
+ except Exception as e :
114
+ error_msg = f"Error executing command: { str (e )} \n "
115
+ try :
116
+ client_socket .send (error_msg .encode ())
117
+ except :
118
+ break
119
+
120
+ except ConnectionResetError :
121
+ print ("[!] Connection reset by peer" )
122
+ break
123
+ except BrokenPipeError :
124
+ print ("[!] Broken pipe - connection lost" )
125
+ break
126
+ except Exception as e :
127
+ print (f"[!] Error in command loop: { str (e )} " )
128
+ break
129
+
130
+ except Exception as e :
131
+ print (f"[!] Exception in handle_client: { str (e )} " )
132
+ finally :
133
+ try :
134
+ client_socket .close ()
135
+ print ("[*] Client connection closed" )
136
+ except :
137
+ pass
138
+
139
+ def server_loop (self ):
140
+ server = None
141
+ try :
142
+ if not len (self .target ):
143
+ self .target = "0.0.0.0"
144
+
145
+ server = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
146
+ server .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
147
+ server .bind ((self .target , self .port ))
148
+ server .listen (5 )
149
+
150
+ print (f"[*] Listening on { self .target } :{ self .port } " )
151
+
152
+ server .settimeout (1.0 )
153
+
154
+ while self .running :
155
+ try :
156
+ client_socket , addr = server .accept ()
157
+ print (f"[*] Accepted connection from { addr [0 ]} :{ addr [1 ]} " )
158
+
159
+ client_thread = threading .Thread (
160
+ target = self .handle_client ,
161
+ args = (client_socket ,)
162
+ )
163
+ client_thread .daemon = True
164
+ self .threads .append (client_thread )
165
+ client_thread .start ()
166
+
167
+ except socket .timeout :
168
+ continue
169
+ except Exception as e :
170
+ if self .running :
171
+ print (f"[!] Exception in server_loop: { str (e )} " )
172
+ break
173
+
174
+ except Exception as e :
175
+ print (f"[!] Failed to create server: { str (e )} " )
176
+ finally :
177
+ if server :
178
+ try :
179
+ server .close ()
180
+ print ("[*] Server socket closed" )
181
+ except :
182
+ pass
183
+
184
+ for thread in self .threads :
185
+ try :
186
+ thread .join (timeout = 1.0 )
187
+ except threading .ThreadError :
188
+ pass
189
+
190
+ def client_sender (self , buffer ):
191
+ client = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
192
+
193
+ try :
194
+ print (f"[*] Connecting to { self .target } :{ self .port } " )
195
+ client .connect ((self .target , self .port ))
196
+
197
+ if len (buffer ):
198
+ try :
199
+ client .send (buffer .encode ('utf-8' ))
200
+ except (BrokenPipeError , ConnectionResetError ):
201
+ print ("[!] Failed to send initial buffer - connection lost" )
202
+ return
203
+
204
+ while self .running :
205
+ try :
206
+ # Receive response from server
207
+ recv_len = 1
208
+ response = b''
209
+
210
+ while recv_len :
211
+ data = client .recv (4096 )
212
+ recv_len = len (data )
213
+ response += data
214
+
215
+ if recv_len < 4096 :
216
+ break
217
+
218
+ if response :
219
+ print (response .decode ('utf-8' ), end = '' )
220
+
221
+ # Get next command
222
+ buffer = input ()
223
+ if not self .running :
224
+ break
225
+
226
+ if buffer .lower () in ['exit' , 'quit' ]:
227
+ break
228
+
229
+ buffer += "\n "
230
+ try :
231
+ client .send (buffer .encode ('utf-8' ))
232
+ except (BrokenPipeError , ConnectionResetError ):
233
+ print ("\n [!] Failed to send data - connection lost" )
234
+ break
235
+
236
+ except ConnectionResetError :
237
+ print ("\n [!] Connection reset by peer" )
238
+ break
239
+ except BrokenPipeError :
240
+ print ("\n [!] Broken pipe - connection lost" )
241
+ break
242
+ except EOFError :
243
+ print ("\n [!] EOF detected - exiting" )
244
+ break
245
+ except Exception as e :
246
+ print (f"\n [!] Exception in client loop: { str (e )} " )
247
+ break
248
+
249
+ except socket .error as exc :
250
+ print ("\n [!] Exception! Exiting." )
251
+ print (f"[!] Caught exception socket.error: { exc } " )
252
+ finally :
253
+ print ("[*] Closing connection" )
254
+ try :
255
+ client .close ()
256
+ except :
257
+ pass
258
+
259
+ def main ():
260
+ if len (sys .argv [1 :]) == 0 :
261
+ print ("Custom Netcat" )
262
+ print ("\n SYNOPSIS" )
263
+ print (" netcat.py [OPTIONS...]\n " )
264
+ print ("OPTIONS" )
265
+ print (" -l, --listen Start server in listening mode on specified host:port" )
266
+ print (" -e, --execute=<file> Execute specified file upon connection establishment" )
267
+ print (" -c, --command Initialize an interactive command shell session" )
268
+ print (" -u, --upload=<path> Upload file to specified destination path on connection" )
269
+ print (" -t, --target=<host> Specify target hostname or IP address" )
270
+ print (" -p, --port=<port> Specify target port number" )
271
+ print ()
272
+ sys .exit (0 )
273
+
274
+ try :
275
+ opts , args = getopt .getopt (sys .argv [1 :], "hle:t:p:cu:" ,
276
+ ["help" , "listen" , "execute" , "target" ,
277
+ "port" , "command" , "upload" ])
278
+
279
+ for o , a in opts :
280
+ if o in ("-h" , "--help" ):
281
+ main ()
282
+ elif o in ("-l" , "--listen" ):
283
+ toolkit .listen = True
284
+ elif o in ("-e" , "--execute" ):
285
+ toolkit .execute = a
286
+ elif o in ("-c" , "--command" ):
287
+ toolkit .command = True
288
+ elif o in ("-u" , "--upload" ):
289
+ toolkit .upload_destination = a
290
+ elif o in ("-t" , "--target" ):
291
+ toolkit .target = a
292
+ elif o in ("-p" , "--port" ):
293
+ toolkit .port = int (a )
294
+ else :
295
+ assert False , "Unhandled Option"
296
+
297
+ except getopt .GetoptError as err :
298
+ print (str (err ))
299
+ main ()
300
+
301
+ signal .signal (signal .SIGINT , toolkit .signal_handler )
302
+ signal .signal (signal .SIGTERM , toolkit .signal_handler )
303
+
304
+ try :
305
+ if not toolkit .listen and len (toolkit .target ) and toolkit .port > 0 :
306
+ buffer = sys .stdin .read ()
307
+ toolkit .client_sender (buffer )
308
+
309
+ if toolkit .listen :
310
+ toolkit .server_loop ()
311
+ except KeyboardInterrupt :
312
+ print ("\n [*] User requested shutdown" )
313
+ except Exception as e :
314
+ print (f"\n [!] Unexpected error: { str (e )} " )
315
+ finally :
316
+ toolkit .running = False
317
+ print ("[*] Shutdown complete" )
318
+ sys .exit (0 )
319
+
320
+ if __name__ == "__main__" :
321
+ toolkit = NetCat ("" , 0 )
322
+ main ()
0 commit comments