一、什么是扫描
扫描相当于更深层次的信息收集,通过发送数据包获得的响应来获取更详细的信息

(1) 扫描的目标
- 找到开放的端口
- 可能存在漏洞的服务
(2) 常见端口 - 80/TCP : HTTP - 超文本传输协议,标准网页浏览服务
- 443/TCP : HTTPS - 安全的HTTP,使用SSL/TLS加密。现代网站的主流端口
- 8080/TCP, 8443/TCP : 常用于HTTP/HTTPS的备用端口或代理服务器
- 21/TCP : FTP - 文件传输协议(控制),用于上传下载文件,通常口令明文传输
- 22/TCP : SSH - 安全外壳协议,用于加密的远程登录和管理,安全性高
- 23/TCP : Telnet - 远程登录协议,口令和数据明文传输,极不安全,现已很少用
- 69/UDP : TFTP - 简单文件传输协议,无需认证,常用于网络设备固件更新
- 25/TCP : SMTP - 简单邮件传输协议,用于发送邮件
- 110/TCP : POP3 - 邮局协议第3版,用于从服务器下载邮件到本地
- 143/TCP : IMAP - 互联网消息访问协议,用于在服务器上管理邮件
- 465/TCP, 587/TCP : SMTPS - 安全的SMTP,用于加密的邮件发送
- 993/TCP, 995/TCP: 分别是安全的IMAPS和安全的POP3S
- 1433/TCP : Microsoft SQL Server 默认端口
- 1521/TCP : Oracle Database 默认监听端口
- 3306/TCP : MySQL / MariaDB 数据库默认端口
- 5432/TCP : PostgreSQL 数据库默认端口
- 27017/TCP : MongoDB 数据库默认端口
- 6379/TCP : Redis 内存数据库默认端口
- 3389/TCP : RDP - 远程桌面协议,用于远程连接Windows计算机
- 5900+/TCP : VNC - 虚拟网络计算机,跨平台的远程桌面协议,端口从5900开始
- 5800+/TCP: VNC over HTTP的端口
- 135/TCP: Microsoft RPC端点映射器,许多Windows服务的基石
- 139/TCP, 445/TCP : NetBIOS / SMB - 用于Windows文件共享、打印机共享和域服务
- 389/TCP, 636/TCP : LDAP / LDAPS - 轻量级目录访问协议,用于查询和修改目录服务
- 88/TCP : Kerberos 身份认证协议
- 53/TCP/UDP : DNS - 域名系统,将域名解析为IP地址。TCP用于区域传输,UDP用于普通查询
- 67/UDP, 68/UDP : DHCP - 动态主机配置协议,自动分配IP地址
- 161/UDP, 162/UDP : SNMP - 简单网络管理协议,用于管理和监控网络设备
- 123/UDP : NTP - 网络时间协议,用于时间同步。可被用于DDoS反射攻击
- 514/UDP : Syslog - 系统日志协议,用于集中收集日志
二、TCP&UDP
(1)TCP的优缺点
传输控制协议(TCP)是一种基于主机与主机连接的协议,因此在传输数据之前需要建立连接。协议必须能够创建、维护和关闭连接。一旦源传输数据包,目标设备必须在发送其他数据包之前确认接收。
TCP协议采用深入的错误核查方法,以提供流量和拥塞控制。字节流有助于维持序列顺序,而数据排序的使用则可让您在下一个数据包发送前重新传输丢失的数据包。
较长的头长度以及错误检查和确认要求,使得TCP比UDP更重一些。好处在于它意味着可靠、安全的通信。它绝不会将你的数据发送到错误的目的地,也不会让你的连接保持畅通。
(2)UDP优缺点
用户数据报协议(UDP)是一种基于通信的协议,采用过程对处理,因此不依赖连接协议,也不需要数据包识别。该协议可在目标设备同意之前发送数据包,并且可以继续以后相互发送,而无需确认交付。它不依赖于开路、维护或关闭连接,且不需要错误核对。UDP仅执行基本的校验,以进行错误核对。
UDP 的开销显著降低,头长固定,比 TCP 更快、更高效。其轻量级变速箱非常适合在传输速度优于精度的情况下。承受数据包丢失也具有密集的带宽,并易于支持广播和多播传输。
(3) TCP 3 次握手 4 次挥手


三、Metasploitable靶机
下载链接:https://www.rapid7.com/products/metasploit/metasploitable/?LS=1631875&CS=web
导入至虚拟机后启动

用户:msfadmin
密码:msfadmin
当前 IP 地址为:10.0.2.3
测试联通性

四、网络发现
netdiscover -r [扫描的网段]

