freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

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

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

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

基于Scapy的主机发现脚本
马叉虫的叉cha 2022-10-30 17:44:05 233984
所属地 广东省

简介

scapy是python的一个第三方库,内部已经实现了许多网络协议,可以利用这个库来编写许多工具。当然,scapy可以实现的功能很多,下文只实现基于TCPUDPARP的三种主机发现的简单脚本。下面介绍这次利用python工具编写所用到的命令和功能。

tips:
	由于scapy不太兼容Windows平台,所以该脚本使用主要用于Linux。
创建一个IP和TCP的报文:
    packet = IP()/TCP()
参数信息:
	IP:
        src 			#源IP地址
        dst				#目的IP地址
        flags			#标记
    TCP:
    	dport  			#目标端口
    ARP:
    	hwsrc   		#源MAC地址
        psrc       		#源IP地址
        hwdst      		#目标MAC地址
        pdst       		#目标IP
查看信息:
	packet.show()       #查看发送过来的报文
	ls(packet)			#查看报文结构
	display()           #查看packet响应参数
报文发送:
	第三层发包:
        sr1    			#只捕获第一个响应报文忽略其他。
    第二层发包
        srp	   			#可以指定网卡
        srp1    		#只接收第一个响应

基于TCP的主机发现

正常的三次握手

  • 客户端向服务器发送SYN

  • 服务端返回SYN/ACK

  • 客户端发送ACK表示连接建立

向服务端开放的端口发送SYN标志,服务端收到请求响应SYN+ACK
scapy里输入的命令
ktp = IP()/TCP()                    # 构造数据包
ktp[IP].dst = "192.168.5.129"		# 目标地址
ktp[TCP].flags = "S"				# 标记
ktp[TCP].dport = 80					# 目标端口
recv = sr1(ktp)						# sr1在第三层发包并接收第一个响应包
向服务端开放的端口发送SYN标志,服务端收到请求响应SYN/ACK

image

向服务端不开放的端口发送SYN标志,服务端收到请求响应RST/ACK

image

向服务端直接发送ACK标志,服务端收到请求响应RST重置连接

image

目标机器响应的flags字段为R,表示请求主机给我们发送了一个重置连接的标志,因此可以由此来判断主机是否存活。

image

可以根据flags判断主机是否存活,编写python代码
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import gevent
from gevent.pool import Pool  # 使用协程

gevent.monkey.patch_all()   #使用monkey来识别io操作,必须放在scapy模块之前
from scapy.all import *
from random import randint
import logging

logging.getLogger("scapy.runtime").setLevel(logging.ERROR) # 屏蔽scapy日志输出ERROR以下的信息


def scan(dst):
    try:
        dport = randint(1, 65535)
        packet = IP(dst=dst) / TCP(flags='A', dport=dport)
        res = sr1(packet, timeout=2.0, verbose=False)
        gevent.sleep(0.5)
        if res:
            if 'R' in res[TCP].flags:
                print(dst + "is alive")
            else:
                print('no')
    except AttributeError as err:
        pass


if __name__ == "__main__":
    import time
    starttime = time.time()
    g = Pool(150)  # 限制协程的并发数量
    run_list = [g.spawn(scan, "192.168.5.{}".format(host)) for host in range(256)]
    gevent.joinall(run_list)
    stoptime = time.time()
    print("用时{}".format(starttime - stoptime))

image

在kali端开启抓包看到扫描段发过来的包

image

存活主机的响应

image

基于UDP的主机发现

UDP是一个面向无连接的通信服务,在程序接收到UDP的数据时,会立刻原模原样的发到网络时。即便出现丢包、或者数据包顺序错乱,也不会再次发送。向目标发送UDP数据包时,对方并不会返回任何的UDP包。但是当主机存活时,如果发送的目标端口是关闭的,目标会响应一个unreachable的ICMP数据包,否则无响应,我们可以利用此原理编写扫描工具


scapy命令
ukp = IP()/UDP()
ukp[IP].dst = "192.168.5.129"
ukp[UDP].dport = 445
recv = sr1(ukp)
可以看到不可达的响应

image

根据此原理编写python脚本,判断有无响应包
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import gevent
from gevent.pool import Pool
gevent.monkey.patch_all()
from scapy.all import *
from random import randint
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)


