网络扫描-主机发现
信息搜集是渗透中进行下一步攻击的基础,下面介绍几种常见的主机发现的方式。
一、原理解析
1、基于IMCP的主机发现
ping命令是ICMP中较为常见的应用,经常使用这个命令来测试本地与目标之间的连通性,发送一个ICMP请求消息给目标主机,若源主机收到目标主机的应答响应消息,则表示目标可达,主机存在。
https://www.rfc-editor.org/rfc/rfc792.txt
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data ... +-+-+-+-+-
2、基于TCP的主机发现
利用TCP三次握手原理进行主机存活的探测,当向目标主机直接发送ACK数据包时,如果目标主机存活,就会返回一个RST数据包以终止这个不正常的TCP连接。也可以发送正常的SYN数据包,如果目标主机返回SYN/ACK或者RST数据包,也可以证明主机为存活状态。其工作原理主要依据目标主机响应数据包中的flags字段,如果flags字段有值,则表示主机存活,该字段通常包括SYN、FIN、ACK、PSH、RST、URG六种类型。SYN表示建立连接,FIN表示关闭连接,ACK表示应答,PSH表示包含DATA数据传输,RST表示连接重置,URG表示紧急指针。
3、基于UDP的主机发现
当向目标发送一个UDP数据包之后,目标是不会发回任何UDP数据包的。不过,如果目标主机处于活跃状态,但是目标端口是关闭状态时,会返回一个ICMP数据包,这个数据包的含义是unreachable。如果目标主机不处于活跃状态,这时是收不到任何响应数据的。利用UDP原理可以实现探测存活主机。
4、基于ARP的主机发现
当目标主机与攻击机处于同一网段时,利用ARP进行主机发现是一个比较好的选择。则这种扫描方式快且准确。当主机存活时,会响应ARP请求,否则不会响应。
二、流量分析
1、基于IMCP的主机发现
本机地址是192.168.1.10,扫描192.168.1.0-192.168.1.9。
请求报文:
响应报文
2、基于TCP的主机发现
执行:
root@kali:~/code/chap4/4.2.2# python3 tcp_host.py -i 8.8.8.8
8.8.8.8 is up
root@kali:~/code/chap4/4.2.2#
3、基于UDP的主机发现
4、基于ARP的主机发现
执行结果存放在result文件中。
root@kali:~/code/chap4/4.2.3# python3 arpscanner.py -i eth0
=====================
ARP 探测结果
本机IP地址:192.168.142.131
本机MAC地址:00:0c:29:03:db:bb
=====================
IP:192.168.142.1
MAC:00:50:56:c0:00:08
=====================
IP:192.168.142.2
MAC:00:50:56:f5:f3:e2
=====================
IP:192.168.142.254
MAC:00:50:56:ff:f9:08
=====================
root@kali:~/code/chap4/4.2.3# ls
arpscanner.py nmap_ARP_find.py result
root@kali:~/code/chap4/4.2.3# cat result
192.168.142.1
192.168.142.2
192.168.142.254
三、代码分析
windows环境下要开启scapy服务。如下图所示:
1、基于IMCP的主机发现
ICMP_host.py
1 #!/usr/bin/python 2 #coding:utf-8 3 from scapy.all import * 4 from random import randint 5 from optparse import OptionParser 6 7 def Scan(ip): 8 ip_id = randint(1, 65535) 9 icmp_id = randint(1, 65535) 10 icmp_seq = randint(1, 65535) 11 packet=IP(dst=ip,ttl=64,id=ip_id)/ICMP(id=icmp_id,seq=icmp_seq)/b'rootkit' 12 result = sr1(packet, timeout=1, verbose=False) 13 if result: 14 for rcv in result: 15 scan_ip = rcv[IP].src 16 print(scan_ip + '--->' 'Host is up') 17 else: 18 print(ip + '--->' 'host is down') 19 20 def main(): 21 parser = OptionParser("Usage:%prog -i <target host> ") # 输出帮助信息 22 parser.add_option('-i',type='string',dest='IP',help='specify target host') # 获取ip地址参数 23 options,args = parser.parse_args() 24 print("Scan report for " + options.IP + "\n") 25 # 判断是单台主机还是多台主机 26 # ip中存在-,说明是要扫描多台主机 27 if '-' in options.IP: 28 # 代码意思举例:192.168.1.1-120 29 # 通过'-'进行分割,把192.168.1.1和120进行分离 30 # 把192.168.1.1通过','进行分割,取最后一个数作为range函数的start,然后把120+1作为range函数的stop 31 # 这样循环遍历出需要扫描的IP地址 32 for i in range(int(options.IP.split('-')[0].split('.')[3]), int(options.IP.split('-')[1]) + 1): 33 Scan( 34 options.IP.split('.')[0] + '.' + options.IP.split('.')[1] + '.' + options.IP.split('.')[ 35 2] + '.' + str(i)) 36 time.sleep(0.2) 37 else: 38 Scan(options.IP) 39 40 print("\nScan finished!....\n") 41 42 if __name__ == "__main__": 43 try: 44 main() 45 except KeyboardInterrupt: 46 print("interrupted by user, killing all threads...")
2、基于TCP的主机发现
tcp_host.py
1 import os 2 import time 3 from optparse import OptionParser 4 from random import randint 5 from scapy.all import * 6 7 8 def Scan(ip): 9 try: 10 dport = random.randint(1, 65535) #随机目的端口 11 packet = IP(dst=ip)/TCP(flags="A",dport=dport) #构造标志位为ACK的数据包 12 response = sr1(packet,timeout=1.0, verbose=0) 13 if response: 14 if int(response[TCP].flags) == 4: #判断响应包中是否存在RST标志位 15 time.sleep(0.5) 16 print(ip + ' ' + "is up") 17 else: 18 print(ip + ' ' + "is down") 19 else: 20 print(ip + ' ' + "is down") 21 except: 22 pass 23 24 25 def main(): 26 27 usage = "Usage: %prog -i <ip address>" # 输出帮助信息 28 parse = OptionParser(usage=usage) 29 parse.add_option("-i", '--ip', type="string", dest="targetIP", help="specify the IP address") # 获取网段地址 30 options, args = parse.parse_args() #实例化用户输入的参数 31 if '-' in options.targetIP: 32 # 代码意思举例:192.168.1.1-120 33 # 通过'-'进行分割,把192.168.1.1和120进行分离 34 # 把192.168.1.1通过','进行分割,取最后一个数作为range函数的start,然后把120+1作为range函数的stop 35 # 这样循环遍历出需要扫描的IP地址 36 for i in range(int(options.targetIP.split('-')[0].split('.')[3]), int(options.targetIP.split('-')[1]) + 1): 37 Scan(options.targetIP.split('.')[0] + '.' + options.targetIP.split('.')[1] + '.' + 38 options.targetIP.split('.')[2] + '.' + str(i)) 39 else: 40 Scan(options.targetIP) 41 42 43 if __name__ == '__main__': 44 main()
3、基于UDP的主机发现
4、基于ARP的主机发现
arpscanner.py
1 #!/usr/bin/python3 2 # -*- coding: utf-8 -*- 3 4 import os 5 import re 6 import optparse 7 from scapy.all import * 8 9 #取IP地址和MAC地址函数 10 def HostAddress(iface): 11 #os.popen执行后返回执行结果 12 ipData = os.popen('ifconfig '+iface) 13 #对ipData进行类型转换,再用正则进行匹配 14 dataLine = ipData.readlines() 15 #re.search利用正则匹配返回第一个成功匹配的结果,存在结果则为true 16 #取MAC地址 17 if re.search('\w\w:\w\w:\w\w:\w\w:\w\w:\w\w',str(dataLine)): 18 #取出匹配的结果 19 MAC = re.search('\w\w:\w\w:\w\w:\w\w:\w\w:\w\w',str(dataLine)).group(0) 20 #取IP地址 21 if re.search(r'((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)',str(dataLine)): 22 IP = re.search(r'((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)',str(dataLine)).group(0) 23 #将IP和MAC通过元组的形式返回 24 addressInfo = (IP,MAC) 25 return addressInfo 26 27 #ARP扫描函数 28 def ArpScan(iface='eth0'): 29 #通过HostAddres返回的元组取出MAC地址 30 mac = HostAddress(iface)[1] 31 #取出本机IP地址 32 ip = HostAddress(iface)[0] 33 #对本机IP地址并进行分割作为依据元素,用于生成需要扫描的IP地址 34 ipSplit = ip.split('.') 35 #需要扫描的IP地址列表 36 ipList = [] 37 #根据本机IP生成IP扫描范围 38 for i in range(1,255): 39 ipItem = ipSplit[0] + '.' + ipSplit[1] + '.' + ipSplit[2] + '.' + str(i) 40 ipList.append(ipItem) 41 ''' 42 发送ARP包 43 因为要用到OSI二层和三层,所以要写成Ether/ARP。 44 因为最底层用到了二层,所以要用srp()发包 45 ''' 46 result = srp(Ether(src=mac,dst='FF:FF:FF:FF:FF:FF')/ARP(op=1,hwsrc=mac,hwdst='00:00:00:00:00:00',pdst=ipList),iface=iface,timeout=2,verbose=False) 47 #读取result中的应答包和应答包内容 48 resultAns = result[0].res 49 #存活主机列表 50 liveHost = [] 51 #number存回应包总数 52 number = len(resultAns) 53 print("=====================") 54 print(" ARP 探测结果 ") 55 print("本机IP地址:" + ip) 56 print("本机MAC地址:" + mac) 57 print("=====================") 58 for x in range(number): 59 IP = resultAns[x][1][1].fields['psrc'] 60 MAC = resultAns[x][1][1].fields['hwsrc'] 61 liveHost.append([IP,MAC]) 62 print("IP:" + IP + "\n\n" + "MAC:" + MAC ) 63 print("=====================") 64 #把存活主机IP写入文件 65 resultFile = open("result","w") 66 for i in range(len(liveHost)): 67 resultFile.write(liveHost[i][0] + "\n") 68 69 resultFile.close() 70 if __name__ == '__main__': 71 parser = optparse.OptionParser('usage: python %prog -i interfaces \n\n' 72 'Example: python %prog -i eth0\n') 73 #添加网卡参数 -i 74 parser.add_option('-i','--iface',dest='iface',default='eth0',type='string',help='interfaces name') 75 (options, args) = parser.parse_args() 76 ArpScan(options.iface)