少年锦时

投我以木桃,报之以琼瑶;你予我三月春光,我赠你四月桃花。人间真情莫过于此。

俗话说的好

前言

?:老哥,是时候前面写的扫描器升升级了,不然都没法打怪了。。。

:从何说起啊?

?:一扫就被墙,一扫就被墙,整个*啊!

:也难怪,哥技术不好,无法带你飞,今后的路你可要自行摸索啊!!!

?:老哥~

:老弟~

?:行啦!别整这些没用的,快给我想招,要不然弄*你!!!

:这变脸如翻书啊。。。咳咳嗯~,方法是有滴,前面不是介绍了 scapy 模块嘛,好家伙,这模块,写扫描,写嗅探,游历于各层协议如入无人之境,取敌方主机首级如探囊取物,各种协议分析函数信手拈来,简直人中吕布,马中赤兔,是为网络协议分析之上乘神兵利器也~

?:逼逼完了就赶紧说说怎么整吧,一个大老爷们磨磨唧唧的。

:话说前面写的端口扫描器只有一种扫描方式 -- TCP全连接扫描,在无防火墙/IPS/IDS ,且网络顺畅的情况下,是为最精准的扫描方式,毕竟是经过了三次握手,但是在当今这错综复杂且危机四伏的网络时代,网络链路中怎能 "无墙" 之说,为了应对这种情况,如 Nmap 端口扫描神器的扫描方式也是衍生出了十几种之多(详情可参考下方链接),在实际的渗透测试过程中,多种扫描方式相结合方能起到较为准确的扫描结果。

https://nmap.org/man/zh/man-port-scanning-techniques.html

Nmap常用的扫描方式

:下面我们参考 nmap 的端口扫描原理,共采用8种端口扫描方式:TCP 全连接扫描,TCP SYN扫描,TCP ACK扫描,TCP Null扫描,TCP Window扫描,TCP Fin扫描,TCP Xmas扫描和UDP扫描。

?:哟哟哟~你看这个面它又长又宽,再看这个碗它又大又圆~

声明

以下内容参考自玄魂大佬的端口扫描器笔记,如有侵权,请联系删除!!!

前置知识

前置知识可以看前一篇文章《TCP三次握手/四次挥手》,主要理解TCP三次握手建立连接的过程即可。

利用 argparse 模块接收命令行参数,关于该模块的简介可参考前面的文章。

import argparse# 打印窗口的状态def print_ports(port, state):    print("%s | %s" % (port, state))# TCP全连接扫描def tcpScan(target, ports):    print("TCP全连接扫描")# TCP SYN扫描def synScan(target, ports):    print("TCP SYN扫描")# TCP ACK扫描def ackScan(target, ports):    print("TCP ACK扫描")# TCP window扫描def windowScan(target, ports):    print("TCP window扫描")# TCP Null扫描def nullScan(target, ports):    print("TCP Null扫描")# TCP FIN扫描def finScan(target, ports):    print("TCP FIN扫描")# TCP XMAX扫描def xmaxScan(target, ports):    print("TCP XMAX扫描")# UDP 扫描def udpScan(target, ports):    print("UDP 扫描")if __name__ == '__main__':    parser = argparse.ArgumentParser("")    parser.add_argument("-t", "--target", dest="target",                        help="目标IP", required=True)    parser.add_argument("-p", "--ports", dest="ports",                        type=int, nargs="+", help="指定端口列表(21 23 80 ...)")    parser.add_argument("-s", "--scantype", dest="scantype", help="""        "T":全连接扫描        "S":syn扫描        "A":ack扫描        "W":TCPwindows扫描        "N":NULL扫描        "F":FIN扫描        "X":Xmas扫描        "U":UDP扫描        """, required=True)    args = parser.parse_args()    target = args.target    scantype = args.scantype    if args.ports:        ports = args.ports    else:        ports = range(1, 65535)    print("扫描主机{},端口:{}".format(target, ports))    if scantype == "T":        tcpScan(target, ports)    elif scantype == "S":        synScan(target, ports)    elif scantype == "A":        ackScan(target, ports)    elif scantype == "W":        windowScan(target, ports)    elif scantype == "N":        nullScan(target, ports)    elif scantype == "F":        finScan(target, ports)    elif scantype == "X":        xmaxScan(target, ports)    elif scantype == "U":        udpScan(target, ports)    else:        print("不支持当前模式。")

TCP Connect扫描

TCP Connect扫描又叫做全连接扫描,客户端与服务器建立 TCP 连接要进行一次三次握手,如果进行了一次成功的三次握手,则说明端口开放。

