作业题目

实验2:端口扫描实验

时间:第3周

地点及方式:教室

人员:全体学生

实验内容:

本次实验主要对主机扫描和端口扫描原理的理解。使用Python(Scapy库)编写端口扫描程序,对目标IP(包含IP地址段)进行扫描,完成以下功能:

1)使用ICMP协议探测主机是否开启;

2)对本机(关闭防火墙)的开放端口和非开放端口完成半连接、ACK、FIN、Null、Xmas、Windows扫描,并与Nmap扫描结果进行比较。

3)对远程(有防火墙)主机的开放端口和非开放端口完成半连接、ACK、FIN、Null、Xmas、Windows扫描,并与2)进行比较,分析结果。

实验报告:

需要提交一份详细的实验报告和截图,来描述做了什么和观察到了什么。还需要对观察结果进行解释。还请列出重要的代码片段,然后进行解释。仅附加代码而不作任何解释将不得分。

需要提交一份详细的实验报告和截图,来描述做了什么和观察到了什么。还需要对观察结果进行解释。还请列出重要的代码片段,然后进行解释。仅附加代码而不作任何解释将不得分。

评分要点:

  • a) 功能完成情况:60%;

  • b) 代码规范性:20%;

  • c) 报告质量:20%

提交方式:

请在学习通作业模块提交,选择对应的作业编号进行提交,请注意:

  • 代码命名为:Lab2_code_学号_姓名.zip

  • 文档命名为:Lab2_doc_学号_姓名.pdf

实验代码及结果

代码:

from scapy.all import *
from IPy import IP as IPY

'''
通过设置flags位为'*',根据不同的扫描方式修改‘*’的值
'''
# 在linux操作系统下需要取消下面一行代码的注释
# conf.L3socket=L3RawSocket
def port_scan(ip, port):
p = IP(dst=ip) / TCP(dport=int(port), flags="*")
ans = sr1(p, timeout=1, verbose=1)
print(ans)
print(type(ans))
if ans == None or ans[TCP].flags!='*':
print(ip, "port", port, "is open.")
elif ans != None and ans[TCP].flags == '*':
ans.display()
print(ip, "port", port, "is closed.")

