-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain2.py
259 lines (201 loc) · 8.4 KB
/
main2.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
244
245
246
247
248
249
250
251
252
253
254
255
from packets import *
import socket
import time
from packetExtraction import *
import sys
from timeit import default_timer as timer
def extract_packet_from_IP(packet):
# gets a TCP packet that starts from IP layer (Ether headers seperated) and returns headers of tcp and ip layer
headers = dict()
head, data = ip(packet)
if head['Protocol number'] != tcp_prot: # it's not a tcp packet
return
headers['IP'] = head
head, data = tcp(data)
headers['TCP'] = head
return headers
def calculate_ports(ports):
# ports can be a tuple or a list
# if ports parameter is a tuple it is a range of ports. e.g -> (70, 90) => ports 70, 71, ..., 90
# otherwise it consits of single ports. e.g -> [70, 90] => ports 70, 90
if type(ports) == tuple:
ports = [i for i in range(min(ports[0], ports[1]), max(ports[0], ports[1]))]
return ports
def send_tcp_packets(dst, ports, delay, iface, flags, sport=20):
# dst is the dst address, a string, can be a name like google.com or an ip
# ports can be a tuple for a range or a list for single ports
# delay is an int. the time to wait for an appropriate for a response
# flags is a string of tcp flags. like "S" for SYN or "FA" for ACK/FIN
# sport is an int, source port
ports = calculate_ports(ports)
dst = socket.gethostbyname(dst)
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
packets_recieved = list()
for port in ports:
status = True
packet_to_send = TCPpacket(dst, port, iface, sport, flags).make()
s.sendto(packet_to_send, (dst, 0))
# in order to keep track of how much to wait for an appropriate answer, start and end is used
# between sending a packet and recieving an answer. if time interval got bigger than delay parameter
# then stops waiting for the answer and sends the next packet
start = time.time()
end = time.time()
while end - start < delay + 0.1: # 0.1 is added because of additional calculations (of course 0.1 is also too much for calculations!)
s.settimeout(delay - (end - start))
try:
packet, addr = s.recvfrom(1024)
except socket.timeout:
break
headers = extract_packet_from_IP(packet)
end = time.time()
if headers is None:
continue
packets_recieved.append((headers, addr))
print('.', end='', flush=True)
print('\n')
return packets_recieved
def connect_scan(dst, ports, delay, iface, sport=20):
print('*' * 30)
print('Starting Connect scan'.center(30))
ports = calculate_ports(ports)
open_ports = list()
for port in ports:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(delay)
try:
s.connect((dst, port))
except:
print('.', end='', flush=True)
continue
print('.', end='', flush=True)
open_ports.append(port)
s.close()
print()
print('Connection with ports {', *open_ports, '} could establish!\n\n')
print('*' * 30)
def syn_scan(dst, ports, delay, iface, sport=20):
print('*' * 30)
print('Starting SYN scan'.center(30))
dst = socket.gethostbyname(dst)
answers = send_tcp_packets(dst, ports, delay, iface, 'S')
# returns a list of tuples. each contains header of rececieved packet and source address of packet.
open_ports = list()
for answer in answers:
if answer[1][0] != dst:
continue
header = answer[0]['TCP']
if header['SYN'] and header['ACK']:
open_ports.append(header['Source port number'])
print()
print('Port numbers {', *open_ports, '} sent back SYN/ACK tcp packets!\n\n')
print('*' * 30)
def ack_scan(dst, ports, delay, iface, sport=20):
print('*' * 30)
print('Starting ACK scan'.center(30))
answers = send_tcp_packets(dst, ports, delay, iface, 'A')
unfiltered_ports = list()
for answer in answers:
if answer[1][0] != dst:
continue
header = answer[0]['TCP']
if header['RST']:
unfiltered_ports.append(header['Source port number'])
print()
print('Port numbers {', *unfiltered_ports, '} may be unfiltered!\n\n')
print('*' * 30)
def fin_scan(dst, ports, delay, iface, sport=20):
print('*' * 30)
print('Starting FIN scan'.center(30))
# if an answer with rst flag has been recieved that port may be closed!
# if there was no answer, that port may be either open or filtered
answers = send_tcp_packets(dst, ports, delay, iface, 'F')
open_ports = set(calculate_ports(ports)) # becaus we want to delete some closed ports, it is easier to use set instead of list
for answer in answers:
if answer[1][0] != dst:
continue
header = answer[0]['TCP']
if header['RST']: # closed ports sometimes send RST packets in answer of FIN packets
open_ports.discard(header['Source port number'])
print()
print('Port numbers {', *open_ports, '} may be opened or maybe filtered!\n\n')
print('*' * 30)
def win_scan(dst, ports, delay, iface, sport=20):
# it's like ack scan. in some cases when a port is open and unfiltered the rst packet has a psitive window size
# in unfiltered closed ports sometimes in rst packet window size is zero
print('*' * 30)
print('Starting FIN scan'.center(30))
answers = send_tcp_packets(dst, ports, delay, iface, 'A')
open_ports = list()
for answer in answers:
if answer[1][0] != dst:
continue
header = answer[0]['TCP']
if header['RST'] and header['Window size']: # window size is not zero and rst flag is on
open_ports.append(header['Source port number'])
print()
print('Port numbers {', *open_ports, '} may be open!\n\n')
print('*' * 30)
options = sys.argv[1:]
# dst is a string, scan is a function, ports is a tuple for range of ports and a list for single ports, delay is an int
# iface is a string
# default values
dst = '127.0.0.1'
scan = connect_scan
ports = (1, 100)
delay = 1
iface = None
for option in options: # expected option format: "<sth>=<sth>"
option = option.strip().split('=')
option[0] = option[0].lower()
if len(option) != 2 or option[0] not in ('mode', 'dst', 'ports', 'delay', 'iface'):
# there is no value. e.g -> mode , mode=
# Or more than one values. e.g -> mode=cports=100 , ports=1-100=150
# unknown arguments -> tcpport=80
print(f'Unknown "{"=".join(option)}"')
continue
option[1] = option[1].lower()
if option[0] == 'mode':
if option[1] == 'c':
scan = connect_scan
print('---Connect scan---')
elif option[1] == 's':
scan = syn_scan
print('---SYN scan---')
elif option[1] == 'f':
scan = fin_scan
print('---FIN scan---')
elif option[1] == 'w':
scan = win_scan
print('---Window scan---')
elif option[1] == 'a':
scan = ack_scan
print('---ACK scan---')
else:
print(f'Scan mode not found: {option[1]}')
elif option[0] == 'ports':
if re.match(r'^(\d+,)*\d*$', option[1]): # single port. e.g "15,17,10,4"
# in single ports -> ports are in a list
ports = list(map(int, option[1].split(',')))
print('---Ports:', ports, '---')
elif re.match(r'^\d+\-\d+$', option[1]): # a range of ports. e.g "100-150" or maybe "30-10"
# range of ports -> start and end port are first and second item of a tuple
first, second = tuple(map(int, option[1].split('-')))
ports = (min(first, second), max(first, second))
print('---Range of ports:', ports, '---')
else:
print(f'Wrong ports input: "{option[1]}"')
elif option[0] == 'delay':
if re.match(r'^\d+\.?\d*$', option[1]):
delay = float(option[1])
print(f'---Delay: {delay}---')
else:
print(f'Wrong delay input: {option[1]}')
elif option[0] == 'dst':
dst = option[1]
print(f'---Target: {dst}---')
elif option[0] == 'iface':
iface = option[1]
print(f'---interface set to {iface}---')
if iface is None:
raise AttributeError('Interface name must be specified')
scan(dst, ports, delay, iface)