五、Nmap 使用教程
(1) 扫描指定地址
nmap + [IP地址]
可以直接查看开放的端口、运行状态、端口运行的服务

(2) 扫描网段
nmap 10.0.2.1-255
罗列出同一网段所有设备的端口信息

255 个 IP,4 个存活

(3) TCP SYN 半开放扫描
判断端口是否开放或监听,如果端口受到某些过滤或防火墙保护,就可能发生过滤现象
nmap -sS [IP地址]

因为没有建立连接,所以该方法扫描速度快,不会在目标日志中留下记录
注:必须在 root 权限下
(4)TCP Connect 扫描
nmap -sT [IP地址]
使用操作系统完整的 connect() 系统调用建立连接。不需要 root 权限,但速度慢,且会在目标日志中留下记录

(5) UDP 扫描
扫描速度非常慢,但是可能会发现被忽视的端口、服务
nmap -sU [IP地址]

(6) 检测操作系统
nmap -O [IP地址]

(7) 检测软件版本
检测服务软件版本
nmap -sV [IP地址]

扫描强度可以设置为 0~9 ,默认状态为 7
sudo nmap -sV --version-intensity 9 [IP地址]

(8) 全面扫描
-A 选项实际上是以下多个选项的快捷方式:
-
-O:操作系统检测(如前所述)。
-
-sV:服务版本检测(尝试确定端口上运行的服务及其版本号)。
-
--traceroute:路由追踪(显示到达目标经过的跳数,即中间节点)。
-
-sC :使用默认的Nmap脚本进行脚本扫描(相当于
--script=default)。nmap -A [IP地址]

(8) 主机发现
不扫描端口,仅判断是否存活
nmap -sn 10.0.2.1-255

(9) 指定端口或范围
nmap -p [端口] [IP地址]


(10) 快速扫描
仅扫描 100 个端口,速度快
nmap -F [IP地址]

(11) 保存扫描信息
通过 >> 将信息保存至指定文件
nmap -sS [IP地址] >> outputofscan.txt

nmap -oN [文件名] [指令] [IP地址]
将结果按照正常格式输出至指定文件

六、什么是防火墙&IDS
(1) 防火墙
监控网络流量的安全系统,依据设定好的规则对流量进行访问控制
- 网络防火墙:过滤两个或多个网络之间的流量
- 主机防火墙:过滤传入或传出特定计算机的流量
(2) IDS
入侵检测系统,主要监控网络中的恶意活动
注:一些主要端口可能在防火墙后面,导致我们的扫描数据包被丢弃,从而无法探测出隐藏的端口

七、绕过防火墙检测
(1) 分片扫描
将扫描数据包分成更小的片段,从而试图规避某些防火墙和IDS的检测
nmap -f [IP地址]
Nmap 默认将 TCP 头分成 8字节 的片段,两个就是 16 字节 的片段
nmap -f -f [IP地址]
类似的 --mtu 命令,可以指定片段大小
nmap --mtu [片段大小] [IP地址]
(2) 诱饵扫描
同时从多个虚假的 IP 地址发送扫描数据包,从而隐藏真实的扫描源地址
nmap -D RND:[指定伪造的IP数量] [IP地址]

大量伪造的 IP同时发送数据包进行混淆,但是 Nmap 只监听正确 IP 返回的信息
局域网内,可以探测当前网络的存活主机 IP,使用他们来伪装我们自己的 IP 地址
nmap -D [IP],[IP],[IP],ME [目标IP]