def syn_scan(ip, port):
print("this is syn_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="S")
ans = sr1(p, timeout=5, verbose=1)
print(ans)
if ans:
if ans[TCP].flags == "SA":
ans.display()
print(ip, "port", port, "is open.")
elif ans[TCP].flags == "RA":
print(ip, "port", port, "is closed")
else:
print(ip, "port", port, "has a unknown response")
else:
print(ip, "port", port, "is filtered.")

# ACK扫描 (只能判定是否存在防火墙)
def ack_scan(ip, port):
print("this is ack_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="A")
ans = sr1(p, timeout=5, verbose=1)
print(ans)
if ans:
ans.display()
if ans[TCP].flags == "R":
print(ip, "port", port, "is unfiltered")
else:
print(ip, "port", port, "is filtered")
else:
print(ip, "port", port, "is filtered")

def fin_scan(ip, port):
print("this is fin_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="F")
ans = sr1(p, timeout=5, verbose=1)
print(ans)
if ans:
ans.display()
if ans[TCP].flags == "RA":
print(ip, "port", port, "is closed.")
else:
print(ip, "port", port, "has an unknown response.")
else:
print(ip, "port", port, "is open or filtered")

def xmas_scan(ip, port):
print("this is xmas_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="FPU")
ans = sr1(p, timeout=5, verbose=1)
print(ans)
if ans:
ans.display()
if ans[TCP].flags == "RA":
print(ip, "port", port, "is closed.")
else:
print(ip, "port", port, "has an unknown response.")
else:
print(ip, "port", port, "is open or filtered")

def null_scan(ip, port):
print("this is null_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="")
ans = sr1(p, timeout=5, verbose=1)
print(ans)
if ans:
ans.display()
if ans[TCP].flags == "RA":
print(ip, "port", port, "is closed.")
else:
print(ip, "port", port, "has an unknown response.")
else:
print(ip, "port", port, "is open or filtered")

def windows_scan(ip, port):
print("this is windows_scan:")
p = IP(dst=ip) / TCP(dport=int(port), flags="A")
ans = sr1(p, timeout=5, verbose=1)
if ans:
if (ans.getlayer(TCP).window == 0):
print(ip, "The PORT ", port, " is closed.")
elif (ans.getlayer(TCP).window > 0):
print(ip, "The PORT ", port, "is open.")
else:
print(ip, "The PORT ", port, "is filtered")

def Ping(dest):
ip_addr=IPY(dest)
for ip in ip_addr:
#print(ip)
packet=IP(dst=str(ip))/ICMP()/b'rootkit'
ping=sr1(packet,timeout=5,verbose=False)
if ping:
print("\033[0;32;47m\t"+str(ip)+" is up!"+"\033[0m")
else:
print(str(ip)+" is down!")

if __name__ == '__main__':
dest='127.0.0.1'
port =80
Ping(dest)
syn_scan(dest,port)
# ack_scan(dest, port)
# fin_scan(dest, port)
# xmas_scan(dest, port)
# null_scan(dest, port)
# windows_scan(dest, port)

回答问题:样例程序中“conf.L3socket=L3RawSocket”的作用是什么?

设置后可以使用原始套接字进行网络通信,这里指定的是使用第三层(L3)套接字类型,在IP层构造数据包(类推发送ARP数据包则第二层)。

答:scapy不适用于本机和环回端口,这段代码使其够用来扫描本地主机。

分析:scapy在默认情况下是无法直接发送ICMP包到本机的,在Linux上需要设置conf.L3socket=L3RawSocket,采用原生套接字接口发送,否则无法捕获环回地址的包(无法直接发送ICMP包到本机),会出现问题。

在Ubuntu(Linux)操作系统内,通过添加代码段conf.L3socket=L3RawSocketscapy就可以直接发送ICMP包到本机,从而可以捕获环回的数据包。与之相对应的,在Windows操作系统下,则不需要conf.L3socket=L3RawSocket,本机就可正常捕获环回地址的数据包,因此在win下需要将这行代码注释掉。

image-20240920003021801

image-20240920003340784

结果分析

详见“【SCU期末】网络攻防技术期末重点”

一个端口扫描的结果有三种:开放、关闭、被过滤(或者是未被过滤),被过滤的结果不能够判断端口到底有没有开放,但可以判断出目标主机有防火墙拦截,所以被过滤这种结果并不是没有意义的。端口扫描的意义是区分这三种情况。

半开放连接扫描可以根据返回数据报的类型判断是开放还是关闭,通过是否返回数据报判断扫描信息是否被过滤;但FIN,Null,Xmas扫描则不同,其本质是一个开放的端口收到没有设置SYN,ACK或RST标志位的异常数据报时,不会做出反应,而如果这个端口是关闭的,他会返回一个标志位是RST的数据报,这是由TCP协议本身决定的,但这三种方法有局限性,体现在:1)不同操作系统在对待这类事件做出的反应不同 2)如果发送出去的数据报丢失,如被防火墙拦截,会被误判成端口开放的情况;ACK扫描不能决定一个端口是否开放 ,只能判断目标是否有防火墙,所以在实际中可以先使用ACK扫描检查防火墙的状态。

发现

一、代码的许多函数调用中都有参数timeout,如果设置的数值过小那么结果往往会出现差错,从而得不到想要的结果(如设置timeout=1)。所以可以设置timeout=5,使得效果更加准确。设置更大的timeout值使得数据包能有更长的时间传送而不会被提前判定超时,也就是说有更大的冗余时间量使得数据包不会因为传输时间的波动而被错误的判定为超时(本实验中指的是被错误地判定为没有回复数据包)。

二、在Linux操作系统下,需要使用conf.L3socket=L3RawSocket,这段代码来使得本机能够捕获环回地址的数据包,但是Windows系统不用。

参考资料

  1. 【nmap】常用五种扫描原理详解 -TCP SYN、完整TCP、TCP ACK、TCP FIN/Xmas/NULL、UDP_xmas tree包是什么-CSDN博客
  2. Nmap端口扫描(TCP,UDP,ACK,SYNC等)-CSDN博客
  3. Nmap扫描基础常用命令(包含进阶使用) - 我超怕的 - 博客园 (cnblogs.com)
  4. Nmap最全使用方法和原理解释(由浅入深)_nmap ping扫描-CSDN博客
  5. 浏览器–常用的搜索操作符大全–使用/实例-CSDN博客
  6. 网络扫描神器:Nmap 保姆级教程(附链接)_虚拟机怎么安装nmap-CSDN博客
  7. 浅谈端口扫描 - BuXuan - 博客园 (cnblogs.com)
  8. 端口扫描的几种方式 - Leo’s Blog (leo021017.github.io)