假设客户端想与服务端的80端口进行通信,首先客户端会发送一个带有SYN标识和端口号的TCP数据包给服务器,如果服务器这个端口是开放的,则会接受这个连接并返回一个带有SYN和ACK标识的数据包给客户端,随后客户端会发送带有ACK和RST标识的数据包给服务点,此时客户端与服务器建立了连接。如果端口不开放则会返回一个RST标识的数据包给客户端。

当客户端发送一个带有 SYN 标识和端口号的 TCP 数据包给服务器后,如果服务器端返回一个带 RST 标识的数据包,则说明端口处于关闭状态。

代码实现如下:

def tcpScan(target,ports):    print("tcp全连接扫描 %s with ports %s" % (target, ports))    for port in ports:        send=sr1(IP(dst=target)/TCP(dport=port,flags="S"),timeout=2,verbose=0) #sr1()工作在第三层,用来发送数据包和返回一个应答数据包,verbose=0 是不显示数据收发过程        if (send is None):            print_ports(port,"closed")        elif send.haslayer("TCP"): #返回的数据包有 TCP 部分            if send["TCP"].flags == "SA": #TCP部分SYN和ACK都置位,说明对方主机响应连接                send_1 = sr1(IP(dst=target) / TCP(dport=port, flags="AR"), timeout=2, verbose=0) #将 TCP 部分的 ACK和RST 都置位,断开连接                print_ports(port,"open")            elif send["TCP"].flags == "RA": #TCP部分的RST和ACK置位,说明对方主机拒绝连接                print_ports(port,"close")            else:                print_ports(port,"unknown")        else:            print_ports(port,"unknown")

上面的代码,组合IP和TCP报文,依据三次握手的流程对端口状态做判断。主义TCP标志位的设置和判断。使用scapy发送tcp数据包的时候TCP的标志位使用如下简写形式:

  • F : FIN - 结束; 结束会话

  • S : SYN - 同步; 表示开始会话请求

  • R : RST - 复位;中断一个连接

  • P : PUSH - 推送; 数据包立即发送

  • A : ACK - 应答

  • U : URG - 紧急

  • E : ECE - 显式拥塞提醒回应

  • W : CWR - 拥塞窗口减少

TCP SYN扫描

TCP SYN扫描又称半开式扫描,该过程不会和服务端建立完整的连接,首先客户端会发送一个带有SYN标识和端口号的TCP数据包给服务器,如果服务器这个端口是开放的,则会接受这个连接并返回一个带有SYN和ACK标识的数据包给客户端,随后客户端会返回带有RST标识的数据包而不是返回一个带有ACK和RST标识的数据包。

如果目标端口处于关闭状态,则服务端会返回一个RST标识的数据包。

代码实现如下:

def synScan(target, ports):    print("tcp半开放扫描 %s with ports %s" % (target, ports))    for port in ports:        send = sr1(IP(dst=target) / TCP(dport=port,flags="S"), timeout=2, verbose=0)        if send is None:            print_ports(port, "close")        elif send.haslayer("TCP"):            # print(send["TCP"].flags)            if send["TCP"].flags == "SA":                send_1 = sr1(IP(dst=target) / TCP(dport=port,flags="R"), timeout=2, verbose=0)                print_ports(port, "open")            elif send["TCP"].flags == "RA":                print_ports(port, "close")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "unkonwn")

注:SYN扫描和TCP全连接扫描的区别在于结束与服务端连接的数据包:SYN扫描是直接发RST,而TCP全连接扫描是发ACK和RST

TCP ACK扫描

ACK扫描只返回两种状态:unfiltered/filtered

发送一个flags为ACK报文,open(开放的)和closed(关闭的) 端口 都会返回RST报文,至于他们是open还是closed状态我们无法确定。不响应的端口,或者发送特定的ICMP错误消息(类型3,代号1,2,3,9,10, 或者13)的端口,标记为 filtered(被过滤的)。大致的流程如下图:

上面那种情况下是服务器REJECT掉数据包,所以客户端会有个ICMP包返回,如果是直接DROP掉的话,就会什么也不会返回,所以我们要判断该主机是否存在,因为如果一个主机存在的话,向它发送一个flags为ACK包的话,无论端口是否关闭都会有返回一个flags为RST包,如果是DROP是话就会一个数据包都不会返回,所以我们可以利用这一点去判断端口是否被过滤了,大致流程如下:

代码实现如下:

