网络扫描

通过网络扫描,可以获取网段内存活的主机以及其开放的端口,更加深入的扫描则能够探测主机的操作系统,配置,安装的软件等。

主机发现

在网络中发现主机有很多方法,如果在局域网内使用arp协议可以轻易的发现存活的kv主机,如果在不同的网段使用ICMP协议也可以尝试和主机取得联系,TCP和UDP协议同样可以

ARP协议探测

ARP协议通过向局域网广播的方式将同网段主机IP地址解析为MAC地址。
在一个路由器下的局域网内,如果对某个IP发起ARP请求,如果这个IP通过路由器上网,那么路由器肯定有这个主机的MAC地址,因此广播到路由器时会受到主机的IP地址;如果不存在这个IP,那么将没有MAC地址的回复。根据是否受到MAC地址,就可以判断局域网内的这个主机是否存活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def arp(ipy):
dst_ip_list = IPY(ipy)
alive_ip_list = []

for dst_ip in dst_ip_list:
pkt = ARP(pdst=str(dst_ip))
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
alive_ip_list.append(dst_ip)
print(dst_ip, 'is up')
else:
print(dst_ip, 'is closed')

return alive_ip_list

ICMP协议探测

ICMP中的request/ping报文可以用于测试网络的可达性和延迟情况,如果主机可达将会返回reply报文,如果不可达会返回具体原因的报文。

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
def ping(ipy):
dst_ip_list = IPY(ipy)
alive_ip_list = []
for dst_ip in dst_ip_list:
pkt = IP(dst=str(dst_ip)) / ICMP() / b'hello'
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
if ans[ICMP].type == 0:
if ans[IP].ttl <= 64:
print(dst_ip, '(Linux)', 'is up')
elif ans[IP].ttl <= 128:
print(dst_ip, '(Windows)', 'is up')
else:
print(dst_ip, '(Mac/Unix)', 'is up')
alive_ip_list.append(dst_ip)
elif ans[ICMP].type == 11:
print(dst_ip, 'is timeout')
elif ans[ICMP].type == 3:
print(dst_ip, 'is unreachable')
elif ans[ICMP].type == 4:
print(dst_ip, 'source quench')
elif ans[ICMP].type == 5:
print(dst_ip, 'redirect')
elif ans[ICMP].type == 12:
print(dst_ip, '参数问题')
else:
print(dst_ip, '其他问题:[ICMP].type', ans[ICMP].type)
else:
print(dst_ip, 'is probably filtered(no response)')

return alive_ip_list

端口扫描

基于TCP协议可以完成多种扫描。

TCP扫描

通过与端口建立TCP连接判断端口的开放情况。如果端口开放,那么可以通过TCP的三次握手建立连接,然后断开连接即可;如果端口关闭,那么TCP握手无法完成。
这种方法的缺点是会在扫描的主机留下痕迹,因为一旦与主机的某个端口建立TCP连接,操作系统就会记录这条连接。并且,完成三次握手的时间会比较长,当扫描端口数量很多的时候速度会比较慢。
nmap -sT [IP]

SYN扫描

SYN扫描相比于TCP扫描更加简单,它发送一个SYN报文进行握手,如果端口开放那么会收到一个SYN&ACK报文,这时候回复一个RST报文断开连接即可,并且由于握手没有完成,操作系统不会记录这次扫描;如果端口关闭,那么不会收到SYN&ACK报文。
nmap -sS [IP]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def syn_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i))
# pkt = IP(dst=str(dst_ip)) / TCP(sport=random.randint(1,65536),dport=int(i))
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
if ans[TCP].flags == 'SA':
print(i, 'port is open')
alive_port_list.append(i)
rst = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='R')
sr1(rst, timeout=1, verbose=False)
else:
print(i, 'port is closed')
else:
print(i, 'port is filtered')

return alive_port_list

根据RFC文档,对于错误TCP报文无论是开放端口还是关闭端口都应该回复RST报文,windows按照规则,但是Linux对于开放端口不会回复RST报文。

ACK扫描

ACK扫描发送一个ACK报文进行端口探测。对于Windows系统,无论是开放还是关闭的端口都会回复RST报文;但是对于Linux系统,开放的端口将不会回复任何内容,关闭的端口则会回复RST报文。
另外,如果开启防火墙那么无论Windows操作系统还是Linux操作系统都不会对错误报文回复任何内容。
nmap sA [IP]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def null_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags=0)
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list

FIN扫描

向目标主机的端口发送FIN报文。
nmap -sF [IP]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def fin_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='F')
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list

NULL扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def null_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags=0)
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list

XMAS扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def xmas_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags=1)
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list

WINDOWS扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def windows_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='S')
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
if ans[TCP].window != 0:
print(i, 'port is open')
alive_port_list.append(i)
rst = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='R')
sr1(rst, timeout=1, verbose=False)
else:
print(i, 'port is closed')
else:
print(i, 'port is filtered')

