Scapy—Ping扫描


Scapy—Ping扫描

一、项目背景

最近在学 Scapy ,决定先从最基本的开始做起,于是有了这篇水文,先来看看文档对它的定义:

Scapy是一个可以让用户发送、侦听和解析并伪装网络报文的Python程序。这些功能可以用于制作侦测、扫描和攻击网络的工具。换言之,Scapy 是一个强大的操纵报文的交互程序。它可以伪造或者解析多种协议的报文,还具有发送、捕获、匹配请求和响应这些报文以及更多的功能。Scapy 可以轻松地做到像扫描(scanning)、路由跟踪(tracerouting)、探测(probing)、单元测试(unit tests)、攻击(attacks)和发现网络(network discorvery)这样的传统任务。它可以代替hpingarpspoofarp-skarpingp0f 甚至是部分的Namptcpdumptshark 的功能。

我总结一句,它说的真的都能实现(手动狗头)…

1、安装Scapy

pip3 install scapy

2、数据包的基本构成

数据包是从底层到高层构造的,ICMP 协议是应用层协议,这里要知道的是当 Type0 时为 echo-reply ;当 Type8时为 echo-request

先来看基本的 ping 命令:

➜  ~ ping -c 1 baidu.com
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79 (39.156.69.79): icmp_seq=1 ttl=49 time=38.4 ms

可以看到,上面的一条 ping 有显示的有序列号,生存周期,花费时间,生成周期一般都是 64128 ,序列号则是需要填的部分。

>>> p = IP(dst='10.87.51.1')/ICMP()    
#这还可以换成 Ether()/IP(dst='10.87.51.1')/ICMP(),但是前面要加上以太网帧
>>> p.show()
###[ IP ]###
  version= 4    #IP版本
  ihl= None
  tos= 0x0
  len= None        #长度
  id= 1            #id是需要填的部分
  flags=
  frag= 0
  ttl= 64        #生存周期
  proto= icmp    #协议
  chksum= None
  src= 10.87.51.1    #源地址
  dst= 10.87.51.1    #目的地址
  \options\
###[ ICMP ]###
     type= echo-request        #类型为请求包,reply的话会变成echo-reply
     code= 0
     chksum= None
     id= 0x0        #需要填的部分加一
     seq= 0x0        #需要填的部分加二

二、项目代码

1、扫描单个IP

先入门嘛,这先搞一个最基本的,扫描单个IP

#!/usr/bin/python3
# -*- coding: utf-8 -*- 
# --author:valecalida--
# Edit time: 2020/4/17 19:29
from scapy.layers.inet import IP, ICMP, sr1
from random import randint
ip = '10.87.51.1'
ip_id = randint(1, 65535)
icmp_id = randint(1, 65535)
icmp_seq = randint(1, 65535)
packet = IP(dst=ip, ttl=64, id=ip_id)/ICMP(id=icmp_id, seq=icmp_seq)
response = sr1(packet, timeout=1, verbose=0)
if response:
    print("[+] %s is alive" % str(ip))
else:
    print("[-] %s is not alive" % str(ip))

控制台输出如下:

[+] 10.87.51.1 is alive

2、扫描整个网段

扫描网段就需要用到一个新的库:ipaddress ,它有功能可以根据掩码直接生成好 IP地址

from ipaddress import ip_network
host = '225.225.225.0/30'
ip_list = ip_network(host)
for ip in ip_list:
    print(str(ip))

这里给它地址空间小一点,看看控制台,已经自动生成好了对应的 IP地址

225.225.225.0
225.225.225.1
225.225.225.2
225.225.225.3

大家也看出来问题了,就是它生成的地址中并没有去除不可用的地址,不过不影响程序进行,继续上代码,把扫描单个地址写出一个函数,在批量扫描的时候使用多进程,调用扫描单个的函数。

#!/usr/bin/python3
# -*- coding: utf-8 -*- 
# --author:valecalida--
# Edit time: 2020/4/17 16:30
from scapy.layers.inet import IP, ICMP, sr1
from random import randint
from ipaddress import ip_network
from threading import Thread
import time


def ping_single(ip):
    ip_id = randint(1, 65535)
    icmp_id = randint(1, 65535)
    icmp_seq = randint(1, 65535)
    packet = IP(dst=ip, ttl=64, id=ip_id)/ICMP(id=icmp_id, seq=icmp_seq)
    response = sr1(packet, timeout=1, verbose=0)    #verbose不显示详情,也可替换为False
    if response:
        print("[+] %s is alive" % str(ip))


def ping_scan(network):
    ip_list = ip_network(network)
    for ip in ip_list:
        t = Thread(target=ping_single, args=[str(ip)])
        t.start()


if __name__ == '__main__':

    host = '10.87.51.0/24'
    t1 = time.time()
    ping_scan(host)
    t2 = time.time()
    print("[+] 本次扫描共花费 %s 秒" % (t2 - t1))

看看控制台输出情况,扫描 256 台主机,共花费了约 10s,其实还算可以(自卖自夸)。

[+] 10.87.51.1 is alive
[+] 本次扫描共花费 9.795329570770264 秒

文章作者: valecalida
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 valecalida !
评论
  目录