def ackScan(target, ports):    print("tcp ack扫描 %s with ports %s" % (target, ports))    for port in ports:        ack_flag_scan_resp = sr1(            IP(dst=target) / TCP(dport=port, flags="A"), timeout=5, verbose=0)        # print(str(type(ack_flag_scan_resp)))        if str(type(ack_flag_scan_resp)) == "":            print_ports(port, "filtered")        elif ack_flag_scan_resp.haslayer(TCP):            if ack_flag_scan_resp.getlayer(TCP).flags == "R":                print_ports(port, "unfiltered")            else:                print_ports(port, "unkonwn")        elif ack_flag_scan_resp.haslayer(ICMP):            if int(ack_flag_scan_resp.getlayer(ICMP).type) == 3 and int(ack_flag_scan_resp.getlayer(ICMP).code) in [1, 2, 3, 9, 10, 13]:                print_ports(port, "filtered")            else:                print_ports(port, "filtered")        else:            print_ports(port, "unkonwn")

TCP Window扫描

TCP 窗口扫描的流程同 ACK 扫描类似,同样是客户端向服务器发送一个带有 ACK 标识和端口号的 TCP 数据包,但是这种扫描能够用于发现目标服务器端口的状态。在 ACK 扫描中返回 RST 表明没有被过滤,但在窗口扫描中,当收到返回的 RST 数据包后,它会检查窗口大小的值。如果窗口大小的值是个非零值,则说明目标端口是开放的。

如果返回的 RST 数据包中的窗口大小为0,则说明目标端口是关闭的。

注:TCP窗口扫描和ACK扫描类似,区别在于TCP窗口扫描在接收到RST包时会检查窗口大小,如果窗口是一个非零值,就说明端口是开放的。

代码实现:

def windowScan(target, ports):    print("tcp window扫描 %s with ports %s " % (target, ports))    for port in ports:        window_scan_resp = sr1(            IP(dst=target) / TCP(dport=port, flags="A"), timeout=5, verbose=0)        # print(str(type(window_scan_resp)))        if str(type(window_scan_resp)) == "":            print_ports(port, "close")        elif window_scan_resp.haslayer(TCP):            if window_scan_resp.getlayer(TCP).window == 0:                print_ports(port, "close")            elif window_scan_resp.getlayer(TCP).window > 0:                print_ports(port, "open")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "close")

TCP Null扫描

在空扫描中,客户端发出的 TCP 数据包仅仅只会包含端口号而不会有其他任何的标识信息。如果目标端口是开放的则不会回复任何信息。

如果服务器返回了一个 RST(或者RST+ACK) 数据包,则说明目标端口是关闭的。

如果返回 ICMP 错误类型3且代码为1,2,3,9,10或13的数据包,则说明端口被服务器过滤了。

代码实现:

def nullScan(target, ports):    print("tcp null 扫描 %s with ports %s" % (target, ports))    for port in ports:        null_scan_resp = sr1(            IP(dst=target) / TCP(dport=port, flags=""), timeout=5, verbose=0)        if str(type(null_scan_resp)) == "":            print_ports(port, "open|filtered")        elif null_scan_resp.haslayer(TCP):            if null_scan_resp.getlayer(TCP).flags == "R" or null_scan_resp.getlayer(TCP).flags == "RA":                print_ports(port, "close")            else:                print_ports(port, "unkonwn")        elif null_scan_resp.haslayer(ICMP):            if int(null_scan_resp.getlayer(ICMP).type) == 3 and int(null_scan_resp.getlayer(ICMP).code) in [1, 2, 3, 9, 10, 13]:                print_ports(port, "filtered")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "unkonwn")

TCP FIN扫描

FIN 扫描会向服务器发送带有 FIN 标识和端口号的 TCP 数据包。如果没有服务器端回应则说明端口开放。

如果服务器返回一个 RST 数据包,则说明目标端口是关闭的。

如果服务器返回了一个 ICMP 数据包,其中包含 ICMP 目标不可达错误类型3以及 ICMP 代码为1,2,3,9,10或13,则说明目标端口被过滤了无法确定端口状态。

代码实现:

def finScan(target, ports):    print("tcp FIN扫描 %s with ports %s" % (target, ports))    for port in ports:        fin_scan_resp = sr1(IP(dst=target) / TCP(dport=port,                                                 flags="F"), timeout=3, verbose=0)        if str(type(fin_scan_resp)) == "":            print_ports(port, "open|filtered")        elif fin_scan_resp.haslayer(TCP):            if fin_scan_resp.getlayer(TCP).flags == 0x14:  # 0x14就是RA                print_ports(port, 'close')            else:                print_ports(port, "unkonwn")        elif fin_scan_resp.haslayer(ICMP):            if int(fin_scan_resp.getlayer(ICMP).type) == 3 and int(fin_scan_resp.getlayer(ICMP).code) in [1, 2, 3, 9, 10, 13]:                print_ports(port, "filtered")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "unkonwn")

