利用socket端口扫描
socket原理
Python的socket库是操作系统底层Socket API的封装,直接使用传输层协议(TCP/UDP)。当您调用s.connect()时,实际发生了以下TCP协议交互:1.发送SYN包到目标端口2.若收到SYN+ACK → 端口开放 → 完成握手(发送ACK)3.若超时无响应 → 端口被过滤。
所以这是标准的TCP全连接扫描(非半开扫描),完全依赖操作系统的TCP协议栈实现。
线程教学视频
https://www.bilibili.com/video/BV1wb4y1S7d6/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=35e4182ce0db72b58a7c3806ee59a0d5
代码
import socket
#端口扫描
def socket_port(ip):
for port in range(78,100):
try:
s=socket.socket()
s.connect((ip,port))
print(f"端口:{port}可用")
s.close()
except:
print(f"这个端口{port}不可用")
if __name__ == '__main__':
socket_port('10.105.66.16')
优化
import socket
import concurrent.futures
# 检查单个端口是否开放
def check_port(ip, port, timeout=0.5):
try:
s = socket.socket()
s.settimeout(timeout)
s.connect((ip, port)) # 尝试连接
s.close()
return True # 连接成功
except:
return False # 连接失败
def socket_port(ip, start=78, end=100):
# 创建线程池(最多同时扫描10个端口)
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
# 准备存储任务和端口号的列表
task_list = []
port_list = []
# 为每个端口创建扫描任务
for port in range(start, end + 1):
# 提交扫描任务到线程池
task = executor.submit(check_port, ip, port) #执行这个函数给到线程池中
# 保存任务对象和对应的端口号
task_list.append(task) #task_list.append(task) 则是把这些 task 对象收集起来,方便后续统一处理结果
port_list.append(port)
# 处理完成的任务
for i in range(len(task_list)):
# 等待任务完成(按提交顺序)
task = task_list[i]
port = port_list[i]
# 获取扫描结果
is_open = task.result() #这个返回就是heck_port的函数分return结果
# 打印结果
if is_open:
print(f"端口 {port} ✅ 开放")
# else:
# print(f"端口 {port} ❌ 关闭或过滤")
if __name__ == '__main__':
socket_port('10.105.66.16', start=1, end=65536) # 只扫描3个端口作为示例
print("扫描结束")
import socket
import concurrent.futures
def check_port(ip, port, timeout=0.5):
try:
with socket.socket() as s:
s.settimeout(timeout)
s.connect((ip, port))
return port, True
except:
return port, False
def socket_port(ip, start=78, end=100, max_workers=50):
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(check_port, ip, port): port for port in range(start, end+1)} # 这里用字典推导式,将executor.submit返回的对象于port绑定在一起组成一个futures字典
for future in concurrent.futures.as_completed(futures): # 要求他们不用按照顺序执行,谁先执行谁就来这里循环
port, status = future.result()
if status:
print(f"端口 {port}")
if __name__ == '__main__':
socket_port('10.105.66.16', start=1, end=65536)
借助天欣大佬的视频
【快速入门python安全开发】 https://www.bilibili.com/video/BV1jBD9Y5Euv/?p=6&share_source=copy_web&vd_source=7ff27bdc142f051d6aec8c3424b47cb8
前提条件
1.安装nmap库
pip install python3-nmap
2.nmap 环境变量
原理学习
有时候防火墙会限制某种协议的扫描,要想解决这种问题,就需要换不同的协议去测试
扫描类型/参数 |
命令 |
原理与特性 |
示例 |
使用场景与注意事项 |
TCP SYN扫描 |
nmap -sS <目标> |
半开放扫描 :发送SYN包,若收到SYN/ACK则端口开放(立即发送RST终止连接)。隐蔽性强,不触发完整连接日志。需Root权限。 |
nmap -sS 192.168.1.1 |
快速探测开放端口,绕过基础日志记录。适用于Linux/Unix系统(需管理员权限)。 |
TCP Connect扫描 |
nmap -sT <目标> |
全连接扫描 :完成三次握手后断开。依赖系统 connect() 函数,无权限要求,但易被日志记录。 |
nmap -sT 10.0.0.5 -p 80,443 |
无Root权限时使用,兼容性好。速度较慢且不够隐蔽,可能触发安全警报。 |
TCP ACK扫描 |
nmap -sA <目标> |
防火墙探测 :发送ACK包,若收到RST说明端口未被过滤;无响应可能被防火墙拦截。不检测端口状态。 |
nmap -sA 203.0.113.0 -p 22 |
探测防火墙规则,识别过滤端口。需结合其他扫描确定实际开放状态。 |
TCP FIN扫描 |
nmap -sF <目标> |
隐蔽扫描 :发送FIN包,关闭的端口返回RST,开放的端口无响应(违反RFC 793)。绕过无状态防火墙/IDS。 |
nmap -sF 192.168.1.100 -T2 |
隐蔽探测Linux/Unix系统端口。对Windows无效(默认不遵循RFC响应)。 |
TCP Xmas扫描 |
nmap -sX <目标> |
畸形包扫描 :发送FIN+PSH+URG标志位的包(类似圣诞灯饰)。响应逻辑同FIN扫描。 |
nmap -sX 10.0.0.10 --top-ports 50 |
绕过简单防火墙,测试系统协议栈兼容性。对Windows通常无效。 |
TCP NULL扫描 |
nmap -sN <目标> |
空标志位扫描 :发送无任何标志位的包,依赖目标系统RFC合规性。开放的端口无响应,关闭的端口返回RST。 |
nmap -sN 192.168.1.200 |
隐蔽性高,适用于Linux/Unix环境。需多次验证结果准确性。 |
UDP扫描 |
nmap -sU <目标> |
无连接探测 :发送UDP包,若收到ICMP不可达则端口关闭;无响应可能开放(需二次验证)。速度极慢。 |
nmap -sU -p 53,123,161 192.168.1.1 |
检测DNS、NTP、SNMP等UDP服务。建议限定端口范围,结合 --max-retries 1 加速。 |
服务版本探测 |
nmap -sV <目标> |
协议指纹匹配 :向开放端口发送探针,匹配响应特征与 nmap-service-probes 数据库,识别服务名称及版本。 |
nmap -sV 192.168.1.1 -p 80,443 |
漏洞利用前的情报收集。可与 -A 组合使用,获取详细服务信息。 |
操作系统检测 |
nmap -O <目标> |
协议栈指纹分析 :通过TTL、窗口大小、序列号生成模式等特征,匹配已知操作系统指纹库。 |
nmap -O --osscan-limit 192.168.1.1 |
识别目标操作系统类型。需至少一个开放和一个关闭的端口提高准确性。 |
综合扫描 |
nmap -A <目标> |
全面探测 :启用OS检测(-O)、版本探测(-sV)、脚本扫描(-sC)及Traceroute。 |
nmap -A -T4 scanme.nmap.org |
渗透测试初期信息收集,获取目标完整画像。资源消耗较高,可能触发安全机制。 |
跳过主机发现 |
nmap -Pn <目标> |
强制扫描 :跳过Ping检测(主机发现),假设所有目标在线,直接进行端口扫描。 |
nmap -Pn 192.168.1.1 |
目标屏蔽ICMP请求时使用(如防火墙过滤Ping),避免Nmap误判主机离线。扫描时间可能增加。 |
空闲扫描 |
nmap -sI <僵尸机> <目标> |
隐蔽源扫描 :利用第三方“僵尸主机”反射流量,隐藏扫描者真实IP。需僵尸机满足空闲且IPID递增条件。 |
nmap -sI 192.168.1.50 10.0.0.0/24 |
高度隐蔽的扫描,绕过IP追踪。需提前验证僵尸机可用性。 |
窗口扫描 |
nmap -sW <目标> |
TCP窗口扫描 :分析返回的RST包中TCP窗口大小,某些系统开放端口与关闭端口的窗口值不同。 |
nmap -sW 192.168.1.1 -p 1-1000 |
替代SYN扫描,绕过某些IDS检测。准确度依赖目标系统实现,适用范围有限。 |
脚本流程图
脚本代码-初代
import nmap3 #引入 nmap3 的库
from openpyxl import Workbook
import json
import time
def scan(ip,default,args): #对一个IP进行端口扫描
scaner = nmap3.Nmap() #对应的类
port_data=scaner.scan_top_ports(ip,default,args) #输入参数 进行扫描 args 可以传别的参数
return ip,port_data #这里返回的值如果用 ,分开 返回的结果是元组
def write_to_excel_sheet(ip,data,ws):#对上面函数输出的结果,进行数据处理,导入到xlsx文件中
try:
# 探测的ip
scaned_ip=ip
# print(ip,data)
ip_datas=data[ip].get('ports',"") # 获取返回结果的 字典中 key为IP,vlau值所有列表ports
if ip_datas:
for ip_data in ip_datas:
# 端口协议
port_col=ip_data.get('protocol','') #获取 上面列表 ports里面的 protocol对应的值 端口协议
# 端口号
port_id=ip_data.get('portid','') #同上
# 端口服务
port_service=ip_data.get('service','').get('name','') #同上
ws.append([scaned_ip,port_id,port_col,port_service]) #写入到 xlsx文件中
except PermissionError:
print("文件可能处于打开状态,请关闭文件") #报错处理
def read_from_txt(filename): #读取txt文件的内容,将文件IP内容返回成列表
try:
with open(filename,'r') as f:
return [i.strip() for i in f.readlines() if i.strip()] #这个就是去除文件中多以空行和空格,并将txt文件的内容返回成 一个列表
except FileNotFoundError:
print("文件不存在,请检查文件名")
if __name__ == '__main__':
start=time.time()
ips = read_from_txt('ips.txt')#利用上面的函数将 txt文件的IP地址提取出来成一个列表
wb = Workbook()
ws = wb.active
ws.append(["IP", "开放端口", "端口协议", "端口服务"])#先输入 数据处理的文件头信息
for ip in ips: #利用for循环,将ips的列表的信息一个一个给到ip
data=scan(ip,100,args='') # 利用上面给到的ip 进行基本的端口扫描工作
write_to_excel_sheet(data[0],data[1],ws)
'''
#"scan(ip,100,args='')"这个返回的是元组,所以采用“data[0],data[1]”这种方式传参,“write_to_excel_sheet”这个函数就是进行数据处理的
'''
wb.save(f'端口扫描脚本初步.xlsx')#保存
print("保存成功")
end=time.time()
cost=end-start
print(f"扫描完成,耗时{cost:.2f}秒")
import json
import time
from openpyxl import Workbook
import nmap3
def scan_task(taskIP,top=100,args=''):
nmap = nmap3.Nmap()
results = nmap.scan_top_ports(taskIP, default=top, args=args)
# print(json.dumps(results, indent=2))
return results
def get_sheet_wb(detail):#判断是否是详细扫描还是简单扫描
workbook = Workbook()
sheet= workbook.active
sheet.title="端口扫描结果"# 这个的话 其实后期可以添加别的工具自动扫描
if detail: #不为空 就说明是详细,xlsx就是下面的几个数据表头
sheet.append(["目标IP", "开放端口", "端口服务", "端口协议", "详细信息", "服务版本", "服务释义", "系统类型"])
else: #为空 就说明不是详细的,xlsx就是下面的几个数据表头
sheet.append(["目标IP", "开放端口", "端口服务", "端口协议"])
return sheet,workbook #返回一个原则 sheet 是返回的表头内容,workbook返回的是一个表格的状态
def read_file(file_name):
try:
with open(file_name,'r') as f:
return [line.strip() for line in f.readlines() if line.strip()] # 读取文件中的IP地址列表
except FileNotFoundError:
print(f"错误:文件{file_name}未找到")
return False
except Exception as e:
print(f"读取文件时候发生错误:{e}")
return False
def write_fails(ip_failed):#将错误的内容输入到这个文件中
with open('failed_ips.txt','w') as f:
for ip in ips_failed:
f.write(ip+'n')
def save_results_to_excel(scan_results,sheet): #将扫描的结果,给到这个函数进行数据的处理
if not isinstance(scan_results, dict): #看是不是返回的结果是不是 字典
return False
for taskIP, IP_results in scan_results.items():#通过键值对的方式,字典格式 key被taskIP接收,value被IP_results接收
if taskIP=='runtime': #这个我猜的是如果没有正常返回,就会先循环这个runtime 这个字段
break
default_OS=""
# 填写扫描结果
if IP_results:
if IP_results['ports']:
for port_info in IP_results['ports']:
if port_info['state'] == 'open':
# print(port_info)
if not default_OS and port_info.get('service','').get("ostype",''):
default_OS = port_info['service'].get("ostype")
result = [taskIP,
port_info['portid'],
port_info.get('service','').get("name",""),
port_info['protocol']]
if detail:
result.extend([port_info.get('service','').get("product",""),
port_info.get('service','').get("version",""),
port_info.get('service','').get("extrainfo",""),
port_info.get('service','').get("ostype",default_OS)])
sheet.append(result)
return True
if __name__ == "__main__":
output_file="open_ports_results.xlsx"
args = '-T4 -Pn -sV'
detail ='-sV' in args or '-A' in args#这个就是说,扫描的参数如果有这两个参数,就说明是详细扫描
file_name=input("请输入文件名:")
port_numb=input("请输入你想扫描多少常见端口,-p-为全端口")
scan_port_numb=int(port_numb)
ips_list=read_file(file_name)#调用函数将txt文件写入到ips_list
ips_failed=[]# 创建一个ip列表中,用于保存由于特殊原因未扫描成功的(可能不在线)
sheet,workbook=get_sheet_wb(detail) #看是否详细扫描,
if ips_list:
print("开始扫描...")
for ip in ips_list:
try:
scan_results = scan_task(ip, scan_port_numb, args)
# print(scan_results)
finall = save_results_to_excel(scan_results, sheet) # ?
except Exception as e:
print(f"这个{ip}有问题:{e}")
ips_failed.append(ip)#将错误ip保存到这个列表中
print(f"这个{ip}探测完毕")
workbook.save(output_file)
if ips_failed:
write_fails(ips_failed)
print(f"扫描失败的IP写入 failed_ips.txt文件")
原文始发于微信公众号(嵩艺):端口扫描工具开发
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论