Skip to main content
JavaScript 协议被添加到 Nuclei v3 中,允许你用 JavaScript 编写检查和检测漏洞,并弥合网络协议之间的差距。
  • 内部使用 JavaScript 协议编写的任何内容都在 Golang 中执行。
  • JavaScript 协议旨在适配或导入 Nuclei 生态系统之外的任何现有 JavaScript 库或框架。
  • Nuclei 提供了一套专为编写漏洞利用和检查而量身定制的函数、库,只添加必要的功能来补充现有的基于 YAML 的 DSL。
  • JavaScript 协议旨在用作通用 JavaScript 运行时,也不会替代 Nuclei 的 matchers、extractors 或任何现有功能。
  • Nuclei v3.0.0 附带了15+ 库(ssh、ftp、RDP、Kerberos 和 Redis),专为在 JavaScript 中编写漏洞利用和检查而定制,未来将不断扩展。

简单示例

以下是 JavaScript 协议模板的基本示例:
id: ssh-server-fingerprint

info:
  name: Fingerprint SSH Server Software
  author: Ice3man543,tarunKoyalwar
  severity: info
  

javascript:
  - code: |
      var m = require("nuclei/ssh");
      var c = m.SSHClient();
      var response = c.ConnectSSHInfoMode(Host, Port);
      to_json(response);
    args:
      Host: "{{Host}}"
      Port: "22"

    extractors:
      - type: json
        json:
          - '.ServerID.Raw'
在上面的 Nuclei 模板示例中,我们通过以非认证模式连接并提取服务器横幅来识别 SSH 服务器软件。让我们分解一下这个模板。

代码部分

code: 包含在运行时由 Nuclei 执行的实际 JavaScript 代码。在上面的模板中,我们:
  • 导入 nuclei/ssh 模块/库
  • 创建 SSHClient 对象的新实例
  • Info 模式连接到 SSH 服务器
  • 将响应转换为 json

参数部分

args: 部分可以简单理解为在运行时传递的 JavaScript 变量,支持 DSL 使用。

输出部分

最后一个表达式的值作为 JavaScript 协议模板的输出返回,可以在 matchers 和 extractors 中使用。如果服务器返回错误,则在 matcher 或 extractor 中会暴露带有错误消息的 error 变量。

SSH 暴力破解示例

SSH 密码暴力破解模板
id: ssh-brute

info:
  name: SSH Credential Stuffing
  author: tarunKoyalwar
  severity: critical
  

javascript:
  - pre-condition: |
      var m = require("nuclei/ssh");
      var c = m.SSHClient();
      var response = c.ConnectSSHInfoMode(Host, Port);
      // 只有当 ssh 服务器允许基于密码的认证时才进行暴力破解
      response["UserAuth"].includes("password")

    code: |
      var m = require("nuclei/ssh");
      var c = m.SSHClient();
      c.Connect(Host,Port,Username,Password);

    args:
      Host: "{{Host}}"
      Port: "22"
      Username: "{{usernames}}"
      Password: "{{passwords}}"

    threads: 10
    attack: clusterbomb
    payloads:
      usernames: helpers/wordlists/wp-users.txt
      passwords: helpers/wordlists/wp-passwords.txt

    stop-at-first-match: true
    matchers:
      - type: dsl
        dsl:
          - "response == true"
          - "success == true"
        condition: and
在上面的示例模板中,我们使用用户名和密码列表对 ssh 服务器进行暴力破解。我们可以看出,这可能无法通过网络模板实现。让我们分解一下这个模板。

前置条件

pre-condition 是在运行 “code” 之前执行的可选 JavaScript 代码部分,它作为漏洞利用的前提条件。在上面的模板中,在尝试暴力破解之前,我们检查:
  • 该地址确实是 SSH 服务器。
  • ssh 服务器配置为允许基于密码的认证。
进一步解释
  • 如果 pre-condition 返回 true,则只执行 code;否则,跳过。
  • 在代码部分,我们导入 nuclei/ssh 模块并创建 SSHClient 对象的新实例。
  • 然后我们尝试使用用户名和密码连接到 ssh 服务器。 该模板使用 payloads 启动具有 10 个线程的 clusterbomb 攻击,并在首次匹配时退出。
现在看这个模板,我们可以看出 JavaScript 模板在编写多步骤和协议/供应商特定的漏洞利用方面非常强大,这是 JavaScript 协议的主要目标。

初始化

init 是一个可选的 JavaScript 部分,可用于初始化模板,它在编译模板后、在任何目标上运行之前执行。虽然很少需要,但它可以用于在针对任何目标运行模板之前加载和预处理数据。 例如,在下面的代码块中,我们从 nuclei-templates/helpers 目录加载所有 ssh 私钥,并将它们作为名为 keys 的变量存储在 payloads 中。如果我们从 “pre-condition” 代码块加载私钥,那么它将为每个目标加载,这不是理想的。
variables:
  keysDir: "helpers/"  # 从此目录加载所有私钥

javascript:
    # init 字段可用于在实际漏洞利用之前进行任何准备工作
    # 这里我们从 helpers 文件夹读取所有私钥并将它们存储在列表中
  - init: |
      let m = require('nuclei/fs');
      let privatekeys = m.ReadFilesFromDir(keysDir)
      updatePayload('keys',privatekeys)

    payloads:
      # 'keys' 将在 init 执行后由实际私钥更新
      keys: 
        - key1
        - key2
init 块中有两个特殊功能
函数描述
updatePayload(key,value)使用给定的键和值更新 payload
set(key,value)使用给定的键和值设置变量
可以在这里找到 JavaScript 协议模板的集合。