TCP 圣诞树(Xmas扫描)

在发送的数据包中设置PSH(PUSH推送,数据包立刻发送),FIN(结束会话),URG(紧急)标志位,如果目标端口是开放的则不会回复任何信息。

如果目标端口关闭则会返回一个RST+ACK的数据包。

但如果服务器返回了一个 ICMP 数据包,其中包含 ICMP 目标不可达错误类型3以及 ICMP 状态码为1,2,3,9,10或13,则说明目标端口被过滤了无法确定是否处于开放状态。

代码实现:

def xmaxScan(target, ports):    print("tcp xamx扫描 %s with ports %s" % (target, ports))    for port in ports:        xmax_scan_resp = sr1(            IP(dst=target) / TCP(dport=port, flags="FPU"), timeout=3, verbose=0)        if str(type(xmax_scan_resp)) == "":            print_ports(port, "open|filtered")        elif xmax_scan_resp.haslayer(TCP):            if xmax_scan_resp.getlayer(TCP).flags == "R":                print_ports(port, "close")            else:                print_ports(port, "unkonwn")        elif xmax_scan_resp.haslayer(ICMP):            if int(xmax_scan_resp.getlayer(ICMP).type) == 3 and int(xmax_scan_resp.getlayer(ICMP).code) in [1, 2, 3, 9, 10, 13]:                print_ports(port, "filtered")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "unkonwn")

UDP扫描

TCP 是面向连接的协议,而UDP则是无连接的协议。

面向连接的协议会先在客户端和服务器之间建立通信信道,然后才会开始传输数据。如果客户端和服务器之间没有建立通信信道,则不会有任何产生任何通信数据。

无连接的协议则不会事先建立客户端和服务器之间的通信信道,只要客户端到服务器存在可用信道,就会假设目标是可达的然后向对方发送数据。

客户端会向服务器发送一个带有端口号的 UDP 数据包。如果服务器回复了 UDP 数据包,则目标端口是开放的。

如果服务器返回了一个 ICMP 目标不可达的错误和代码3,则意味着目标端口处于关闭状态。

如果服务器返回一个 ICMP 错误类型3且代码为1,2,9,10或13的数据包,则说明目标端口被服务器过滤了。

但如果服务器没有任何相应客户端的 UDP 请求,则可以断定目标端口可能是开放或被过滤的,无法判断端口的最终状态。

代码实战:

def udpScan(target, ports):    print("UDP扫描 %s with ports %s" % (target, ports))    for port in ports:        udp_scan_resp = sr1(            IP(dst=target) / UDP(dport=port), timeout=5, verbose=0)        if str(type(udp_scan_resp)) == "":            print_ports(port, "open|filtered")        elif udp_scan_resp.haslayer(UDP):            if udp_scan_resp.getlayer(UDP).flags == "R":                print_ports(port, "open")            else:                print_ports(port, "unkonwn")        elif udp_scan_resp.haslayer(ICMP):            if int(udp_scan_resp.getlayer(ICMP).type) == 3 and int(udp_scan_resp.getlayer(ICMP).code) in [1, 2, 9, 10, 13]:                print_ports(port, "filtered")            elif int(udp_scan_resp.getlayer(ICMP).type) == 3 and int(udp_scan_resp.getlayer(ICMP).code) == 3:                print_ports(port, "close")            else:                print_ports(port, "unkonwn")        else:            print_ports(port, "unkonwn")

测试

尾声

我是匠心,一个在清流旁默默磨剑的匠人,期待那一天能利刃出鞘,仗剑走江湖。

