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 ``` 防止页面被嵌入到 `