7-IP地址段存活主机扫描

思路:

1、定义一个简单的字符串作为签名,用于确认收到的ICMP响应是否是我们发送的UDP包触发的;

2、udp_sender函数会读取程序开头定义的子网,往这个子网的每一个地址发送UDP数据包;

3、定义一个名为scanner的类,初始化这个类时,需要传递扫描器所在的主机IP,即程序运行的位置;

  初始化过程中,创建一个socket对象(windows上需要启动网络混杂模式),并把这个对象设定为scanner类的成员变量;

4、sniff函数会嗅探网络上的数据,并把在线的主机记录下来:

  接收到ICMP消息时,首先检查是不是来自我们正在扫描的子网,然后检查ICMP消息里有没有我们自定义的签名;

  如果所有检查都通过了,就把这条主机IP信息打印出来,使用ctrl+c组合键中断扫描,程序会关闭网卡混杂模式,并把扫描出来的主机打印出来,然后退出程序;

 

IP报头格式:                              ICMP报头格式:   

      

 

ICMP 报文分类: 

Type

Code

描述

查询/差错

0-Echo响应

0

Echo响应报文

查询

3-目的不可达

0

目标网络不可达报文

差错

1

目标主机不可达报文

差错

2

目标协议不可达报文

差错

3

目标端口不可达报文

差错

4

要求分段并设置DF flag标志报文

差错

5

源路由失败报文

差错

6

未知的目标网络报文

差错

7

未知的目标主机报文

差错

8

源主机隔离报文

差错

9

禁止访问的网络报文

差错

10

禁止访问的主机报文

差错

11

对特定的TOS网络不可达报文

差错

12

对特定的TOS主机不可达报文

差错

13

由于过滤 网络流量被禁止报文

差错

14

主机越权报文

差错

15

优先权终止生效报文

差错

5-重定向

0

重定向网络报文

差错

1

重定向主机报文

差错

2

基于TOS的网络重定向报文

差错

3

基于TOS的主机重定向报文

差错

8-Echo请求

0

Echo请求报文

查询

9-路由器通告

0

路由通告报文

查询

10-路由器请求

0

路由器的发现/选择/请求报文

查询

11-ICMP超时

0

TTL超时报文

差错

1

分片重组超时报文

差错

12-参数问题

0

IP报首部参数错误报文

差错

1

丢失必要选项报文

差错

2

不支持的长度报文

差错

13-时间戳请求

0

时间戳请求报文

查询

14-时间戳应答

0

时间戳应答报文

查询

15-信息请求

0

信息请求报文

查询

16-信息应答

0

信息应答报文

查询

scanner.py
 # -*-utf-8-*-

import ipaddress
import struct
import socket
import os
import sys
import time
import threading


SUBNET = input('subnet(1.1.1.0/24): ')
MSG = 'PYTHONRULES'

# 使用struct库定义一个IP类
class IP:
    def __init__(self, buffer = None):
        header = struct.unpack('!BBHHHBBH4s4s', buffer)
        self.version = header[0] >> 4
        self.header_len = header[0] & 0xF
        self.tos = header[1]
        self.total_len = header[2]
        self.id = header[3]
        self.frag_off = header[4]
        self.ttl = header[5]
        self.protocol = header[6]
        self.check = header[7]
        self.src = header[8]
        self.dst = header[9]

        self.src_addr = ipaddress.ip_address(self.src)
        self.dst_addr = ipaddress.ip_address(self.dst)

        self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"}
        try:
            self.protocol = self.protocol_map[self.protocol]
        except Exception as e:
            print(f'{e} No protocol for {self.protocol}')
            self.protocol = str(self.protocol)

class ICMP:
    def __init__(self, buffer):
        header = struct.unpack('!BBHHH', buffer)
        self.type = header[0]
        self.code = header[1]
        self.checksum = header[2]
        self.unused = header[3]
        self.next_hop_mtu = header[4]

# udp datagrames with magic message
def udp_sender():
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
        for ip in ipaddress.ip_network(SUBNET).hosts():
            s.sendto(bytes(MSG,'utf-8'), (str(ip), 65212))

class scanner:
    def __init__(self, host):
        self.host = host
        if os.name == 'nt':
            socket_protocol = socket.IPPROTO_IP
        else:
            socket_protocol = socket.IPPROTO_ICMP
        self.scoket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
        self.scoket.bind((host, 0))
        self.scoket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

        if os.name == 'nt':
            self.scoket.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON) #开启混杂模式

    def sniff(self):
        hosts_up = set([f'{str(self.host)} *'])
        try:
            while True:
                raw_buffer = self.scoket.recvfrom(65565)[0]
                ip_header = IP(raw_buffer[0:20])
                if ip_header.protocol == 'ICMP':
                    offset = ip_header.header_len * 4
                    buf = raw_buffer[offset:offset + 8]
                    icmp_header = ICMP(buf)
                    if icmp_header.type == 3 and icmp_header.code == 3:
                        if ipaddress.ip_address(ip_header.src) in hosts_up:
                            if raw_buffer[len(raw_buffer) - len(MSG):] == bytes(MSG,'utf-8'):
                                tgt = str(ip_header.src_addr)
                                if tgt != self.host and tgt not in hosts_up:
                                    hosts_up.add(tgt)
                                    print(f'[+] {tgt} is UP')
        except KeyboardInterrupt:
            if os.name == 'nt':
                self.scoket.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) #关闭混杂模式
            print('\nuser interrupted')
            if hosts_up:
                print(f'{len(hosts_up)} UP hosts')
            for host in sorted(hosts_up):
                print(f'{host}')
            print('\n')
            sys.exit(0)


if __name__ == '__main__': 
    if len(sys.argv) == 2:
        host = sys.argv[1]
    else:
        host = '192.168.1.101'
    s = scanner(host)
    time.sleep(5)
    t = threading.Thread(target=udp_sender)
    t.start()
    s.sniff()
 

 

ctrl+c中断扫描后如下:

 

posted @   段愿仁长九  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示