title: 2023网络安全作业chap0x05 description: 基于 Scapy 编写端口扫描器 slug: nsChap0x05 date: 2023-10-20 15:33:00+0800 image: assets/imgs/gitlab.png categories:
- cucStudy
tags:
- VirtualBox
- linux
- Kali
- ComputerNetworkSecurity
comments: true
links:
title: 网络安全作业chap0x04 description: 2023网络安全作业chap0x04作业img仓库 website: https://git.cuc.edu.cn/ccs/ns-2023/liduoyang/-/tree/chap0x04 image: /gitlab.png
title: 网络安全在线课本 description: 这是一本试水互联网+高等教育的开放编辑电子版教材,作者本人从2011年起在中国传媒大学计算机学院讲授《网络安全》这门课程。在2014年之前,本课程的授课对象是计算机科学与技术专业大三的选修课。从2014年起,本门课程首次面向信息安全专业本科生进行教学。 website: https://c4pr1c3.github.io/cuc-ns image: /gitlab.png
测试端口状态为:开放、关闭 和 过滤 状态时的程序执行结果
ufw disable
systemctl start apache2 # port 80
ufw enable && ufw deny 80/tcp
这种扫描方式可以使用 Connect()调用,使用最基本的 TCP 三次握手链接建立机制,建立一个链接到目标主机的特定端口上。 首先发送一个 SYN 数据包到目标主机的特定端口上,接着我们可以通过接收包的情况对端口的状态进行判断:
如果接收到的是一个 SYN/ACK 数据包,则说明端口是开放状态的; 如果接收到的是一个 RST/ACK 数据包,通常意味着端口是关闭的并且链接将会被重置; 如果目标主机没有任何响应则意味着目标主机的端口处于过滤状态。
若接收到 SYN/ACK 数据包(即检测到端口是开启的),便发送一个 ACK 确认包到目标主机,这样便完成了三次握手连接机制。成功后再终止连接。如图所示:
def tcp_connect_scan(target_ip, target_port):
print(f"\033[31m[tcp_connect_scan]\033[0m {target_port}...\n")
response = sr1(IP(dst=target_ip)/TCP(dport=target_port, flags="S"), timeout=2)
if response and response.haslayer(TCP):
if response[TCP].flags == 0x12:
send(IP(dst=target_ip)/TCP(dport=target_port, flags="R"))
print(f"Port {target_port} is open\n")
elif response[TCP].flags == 0x14:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is filtered\n")
在TCP connect scan
基础上,收到目标主机的数据包后,不进行回应,从而不打成三次握手连接,这使得目标主机难以确定是否正在进行扫描。
def tcp_stealth_scan(target_ip, target_port):
print(f"\033[31m[tcp_stealth_scan]\033[0m {target_port}...\n")
response = sr1(IP(dst=target_ip)/TCP(dport=target_port, flags="S"), timeout=2)
if response and response.haslayer(TCP):
if response[TCP].flags == 0x12:
send(IP(dst=target_ip)/TCP(dport=target_port, flags="R"))
print(f"Port {target_port} is open\n")
elif response[TCP].flags == 0x14:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is filtered\n")
Xmas 发送一个 TCP 包,并对 TCP 报文头 FIN、URG 和 PUSH 标记进行设置。若是关闭的端口则响应 RST 报文;开放或过滤状态下的端口则无任何响应。如图所示。优点是隐蔽性好,缺点是需要自己构造数据包,要求拥有超级用户或者授权用户权限。
def tcp_xmas_scan(target_ip, target_port):
print(f"\033[31m[tcp_xmas_scan]\033[0m {target_port}...\n")
response = sr1(IP(dst=target_ip)/TCP(dport=target_port, flags="FPU"), timeout=2)
if response and response.haslayer(TCP):
if response[TCP].flags == 0x14:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is filtered or opened\n")
仅发送 FIN 包,它可以直接通过防火墙,如果端口是关闭的就会回复一个 RST 包,如果端口是开放或过滤状态则对 FIN 包没有任何响应。如图所示。 其优点是 FIN 数据包能够通过只监测 SYN 包的包过滤器,且隐蔽性高于 SYN 扫描。缺点和 SYN 扫描类似,需要自己构造数据包,要求由超级用户或者授权用户访问专门的系统调用。
def tcp_fin_scan(target_ip, target_port):
print(f"\033[31m[tcp_fin_scan]\033[0m {target_port}...\n")
response = sr1(IP(dst=target_ip)/TCP(dport=target_port, flags="F"), timeout=2)
if response and response.haslayer(TCP):
if response[TCP].flags == 0x14:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is filtered or opened\n")
发送一个 TCP 数据包,关闭所有 TCP 报文头标记。只有关闭的端口会发送 RST 响应。其优点和 Xmas 一样是隐蔽性好,缺点也是需要自己构造数据包,要求拥有超级用户或者授权用户权限。
def tcp_null_scan(target_ip, target_port):
print(f"\033[31m[tcp_null_scan]\033[0m {target_port}...\n")
response = sr1(IP(dst=target_ip)/TCP(dport=target_port, flags=""), timeout=2)
if response and response.haslayer(TCP):
if response[TCP].flags == 0x14:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is filtered or opened\n")
UDP 是一个无链接的协议,当我们向目标主机的 UDP 端口发送数据,我们并不能收到一个开放端口的确认信息,或是关闭端口的错误信息。可是,在大多数情况下,当向一个未开放的 UDP 端口发送数据时,其主机就会返回一个 ICMP 不可到达(ICMP_PORT_UNREACHABLE)的错误,因此大多数 UDP 端口扫描的方法就是向各个被扫描的 UDP 端口发送零字节的 UDP 数据包,如果收到一个 ICMP 不可到达的回应,那么则认为这个端口是关闭的,对于没有回应的端口则认为是开放的,但是如果目标主机安装有防火墙或其它可以过滤数据包的软硬件,那我们发出 UDP 数据包后,将可能得不到任何回应,我们将会见到所有的被扫描端口都是开放的。如图所示: 其缺点是,UDP 是不可靠的,UDP 数据包和 ICMP 错误报文都不保证到达;且 ICMP 错误消息发送效率是有限的,故而扫描缓慢;还有就是非超级用户无法直接读取端口访问错误。
def udp_scan(target_ip, target_port):
print(f"\033[31m[udp_scan]\033[0m {target_port}...\n")
# 发送一个零字节的UDP数据包到目标端口
udp_packet = IP(dst=target_ip)/UDP(dport=target_port)
response = sr1(udp_packet, timeout=2, verbose=0)
if response is None:
# 没有回应,通常认为端口是开放的
print(f"Port {target_port} is open or filtered\n")
else:
if response.haslayer(ICMP):
# 收到ICMP错误消息
if int(response.getlayer(ICMP).type) == 3 and int(response.getlayer(ICMP).code) in [3, 13, 14]:
print(f"Port {target_port} is closed\n")
else:
print(f"Port {target_port} is open or filtered\n")
close
在windows编写完代码后传到kali
虚拟机运行时报错SyntaxError: Non-ASCII character '\xe7' in file test.py on line 3, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
解决方法:在文件开头加入# -*- coding: utf-8 -*-