网络扫描
网络扫描
通过网络扫描,可以获取网段内存活的主机以及其开放的端口,更加深入的扫描则能够探测主机的操作系统,配置,安装的软件等。
主机发现
在网络中发现主机有很多方法,如果在局域网内使用arp协议可以轻易的发现存活的kv主机,如果在不同的网段使用ICMP协议也可以尝试和主机取得联系,TCP和UDP协议同样可以
ARP协议探测
ARP协议通过向局域网广播的方式将同网段主机IP地址解析为MAC地址。
在一个路由器下的局域网内,如果对某个IP发起ARP请求,如果这个IP通过路由器上网,那么路由器肯定有这个主机的MAC地址,因此广播到路由器时会受到主机的IP地址;如果不存在这个IP,那么将没有MAC地址的回复。根据是否受到MAC地址,就可以判断局域网内的这个主机是否存活。
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报文,如果不可达会返回具体原因的报文。
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]
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]
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]
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扫描
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扫描
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扫描
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
源代码
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')