八、端口扫描器
python
import socket
import sys
# sys 导入系统相关的功能,通常用于访问命令行参数、退出程序等
from queue import Queue
# 导入线程安全的队列数据结构,用于在多线程/协程间安全地传递数据
from gevent import monkey;monkey.patch_socket()
# gevent是一个基于协程的Python网络库
# monkey模块提供了"猴子补丁"功能
# monkey.patch_socket()将标准库的socket模块替换为gevent的异步版本
# 效果:使普通的同步socket代码变成异步非阻塞的,无需修改原有代码
import gevent
# 导入gevent主模块,用于创建和管理协程
import argparse
# socket套接字基本格式
# socket.socket(family.type)
print('''
____ _ ____
| _ \ ___ _ __| |_/ ___| ___ __ _ _ __
| |_) / _ \| '__| __\___ \ / __/ _` | '_ \
| __/ (_) | | | |_ ___) | (_| (_| | | | |
|_| \___/|_| \__|____/ \___\__,_|_| |_|
''')
#定义生成扫描列表的函数
def make_port_list(ports):
#接收的列表
new_port_list = []
# 判断并处理传入的ports的值,判断间隔为 "," or "-"
# 情况一:22,80,443
if "," in ports:
#以","为分隔符生成列表
temp_list = ports.split(",")
#在temp_list列表中循环遍历
for port in temp_list:
#判断是否有"-"范围类参数在列表内
if "-" in port:
#根据传入的值从首位遍历值末位
for p in range(int(port.split("-")[0]),int(port.split("-")[1]) + 1):
new_port_list.append(p)
# 如果在"-"则代表传入的为1-100格式
# 否则就是20,22,23,80这种格式,直接传入遍历的值即可
#^_^ 连续的话必须现有一个正常扫描的,这样 22,23-999
#懒得改了
else:
new_port_list.append(port)
# 情况二:1-100
elif "-" in ports:
# 从第一个数通过 +1 一直遍历至最后一个数
for p in range(int(port.split("-")[0]),int(port.split("-")[1]) + 1):
new_port_list.append(p)
# 情况三:使用者输入的内容为单一端口
else:
new_port_list.append(ports)
# 返回端口列表的值
return new_port_list
# 定义多协程函数
def coroutines(batch_size=None):
#开启多协程
cos = []
#空列表cos用于存储所有的协程对象
# 如果指定了batch_size,就使用它,否则使用队列中的所有任务
if batch_size is None:
num = ip_port.qsize()
else:
num = min(batch_size, ip_port.qsize())
# 确保不超过队列中剩余的任务数
# ip_port.qsize():获取队列 ip_port 中的任务数量
# num:保存任务总数
# print(num):打印任务数量,用于调试
for i in range(num):
# 循环任务数量,为每个任务创建协程
# 调用工作函数,
cor = gevent.spawn(star_scan)
# gevent.spawn()函数用于创建一个新的协程,并调用star_scan函数
# spawn方法不会立即执行函数,而是创建协程对象
# 将返回的协程对象保存至变量cor
cos.append(cor)
#将cor中的协程对象添加至cor列表中
gevent.joinall(cos)
#等待列表中的所有协程执行完毕
#定义一个开始扫描的函数
def star_scan():
#动态任务分配
sockets = ip_port.get()
ip = sockets[0]
port = int(sockets[1])
#异常处理
try:
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 创建一个使用tcp的套接字
s.settimeout(2.0) #设置超时时间
s.connect((ip,port))
except Exception as e:
# print(e) #防止超时提醒过多
pass
else:
#避免因未接收到返回数据而报错误判,所以注释掉了
# res = s.recv(3096).decode('utf-8').encode()
# print(res)
print("[+]{}:{} \topen".format(ip,port))
finally:
s.close()
# 命令行传入函数
def arguments():
# 创建对象
parser = argparse.ArgumentParser(description='基于TCP连接的简易端口扫描工具')
# 保存定义的命令行参数信息
parser.add_argument('IP', type=str, help='待扫描IP地址')
parser.add_argument('Port', type=str, help='指定端口')
'''
add_argument方法:用于添加命令行参数
'input'指定的 name:指定命令行参数的名称
type:指定参数的类型
help:用于描述该参数的作用
'''
# 如果参数是可选参数,使用 - -- 前缀来定义
# parser.add_argument('-P', '--Port', action='store_true', help='待扫描端口' \
# '[20,21,22] or [1-999]')
'''
--output 为可选参数,类型为字符串
-v 和 --verbose 是同一个可选参数的两种类型,类型为布尔值
如果用户指定了该参数时,值为 True ,否则为 False
action='store_true' 表示当指定这个参数时,将其值设置为 True
'''
args = parser.parse_args()
# parse_args():解析命令行参数,返回命名空间
IP = args.IP
Port = args.Port
return(IP,Port)
IP,Port = arguments()
ip_port = Queue()
#创建队列
ip = IP
port = Port
# 将make_port_list返回的值传入port_list
port_list = make_port_list(port)
print("total port num:{}".format(len(port_list)))
for port in port_list:
ip_port.put([ip,port])
coroutines()
#开启协程
#将协程设置为每50个创建一次
num = 50
if len(port_list)%num == 0:
#如果port_list中的数量能被50整除
turn = int(len(port_list)/num)
#计算需要多少批次
for i in range(turn):
coroutines(num)
#每批处理50个端口
else:
turn = int(len(port_list)/num)+1
# 因为不能被整除,所以 批次 = 整数部分 + 1
for i in range(turn):
if i == turn-1:
#如果是最后一批
coroutines(len(port_list)%num)
#取余,处理剩余端口
else:
coroutines(num)
#正常处理50个端口

注:端口连续的话必须,先有一个正常扫描的,这样 22,23-999,懒得改了