https 带端口_基于scapy模块的8种端口扫描相关推荐

  1. python scapy模块_关于scapy模块

    scapy是一个可以让用户发送.侦听和解析并伪装网络报文的Python程序.这些功能可以用于制作侦测.扫描和攻击网络的工具. 换言之,Scapy 是一个强大的操纵报文的交互程序.它可以伪造或者解析多种 ...

  2. ubuntu 查看对外端口_[mcj]Ubuntu如何查看已开放端口|Ubuntu开放关闭指定端口方法...

    有时候我们经常无法连接服务器的某些端口,这时就需要查看一下这些端口是不是放行了,最简单的方法就是使用ufw工具,步骤如下. 1 安装ufw sudo apt install ufw 1 sudo ap ...

  3. STP:五种端口状态与角色 RSTP:3种端口状态与角色

    阻塞(blocking):该端口是非指定端口,不参与帧转发.此类端口接收 BPDU 帧来确定根桥交换机的位置和根 ID,以及最终的活动 STP 拓扑中每个交换机端口扮演的端口角色. 侦听(listen ...

  4. axis2 默认端口_基于 AXIS2/C 的 C 语言库实现对提供 REST API 的系统进行数据访问...

    基于 AXIS2/C 的 C 语言库实现对提供 REST API 的系统进行数据访问 宋 东平 和 赵 健 2013 年 3 月 07 日发布 AXIS2/C 简介和 REST 及 REST API ...

  5. dubbo consumer 端口_基于Springboot+Dubbo+Nacos 注解方式实现微服务调用

    今天跟大家分享基于Springboot+Dubbo+Nacos 注解方式实现微服务调用的知识. 1 项目结构 |-- spring-boot-dubbo-demo (父级工程) |-- spring- ...

  6. 基于xilinx fpga的ofdm通信系统基带设计_基于嵌入式Wi-Fi处理器的无线系统设计...

    0 引 言 随着物联网技术的发展,众多的嵌入式系统均有增加Wi-Fi特性的需求,比如利用智能手机内建的Wi-Fi来遥控各种嵌入式设备,使支持机器对机器的通信(M2M)具有物联网通讯功能的嵌入式网络解决 ...

  7. jenkins不能启用端口_基于K8s的Jenkins持续集成实战(上)

    Jenkins是一款广泛受到的欢迎的持续集成工具,有着丰富的插件以及扩展能力,基本上能够满足大多数团队的需求.本文将从工具使用的角度,来讲述如何在kubernetes集群中使用Jenkins作为持续集 ...

  8. 查看模拟器使用端口_为什么我们仍然使用模拟音频端口?

    查看模拟器使用端口 When leaks about what the chassis of the iPhone 7 might look like hit headlines earlier th ...

  9. 将设备插入usb2.0端口_将鼠标插入USB 3.0端口有什么好处?

    将设备插入usb2.0端口 When you are serious about online gaming, you look for every edge that you can find. T ...

  10. nc 探测端口_防盗报警探测器的几种防拆接线方式,附接线图

    1.无防拆接线 不启用探测器的防拆功能,报警系统无法感知探测器是否遭到破坏,这种方式的接线在报警主机不设置单独的防拆防区或防拆设置,探测器的信号线材只需四芯.其接线方式最为简朴.可靠,但安全性差. 在 ...

最新文章

  1. FPGA基础知识极简教程(3)从FIFO设计讲起之同步FIFO篇
  2. petshop4.0 详解之一(系统架构设计)
  3. 【数字信号处理】基本序列 ( 实指数序列 | 收敛序列 | 发散序列 )
  4. c语言寻找James,[semi-tutorial]某亚里亚写在JamesM边上的OS笔记
  5. 机器学习(二)Logistic回归(Logistic regression)算法
  6. [html] 列举下哪些块元素里面不能放哪些块元素呢?
  7. 打破多项世界记录  双11背后最大的力量是技术
  8. Java文档阅读笔记-JPA中getOne()和findById的区别
  9. Unity 性能优化经验整理
  10. 无法打开文件ws32_2.lib ws2_32.lib
  11. SqlServer 计算年龄(岁月天)的函数
  12. 基于Matlab的数字水印设计—基于DCT域的水
  13. Carsim工况设置:道路场景的构建
  14. 微信支付 postman_微信信用分是什么怎么回事 如何查看微信支付分图文攻略
  15. 【问题解决】正则表达式在线自动生成器
  16. dz.27z.co index.php,dc vip中心 专业版v2.2.1 discuz插件 dzvip插件 vip会员插件 积分充值插件...
  17. google paly 应用推广 发送渠道广播
  18. unity动态生成预制体
  19. CSMA/CD 与 CSMA/CA概述
  20. C++高级——多线程编程

热门文章

  1. [搬运] 写给 C# 开发人员的函数式编程
  2. 用Map集合来统计一个字符串数组中每个字符串的个数
  3. ElasticSearch全文搜索引擎之term和match的区别
  4. SpringBoot 2.0.x应用修改默认的端口号
  5. 资深CTO带来的8条Serverless最佳实践
  6. Redis与LRU实现
  7. Mybatis 入门案例分享
  8. Java容器类研究8:HashMap
  9. Java Design Demo -简单的队列-异步多任务队列(java android)
  10. Node.js与Golang使用感受与小结【二】