Python 协议攻击脚本(三): ICMP扫描

时间:2024-05-21 12:12:37

ICMP协议

互联网控制消息协议(英语:Internet Control Message Protocol,缩写:ICMP)是互联网协议族的核心协议之一。它用于网际协议(IP)中发送控制消息,提供可能发生在通信环境中的各种问题反馈。通过这些信息,使管理者可以对所发生的问题作出诊断,然后采取适当的措施解决。

Type

ICMP的类型

  • 0 回显请求 Echo Request
  • 8 回显应答 Echo Reply
  • 3 目标不可达 Destination Unreachable
  • 11 超时消息 Time Exceeded
  • 5 重定向消息 Redirect

ICMP扫描

利用ICMP协议对来判断存活的主机

原理

对需要扫描的ip发送icmp回显请求Echo Request,如果收到回显应答Echo Reply则该ip处于活动状态,简单来说就是ping别人,以是否ping得通来判断是否存活

数据包分析

ping网关

# ping 网关 -c 1 

Python 协议攻击脚本(三): ICMP扫描

Python 协议攻击脚本(三): ICMP扫描

可以看到封装为Ether/IP/ICMP,ICMP的类型为8 (Echo Request)

Python 协议攻击脚本(三): ICMP扫描

答复的数据包ICMP类型为0(Echo Reply)

>>> ls(ICMP)
type       : ByteEnumField                       = (8) #ICMP类型
code       : MultiEnumField (Depends on type)    = (0)
chksum     : XShortField                         = (None)
id         : XShortField (Cond)                  = (0)
seq        : XShortField (Cond)                  = (0)
[...]

Python脚本

1.Scapy中ICMP的请求和答复

>>> p = IP(dst='10.35.68.1')/ICMP(type=8)
>>> p.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags=
  frag= 0
  ttl= 64
  proto= icmp
  chksum= None
  src= 10.35.71.205
  dst= 10.35.68.1
  \options\
###[ ICMP ]###
     type= echo-request
     code= 0
     chksum= None
     id= 0x0
     seq= 0x0
>>> p1 = sr1(p)
Begin emission:
.......Finished sending 1 packets..
..........*
Received 19 packets, got 1 answers, remaining 0 packets
>>> p1 = sr1(p,verbose=False) #关闭消息反馈
>>> p1    #答复的包
<IP  version=4 ihl=5 tos=0x0 len=28 id=2899 flags= frag=0 ttl=64 proto=icmp chksum=0xcf7a src=10.35.68.1 dst=10.35.71.205 |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00    ' |>>>
>>> p1.getlayer('ICMP')    #获取ICMP层
<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00    ' |>>

>>> p1.getlayer('ICMP').fields['type']	#获取type的值
0

Python自带的ipaddress模块

>>> import ipaddress
>>> ip = list(ipaddress.ip_network('192.168.1.0/30'))
>>> ip
[IPv4Address('192.168.1.0'),
 IPv4Address('192.168.1.1'),
 IPv4Address('192.168.1.2'),
 IPv4Address('192.168.1.3')]
>>> for i in ip:
...:     print(i)
...:
192.168.1.0
192.168.1.1
192.168.1.2
192.168.1.3
>>> ip = ipaddress.ip_network('192.168.1.1')
>>> for i in ip:
...:     print(i)
...:
192.168.1.1

2.demo:先定义两个函数

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from scapy.all import *

#ICMP请求,返回响应包
def icmp_requset(ip_dst,iface=None):
    pkt = IP(dst=ip_dst)/ICMP(type=8) #ICMP类型为
    req = sr1(pkt,timeout=2,verbose=False) #timeou:超时时间设置 verbose:设置自带消息反馈
    return req

#判断是否存活
def icmp_scan(ip_dst):
    req = icmp_requset(ip_dst)
    #判断是否响应包是否为空
    if req:
         type = req.getlayer('ICMP').fields['type']
         print('[+]',ip_dst,':',type,'    Host is up')
    else:
        pass
if __name__ == '__main__':
    icmp_scan('10.35.68.1')

运行结果

[+] 10.35.68.1 : 0     Host is up

3.改进代码,加入扫描子网

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from scapy.all import *
import ipaddress

#ICMP请求,返回响应包
def icmp_requset(ip_dst,iface=None):
    pkt = IP(dst=ip_dst)/ICMP(type=8) #ICMP类型为
    req = sr1(pkt,timeout=2,verbose=False) #timeou:超时时间设置 verbose:设置自带消息反馈
    return req

#判断是否存活
def icmp_scan(ip_dst):
    req = icmp_requset(ip_dst)
    #判断是否响应包是否为空
    if req:
         print('[+]',ip_dst,'    Host is up')
    else:
        pass
def main(network):
    
    #Windows**释掉这段
    ##判断是否为root
    # if os.getuid() != 0:
    #     print('[-]Need root user to run')
    #     sys.exit(1)

    network = list(ipaddress.ip_network(network))

    for ip in network:
        icmp_scan(ip)
    
if __name__ == '__main__':
    main('10.35.68.0/24')

运行结果

[+] 10.35.68.1 : 0     Host is up
[+] 10.35.68.4 : 0     Host is up
[+] 10.35.68.8 : 0     Host is up
[+] 10.35.68.3 : 0     Host is up
[+] 10.35.68.9 : 0     Host is up

4.代码完善,加上参数选项和子网的识别

argparse 命令行选项模块

threading 多线程模块

PYTHON3 多线程实例学习

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from scapy.all import IP,ICMP,sr1
import threading
import argparse
import ipaddress
import os
import sys

def icmp_requset(ip_dst,iface=None):
    pkt = IP(dst=ip_dst,ttl=64)/ICMP(type=8)
    req = sr1(pkt,timeout=3,verbose=False)
    return req

def icmp_scan(ip_dst):
    req = icmp_requset(ip_dst)
    if req:
         print('[+]',ip_dst,':',type,'    Host is up')
    else:
        pass

def main():
    #Windows中注释掉这段
    ##判断是否为root
    # if os.getuid() != 0:
    #     print('[-]Need root user to run')
    #     sys.exit(1)

    #命令行选项
    parser = argparse.ArgumentParser()
    parser.add_argument('network', help='eg:192.168.1.0/24')
    args = parser.parse_args()
    
    network = list(ipaddress.ip_network(args.network))
    length = len(network)
    threads = []
    
    #多线程 
    for ip in network:
        t = threading.Thread(target=icmp_scan,args=(str(ip),))
        threads.append(t)

    for i in range(length):
        threads[i].start()

    for i in range(length):
        threads[i].join()



if __name__ == '__main__':
    main()

运行演示

Python 协议攻击脚本(三): ICMP扫描