def scan(dst):
    try:
        dport = randint(1, 65535)
        packet = IP(dst=dst)/UDP(dport=dport)
        res = sr1(packet, timeout=1.0, verbose=False)
        if res:
            print(dst+"is alive")
    except AttributeError as err:
        pass

if __name__ == "__main__":

    import time
    starttime = time.time()
    g = Pool(150)  # 限制协程的并发数量
    run_list = [g.spawn(scan, "192.168.5.{}".format(host)) for host in range(256)]
    gevent.joinall(run_list)
    stoptime = time.time()
    print("用时{}".format(starttime - stoptime))
扫描成功

image

在kali端看到了响应给扫描机的ICMP包

image

基于ARP的主机发现

地址解析协议ARP处于数据链路层,用于根据IP(网络层)获取MAC(数据链路层)地址,简单的来说,在一个局域网内,一台主机想要和另一台主机通信时,需要知道对方MAC地址,如果本地ARP缓存没有对方的MAC地址,就会向局域网进行广播发送ARP的请求,询问目标IP的MAC地址,同时数据包里包含自己的IP和MAC地址,局域网内的所有主机都会收到该请求。如果自身IP与ARP请求的IP一致,则将自己的MAC地址发回给请求方,并将请求数据包中的IP与MAC地址存入本地。


我们可以利用arp请求扫描存活的主机,ARP请求涉及网络层与数据链路层,因此我们需要scapy模块里的EtherARP

编写扫描器需要用到的参数
Ether:
    src    # 源MAC地址
    dst    # 目表MAC地址
ARP:
    hwsrc 	  # 源MAC地址
    hwdst    # 源IP地址
    pdst     # 目标IP地址
    op       # 1是ARP请求  2是ARP的响应

image

构造一个ARP请求,这是对方主机响应后的正常回显,可以看到对方的mac地址

image

响应信息里对方的MAC地址

image

image

再次发送一个ARP请求,这次请求一个局域网里不存在的主机IP

image

可以看到并没有响应信息

image

可以根据响应信息来进行扫描器的编写
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import gevent
from gevent.pool import Pool
gevent.monkey.patch_all()
from scapy.all import *
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

def scan(dst, conf):
    try:
        ip, mac, iface = conf
        kpt = Ether() / ARP()
        kpt[Ether].src = mac    # 源MAC地址
        kpt[Ether].dst = "FF:FF:FF:FF:FF:FF"    # 目的MAC地址
        kpt[ARP].hwsrc = "00:0c:29:ec:dc:d2"
        kpt[ARP].hwdst = mac
        kpt[ARP].pdst = dst
        kpt[ARP].op = 1
        ares = srp(kpt, iface=iface, timeout=2.0, verbose=False)
        if ares[0].res:
            print("\nIP:{0}\nMAC:{1}".format(dst, ares[0].res[0][1].src))
    except AttributeError as err:
        pass

if __name__ == "__main__":
    import time
    import subprocess
    import re

    rec = input("请输入扫描网卡:").strip()
    # 提取本地IP与MAC信息
    res = subprocess.Popen(rec, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True)
    tmp = res.stdout.read().decode() + res.stderr.read().decode()
    IP = re.search('inet(.*?)netmask', tmp, re.S)
    MAC = re.search('ether(.*?)txqueuelen', tmp, re.S)

    starttime = time.time()
    g = Pool(150)  # 限制协程并发数量,单线程的,不要设置太大
    run_list = [g.spawn(scan, "192.168.5.{}".format(host), (IP, MAC, rec)) for host in range(256)]
    gevent.joinall(run_list)
    stoptime = time.time()
    print("用时{}".format(starttime - stoptime))
查看要扫描网段的网卡

image

可以看到扫描的结果是三种方法里最快的

image

当然,上文只是简单的实现了主机扫描的功能,代码运行速度还有很大的提升空间,后续会整合成一个工具,能力有限大佬勿喷。。。
# web安全 # 系统安全 # 数据安全 # 内网渗透 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 马叉虫的叉cha 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
马叉虫的叉cha LV.2
这家伙太懒了,还未填写个人描述!
  • 2 文章数
  • 0 关注者
基于Scapy的主机发现脚本
2022-10-30
文章目录