RidhiGupta001/Web-and-Network-Scanners
GitHub: RidhiGupta001/Web-and-Network-Scanners
基于 Python 的轻量级安全扫描工具集,包含网络侦察扫描器和 Web 应用漏洞扫描器,用于快速识别目标系统的开放服务、软件版本及常见 Web 漏洞。
Stars: 0 | Forks: 0
# 代码分析与文档报告
## 网络与 Web 安全测试工具
## 引言
现代系统时刻暴露在安全风险之中——从配置错误的服务器、过时的软件,到可被利用的 Web 漏洞(如 SQL 注入和跨站脚本攻击 (XSS))。
挑战不仅在于这些漏洞的存在,更在于它们在被利用之前通常**未被检测到**。许多系统缺乏对以下方面的持续可见性:
- 开放的网络攻击面(端口、服务、版本)
- 脆弱或过时的配置
- 可能导致系统被完全攻陷的常见 Web 漏洞
传统的安全工具通常:
- 配置复杂
- 对于快速分析而言过于笨重
- 难以针对特定用例进行自定义
本文档提供了两个用于网络侦察和 Web 漏洞评估的 Python 安全工具的技术演练。
这两个工具都实现了用于安全评估的行业标准实践,并展示了网络映射和漏洞检测的合法方法。
## 工具 1:网络侦察扫描器
### 目的与概述
该网络扫描器旨在对目标系统执行全面的网络侦察。它回答了三个基本问题:
1. **什么在监听?** - 哪些端口处于开放状态并接受连接?
2. **什么在运行?** - 这些端口上运行着哪些服务和软件版本?
3. **什么操作系统?** - 目标运行的是什么操作系统?
这是任何安全评估的基础——在评估其安全状况之前,您需要了解您面对的是什么。
### 核心架构
扫描器分三个相连的阶段工作,每个阶段都建立在前一个阶段的基础之上:
```
Input (Target IP + Port Range)
↓
Stage 1: Port Enumeration
↓
Stage 2: Banner Extraction
↓
Stage 3: Service Fingerprinting
↓
Output (Complete inventory)
```
### 阶段 1:TCP 端口枚举
#### 端口扫描的工作原理
脚本遍历指定的端口范围,并尝试与每个端口建立 TCP 连接:
```
def port_scan(target, start_port, end_port):
open_ports = []
for port in range(start_port, end_port + 1):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex((target, port))
if result == 0:
print(f"[+] Port {port} is OPEN")
open_ports.append(port)
sock.close()
except Exception as e:
pass
return open_ports
```
#### 逐步解析
**Socket 创建:**
```
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
```
- `AF_INET` = IPv4 协议族
- `SOCK_STREAM` = TCP(面向连接、可靠的协议)
这将创建一个 TCP socket——建立连接的机制。
**超时配置:**
```
sock.settimeout(1)
```
设置 1 秒的连接尝试时间窗口。如果目标在 1 秒内没有响应,我们假设该端口未在监听并继续下一步。这可以防止扫描无限期挂起。
**连接尝试:**
```
result = sock.connect_ex((target, port))
```
`connect_ex()` 是 connect 的非阻塞版本。它返回:
- `0` = 连接成功(端口开放)
- 非零 = 连接失败(端口关闭或被过滤)
**逻辑:**
```
if result == 0:
open_ports.append(port)
```
当我们的返回值为 0 时,意味着我们成功建立了 TCP 连接。一个监听服务响应了我们的请求。我们将此端口记录为开放,并移至下一个端口。
#### 为什么这会起作用
TCP 连接遵循三次握手:
1. **SYN** - 我们向该端口发送连接请求
2. **SYN-ACK** - 如果有程序在监听,它会做出响应
3. **ACK** - 我们完成握手
如果没有服务在该端口监听,操作系统会发回一个 RST(重置)数据包或直接忽略我们。无论哪种方式,`connect_ex()` 都会返回非零值,我们就知道该端口是关闭的。
### 阶段 2:服务 Banner 提取
一旦我们知道哪些端口是开放的,我们就连接到每个端口并读取服务发回的第一批数据:
```
def banner_grab(target, port):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
sock.connect((target, port))
banner = sock.recv(1024).decode('utf-8', errors='ignore')
sock.close()
return banner.strip()
except:
return None
```
#### Banner 抓取显示了什么
不同的服务在您连接时会有不同的问候方式。这些问候信息非常具有参考价值:
**SSH 服务:**
```
SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u7
```
告诉我们:这是 SSH 版本 2.0,运行在 Debian Linux 上的 OpenSSH 7.4。
**HTTP 服务:**
```
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
```
告诉我们:运行在 Ubuntu 上的 Apache Web 服务器版本 2.4.41。
**SMTP 服务:**
```
220 mail.example.com ESMTP Postfix 3.4.8
```
告诉我们:Postfix 邮件服务器,版本 3.4.8。
#### Banner 抓取过程
```
sock.connect((target, port))
```
建立到该端口的真实 TCP 连接。与 `connect_ex()` 不同,这是阻塞式的,会进行等待。
```
banner = sock.recv(1024).decode('utf-8', errors='ignore')
```
读取最多 1024 字节的数据。大多数服务在等待客户端输入之前,会立即发送其标识字符串。`.decode('utf-8', errors='ignore')` 将字节转换为文本,忽略任何无效的 UTF-8 字符。
```
return banner.strip()
```
移除空白字符并返回干净的 Banner 字符串。
#### 为什么这很重要
软件版本信息有助于识别可能存在哪些漏洞。安全研究人员发布了按软件版本索引的 CVE(常见漏洞和暴露)数据库。了解确切的版本使安全专业人员能够检查:“该版本是否容易受到已知攻击?”
这就是为什么许多生产系统会故意隐藏或混淆其 Banner——不对外宣称正在运行的软件及其确切版本是基本的安全卫生习惯。
### 阶段 3:服务与操作系统指纹识别
最后阶段使用 Nmap 执行更复杂的分析:
```
def vulnerability_scan(target):
try:
nm = nmap.PortScanner()
nm.scan(target, arguments='-sV -O')
result = {}
if target in nm.all_hosts():
host = nm[target]
result['hostnames'] = host.hostname()
if 'osmatch' in host:
result['osmatch'] = host['osmatch']
# Extract open ports + services
vulns = []
for proto in host.all_protocols():
ports = host[proto].keys()
for port in ports:
service = host[proto][port]
vulns.append({
"port": port,
"service": service.get('name'),
"product": service.get('product'),
"version": service.get('version')
})
result['vulns'] = vulns
return result
except Exception as e:
print(f"[-] Nmap scan failed: {e}")
return None
```
#### Nmap 在此的作用
**服务检测 (`-sV`):**
```
nm.scan(target, arguments='-sV -O')
```
`-sV` 标志告诉 Nmap 执行主动的服务版本检测。它会:
- 使用特定服务的请求探测开放端口
- 将响应与已知服务的数据库进行比较
- 识别运行中的确切产品和版本
**操作系统检测 (`-O`):**
`-O` 标志执行 TCP/IP 协议栈指纹识别:
- 发送特制的数据包并分析响应
- 将响应模式与已知的操作系统特征进行比较
- 以极高的概率识别操作系统
#### 构建结果
```
for proto in host.all_protocols():
ports = host[proto].keys()
for port in ports:
service = host[proto][port]
vulns.append({
"port": port,
"service": service.get('name'),
"product": service.get('product'),
"version": service.get('version')
})
```
这会遍历所有协议(TCP、UDP 等)和所有端口,提取:
- **port** - 端口号(22, 80, 443 等)
- **service** - 服务名称 (SSH, HTTP, HTTPS)
- **product** - 软件名称
- **version** - 版本字符串(7.4, 2.4.41 等)
#### 输出结构示例
```
{
'hostnames': ['example.com'],
'osmatch': [{'name': 'Linux 4.15 - 5.6', 'accuracy': '95%'}],
'vulns': [
{'port': 22, 'service': 'ssh', 'product': 'OpenSSH', 'version': '7.4'},
{'port': 80, 'service': 'http', 'product': 'Apache httpd', 'version': '2.4.41'},
{'port': 443, 'service': 'https', 'product': 'Apache httpd', 'version': '2.4.41'},
{'port': 3306, 'service': 'mysql', 'product': 'MySQL', 'version': '5.7.30'}
]
}
```
### 主执行流程
```
def network_scan(target, start_port, end_port):
print(f"\n[+] Starting network scan for target: {target}...")
start_time = datetime.now()
open_ports = port_scan(target, start_port, end_port)
if open_ports:
print(f"\n[+] Open ports found: {open_ports}")
else:
print("\n[-] No open ports found")
# Banner grab for each open port
for port in open_ports:
banner = banner_grab(target, port)
if banner:
print(f"[+] Banner for {target}:{port} -> {banner}")
else:
print(f"[-] No banner found for {target}:{port}")
# Run Nmap for detailed info
vuln_info = vulnerability_scan(target)
if vuln_info:
print("\n[+] Nmap Scan Results:")
if 'hostnames' in vuln_info:
print(f"Hostnames: {vuln_info['hostnames']}")
if 'osmatch' in vuln_info:
print(f"Operating Systems: {vuln_info['osmatch']}")
if 'vulns' in vuln_info:
print(f"Vulnerabilities: {vuln_info['vulns']}")
end_time = datetime.now()
print(f"\n[+] Scan completed in {end_time - start_time}")
```
#### 执行顺序
1. **端口扫描** - 查找所有开放端口
2. **Banner 抓取** - 连接到每个端口并读取其问候信息
3. **服务检测** - 运行带有版本和操作系统检测的 Nmap
4. **计时** - 跟踪整个扫描花费的时间
#### 用户交互
```
if __name__ == "__main__":
target_ip = input("Enter the target IP or Hostname: ")
start_port = int(input("Enter the starting port: "))
end_port = int(input("Enter the ending port: "))
network_scan(target_ip, start_port, end_port)
```
脚本提示输入三个信息:
- **目标** - 要扫描的 IP 地址或主机名
- **起始端口** - 端口范围的开始(通常为 1)
- **结束端口** - 端口范围的结束(通常为 65535)
然后启动完整的三阶段侦察管道。
## 工具 2:Web 应用程序安全扫描器
### 目的与概述
虽然网络扫描器为您提供了网络上内容的鸟瞰图,但 Web 扫描器会放大特定 Web 应用程序并测试其是否存在常见漏洞。它旨在回答:
1. **是否存在 SQL 注入漏洞?** - 攻击者能否操纵数据库查询?
2. **是否存在 XSS 漏洞?** - 攻击者能否注入恶意脚本?
3. **安全头是否已配置?** - 应用程序是否遵循了最佳实践?
4. **是否暴露了敏感文件?** - 配置文件、备份或管理面板是否公开?
### 架构与阶段设计
```
Input (Target URL)
↓
Phase 1: Basic Site Information
↓
Phase 2: Security Headers Audit
↓
Phase 3: SQL Injection Testing
↓
Phase 4: XSS Testing
↓
Phase 5: Sensitive Files Detection
↓
Output (Summary Report)
```
每个阶段都建立在先前的侦察基础之上,以逐步测试更深层漏洞。
### 阶段 1:基准站点侦察
```
def get_site_info(url, session):
section("Basic site info")
try:
r = session.get(url, timeout=10)
info(f"Status: {r.status_code}")
info(f"Server: {r.headers.get('Server', 'hidden')}")
info(f"Powered by: {r.headers.get('X-Powered-By', 'hidden')}")
info(f"Responded in {r.elapsed.total_seconds():.2f}s")
return r
except Exception as e:
print(f"{Fore.RED}Could not connect: {e}{Style.RESET_ALL}")
sys.exit(1)
```
#### 这有什么作用
向目标 URL 发出基本的 HTTP GET 请求并提取关键信息:
**HTTP 状态码:**
```
r.status_code
```
- 200 = OK(站点正常运行)
- 404 = Not Found(未找到)
- 500 = Server Error(服务器错误)
- 403 = Forbidden(禁止访问)
**服务器标识:**
```
r.headers.get('Server', 'hidden')
```
读取 `Server` HTTP 头,通常会标识 Web 服务器软件及版本。
**技术栈:**
```
r.headers.get('X-Powered-By', 'hidden')
```
许多框架会添加 `X-Powered-By` 头,表明它们使用了 PHP、ASP.NET、Node.js 等。
**响应时间:**
```
r.elapsed.total_seconds()
```
测量完成请求所需的时间。异常缓慢的响应可能表明服务器负载过高或正在执行昂贵的操作。
#### 会话管理
```
session = requests.Session()
session.headers["User-Agent"] = "Mozilla/5.0"
```
使用会话对象而不是单独的请求有两个作用:
1. **连接重用** - HTTP keep-alive。TCP 连接在请求之间保持打开状态,从而减少了开销。
2. **一致性** - 所有请求都包含相同的头和 cookies,模拟真实的浏览器会话。
这一点很重要,因为服务器有时会根据浏览器标识做出不同的行为。
### 阶段 2:安全头验证
```
important_headers = {
"Content-Security-Policy": "blocks XSS attacks",
"X-Frame-Options": "prevents clickjacking",
"X-Content-Type-Options": "stops MIME sniffing",
"Strict-Transport-Security": "forces HTTPS",
"Referrer-Policy": "controls referrer info",
}
def check_headers(response):
section("Security headers")
missing = []
for header, what_it_does in important_headers.items():
if header in response.headers:
good(header)
else:
warn(f"Missing: {header} ({what_it_does})")
missing.append(header)
return missing
```
#### 了解每个头
**Content-Security-Policy (CSP):**
```
Content-Security-Policy: script-src 'self' https://trusted.com
```
告诉浏览器:“只执行来自我自己的域或 https://trusted.com 的 JavaScript。不要运行任何内联脚本。”这是防御 XSS 攻击的主要手段。
**X-Frame-Options:**
```
X-Frame-Options: DENY
```
防止页面被嵌入到 `
标签:Banner抓取, CTI, Python, Scrypt密钥派生, TCP枚举, Web安全, XSS, 安全测试, 密码管理, 开源安全工具, 插件系统, 攻击性安全, 数据统计, 无后门, 服务器安全, 服务指纹识别, 漏洞情报, 端口扫描, 系统指纹识别, 网络安全, 网络扫描仪, 自动化分析, 蓝队分析, 跨站脚本, 逆向工具, 逆向工程平台, 隐私保护