### NSE 脚本原理

1. NSE 脚本的运行机制

NSE 的核心是一个脚本解释器，它运行用 Lua 语言编写的脚本。Nmap 会在扫描过程中加载并执行这些脚本，以扩展其核心功能。整个运行机制可以概括为以下几个步骤：

1. 脚本加载：Nmap 在启动时，会根据你的命令行参数（如 `-sC` 或 `--script <脚本名>`），加载相应的 NSE 脚本。这些脚本文件通常位于 Nmap 的安装目录下的 `scripts` 文件夹中
2. 事件触发：NSE 脚本不会无缘无故地运行。它依赖于一系列的事件触发器（Triggers），这些触发器会在 Nmap 的不同扫描阶段被激活
   - `pre-scan`：在任何主机扫描开始之前运行。通常用于一些全局性任务，如收集 DNS 信息
   - `host-scan`：在扫描每个主机时运行。通常用于对单个主机进行枚举或漏洞检测
   - `port-scan`：在扫描每个端口时运行。这是最常用的触发器，用于针对特定端口的服务进行探测，如 HTTP、FTP、SSH 等
   - `post-scan`：在所有主机扫描完成后运行。通常用于汇总结果或生成报告
3. 脚本执行：当一个事件被触发时，Nmap 会调用相应脚本中的`action()` 函数。这个函数包含了脚本要执行的核心逻辑
4. 结果返回：`action()` 函数执行完毕后，会将结果返回给 Nmap。Nmap 会将这些结果以标准的格式（如 XML、文本等）显示给用户

2. 编写 NSE 脚本的核心结构

一个典型的 NSE 脚本由以下几个关键部分组成：

1. 脚本描述（`description`）：一个简短的字符串，描述脚本的功能
2. 分类（`categories`）：脚本的分类，如 `safe`（安全）、`vuln`（漏洞）、`auth`（认证）等。这些分类使得用户可以通过 `-sC` 或 `--script=safe` 等参数来批量运行某一类脚本
3. 依赖关系（`dependencies`）：如果脚本依赖于其他脚本，可以在这里声明
4. 触发器（`hostrule`、`portrule` 等）：指定脚本在什么条件下运行。例如，`portrule` 规定了脚本只在发现某个特定端口开放时才运行
   - `portrule = "tcp or udp"`：在所有 TCP 或 UDP 端口上运行
   - `portrule = "port:80"`：只在 80 端口上运行
   - `hostrule`：在整个主机上运行，不依赖于特定端口
5. 主函数（`action()`）：这是脚本的核心代码，包含了所有业务逻辑。在这个函数中，你可以使用 Nmap 提供的各种库函数（如 `http.get`、`nmap.set_port_state` 等），来完成网络交互和数据处理