return alive_port_list

源代码

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
from scapy.all import *
from IPy import IP as IPY
from scapy.layers.inet import ICMP, IP, TCP
from scapy.layers.l2 import ARP


def preview(list):
preview = input("预览(y/n):")
if preview == 'y' or 'Y':
for li in list:
print(li)


def arp(ipy):
dst_ip_list = IPY(ipy)
alive_ip_list = []

for dst_ip in dst_ip_list:
pkt = ARP(pdst=str(dst_ip))
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
alive_ip_list.append(dst_ip)
print(dst_ip, 'is up')
else:
print(dst_ip, 'is closed')

return alive_ip_list


def ping(ipy):
dst_ip_list = IPY(ipy)
alive_ip_list = []
for dst_ip in dst_ip_list:
pkt = IP(dst=str(dst_ip)) / ICMP() / b'hello'
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
if ans[ICMP].type == 0:
if ans[IP].ttl <= 64:
print(dst_ip, '(Linux)', 'is up')
elif ans[IP].ttl <= 128:
print(dst_ip, '(Windows)', 'is up')
else:
print(dst_ip, '(Mac/Unix)', 'is up')
alive_ip_list.append(dst_ip)
elif ans[ICMP].type == 11:
print(dst_ip, 'is timeout')
elif ans[ICMP].type == 3:
print(dst_ip, 'is unreachable')
elif ans[ICMP].type == 4:
print(dst_ip, 'source quench')
elif ans[ICMP].type == 5:
print(dst_ip, 'redirect')
elif ans[ICMP].type == 12:
print(dst_ip, '参数问题')
else:
print(dst_ip, '其他问题:[ICMP].type', ans[ICMP].type)
else:
print(dst_ip, 'is probably filtered(no response)')

return alive_ip_list


def syn_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i))
# pkt = IP(dst=str(dst_ip)) / TCP(sport=random.randint(1,65536),dport=int(i))
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
if ans[TCP].flags == 'SA':
print(i, 'port is open')
alive_port_list.append(i)
rst = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='R')
sr1(rst, timeout=1, verbose=False)
else:
print(i, 'port is closed')
else:
print(i, 'port is filtered')

return alive_port_list


def ack_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='A')
# pkt.show()
ans = sr1(pkt, timeout=0.2, verbose=False)
if ans is None:
print(i, 'port is filtered')
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list


def fin_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='F')
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list


def null_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags=0)
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list


def xmas_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags=1)
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is None:
print(i, 'port is open or filtered')
alive_port_list.append(i)
else:
# ans.summary()
# ans.show()
print(i, 'port is closed')

return alive_port_list


def windows_scan(dst_ip, n, m):
alive_port_list = []
for i in range(n, m):
pkt = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='S')
# pkt.show()
ans = sr1(pkt, timeout=1, verbose=False)
if ans is not None:
# ans.summary()
# ans.show()
if ans[TCP].window != 0:
print(i, 'port is open')
alive_port_list.append(i)
rst = IP(dst=str(dst_ip)) / TCP(dport=int(i), flags='R')
sr1(rst, timeout=1, verbose=False)
else:
print(i, 'port is closed')
else:
print(i, 'port is filtered')

return alive_port_list


if __name__ == '__main__':
# 主机ip(移动)
# dst_ip = '10.132.68.173'
# 网关ip
# dst_ip = '10.132.168.1'
# 子网
# dst_ip = '10.132.168.0/21'
# Windows虚拟机ip
# dst_ip = '192.168.59.132'
# Linux虚拟机ip
# dst_ip = '192.168.59.131'

while True:
print('-------net scanner-------')
service = input('你选择主机扫描或是端口扫描?(host/port):')
if service == 'host':
way = input('请输入扫描方式(arp/ping):')
if way == 'ping':
dst_ip = input('请输入你要查询的主机或者范围:')
alive_ip_list = ping(dst_ip)
preview(alive_ip_list)
elif way == 'arp':
dst_ip = input('请输入你要查询的主机或者范围:')
alive_ip_list = arp(dst_ip)
preview(alive_ip_list)
elif service == 'port':
way = input('请输入扫描方式(syn/windows/ack/fin/null/xmas):')
if way == 'syn':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = syn_scan(dst_ip, 1, 1024)
preview(alive_port_list)
elif way == 'windows':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = windows_scan(dst_ip, 1, 1024)
preview(alive_port_list)
elif way == 'ack':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = ack_scan(dst_ip, 1, 1024)
preview(alive_port_list)
elif way == 'fin':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = fin_scan(dst_ip, 1, 1024)
preview(alive_port_list)
elif way == 'null':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = null_scan(dst_ip, 1, 1024)
preview(alive_port_list)
elif way == 'xmas':
dst_ip = input('请输入你要查询的主机:')
alive_port_list = xmas_scan(dst_ip, 1, 1024)
preview(alive_port_list)
else:
print('i am a teapot')