Skip to main content

什么是认证扫描

在某些情况下,仅在目标上运行Nuclei扫描可能不足以发现漏洞。如果目标受登录保护,那么扫描将无法访问这些受保护的端点。这意味着只有在登录后才能访问的漏洞将无法被发现。 这就是为什么在扫描前进行目标认证很重要。在Nuclei v3.2.0之前,你只能通过在-H标志中传递header进行认证,但这限制了认证的范围,而且不是一个可扩展的解决方案,因为认证需要手动执行,并且header需要手动更新。 为了解决这个问题,Nuclei v3.2.0引入了一个新的通用客户端认证规范,这允许像Nuclei这样的应用程序使用这种格式对目标进行认证。我们称这种格式为Secret File(密钥文件),它通过包含认证相关配置的YAML文件进行管理。
此功能正在为其他ProjectDiscovery工具开发中。

规范

由于认证可以通过多种方式完成,例如使用第三方服务如OAuth、自定义登录、SSO、Bearer Auth等 - 此规范将认证分为两类:静态认证和动态认证。

静态认证

这种方法涉及单一的、静态的密钥,它不会频繁更改,并直接作为已认证HTTP会话的指示器。示例包括API密钥或用于基本认证(Basic Authentication)的凭据(用户名和密码)。

动态认证

这种方法需要多个、经常变化的密钥来管理会话。这在社交登录或OAuth等过程中很常见。在动态认证中,一组凭据(例如:用户名和密码)用于初始认证,而额外的元素(如会话cookie或header)则用于维护会话状态。

处理动态认证

实现和管理静态认证很容易,但处理动态认证因涉及多个实体、密钥和认证流程而变得复杂。有些可能需要浏览器引导认证,而有些可能通过认证流程实现。 解决这个问题的常见方法是使用浏览器捕获并生成登录流程/序列,然后将该脚本提供给处理认证的应用程序。 为了使这个过程变得简单、熟悉和可扩展(用户应该能够在不费太多力气的情况下对数千个带有认证的目标进行扫描),我们利用了现有的丰富的nuclei-templates生态系统。这些模板用YAML编写,可扩展,并配有强大的引擎。 我们通过重用和扩展我们的default-login模板库来实现这种可扩展性。我们不断为不同的应用程序和服务添加模板,这些模板可以在Secret File中引用以执行认证。

认证范围

建议只向使用和需要认证相关数据的目标发送这些数据,而不是全局共享它们并冒着将密钥泄露给第三方的风险。 为了限制特定密钥的范围,我们引入了两个字段domainsdomains-regex(互斥),可用于将密钥的范围限制到特定的目标集。
使用通配符如.*将密钥发送给所有目标。
对于特定目标,只能使用一个密钥。如果发现多个密钥适用于一个目标,将使用第一个,优先考虑domains而非domains-regex

安全性和存储密钥

我们没有强制要求在Secret File配置中硬编码密钥,并支持使用第三方密钥管理系统来模板化和管理密钥。

与密钥管理系统的集成

我们目前正在探索与流行的密钥管理系统集成,以便轻松安全地管理密钥 我们优先支持:
  • 1Password
  • Hashicorp Vault
  • AWS Secrets Manager

跳过密钥文件

此功能在Nuclei v3.3.1中可用。
如果你向Nuclei引擎提供密钥文件,它将自动为执行的模板中的每个请求配置认证或授权。如果你想跳过密钥文件中的密钥配置,而是在特定模板中使用硬编码的密钥或变量,可以使用skip-secret-file _(bool)_选项。通过将此属性设置为true,Nuclei将不会将密钥应用于该模板中的每个请求。 示例
variables:
  username: foo
  password: bar

http:
  - raw:
      - |
        GET /some-restricted-page HTTP/1.1
        Host: {{Hostname}}
        Accept: application/json
        Authorization: Basic {{base64(concat(username, ":", password))}}

    skip-secret-file: true

密钥文件格式

Nuclei v3.2.0的密钥文件YAML格式:
# static secrets
static:
  # 1. Basic Auth based auth
  - type: basicauth
    domains:
      - scanme.sh
    username: test
    password: test

  # 2. API Key (via query parameters) based auth
  - type: query
    domains:
      - example.com
    params:
      - key: token
        value: 1a2b3c4d5e6f7g8h9i0j

  # 3. Bearer Token based auth
  - type: bearertoken
    domains-regex:
      - .*scanme.sh
      - .*pdtm.sh
    token: test
    
  # 4. Custom Header based auth
  - type: header
    domains:
      - api.projectdiscovery.io
      - cve.projectdiscovery.io
      - chaos.projectdiscovery.io
    headers:
      - key: x-pdcp-key
        value: <api-key-here>

  # 5. Cookie based auth
  - type: cookie
    domains:
      - scanme.sh
    cookies:
      - key: PHPSESSID
        value: 1a2b3c4d5e6f7g8h9i0j
        # raw: "PHPSESSID=1a2b3c4d5e6f7g8h9i0j" (an alternative way to specify cookie value)


# dynamic secrets
dynamic:
    # A example dynamic login of Wordpress using REST API
  - template: /path/to/wordpress-login.yaml
    variables:
      - key: username
        value: pdteam
      - key: password
        value: nuclei-fuzz
    input: auth-server.projectdiscovery.io # optional input/target, not required if target is hardcoded in template
    # once login is successful, this can be used in below templatized static secret
    type: cookie
    domains:
        - .*wp.*projectdiscovery.io
    cookies:
      - raw: "{{wp-global-cookie}}"
      - raw: "{{wp-admin-cookie}}"
      - raw: "{{wp-plugin-cookie}}"
    # Note: This here (^) is a static secret in a templatized form
    # so it can be any of the static secret type and not limited to just `cookie`.

密钥文件字段

以下是密钥文件中每个字段的简要说明:

type

此字段指定正在使用的静态密钥类型,并确定应在请求中更新密钥的位置。支持以下类型:
  • basicauth:基本认证
  • query:查询参数
  • bearertoken:Bearer令牌
  • header:自定义Header
  • cookie:Cookie

domains

此字段用于指定应使用密钥的域。如果目标域与此处指定的任何域匹配,则将为该目标使用该密钥。该字段与domains-regex互斥,可用于将密钥的范围限制到特定的目标集。 示例:
domains:
  - scanme.sh
  - example.com

domains-regex

此字段用于使用正则表达式指定应使用密钥的域。如果目标域与此处指定的任何正则表达式匹配,则将为该目标使用该密钥。该字段与domains互斥,可用于将密钥的范围限制到特定的目标集。 示例:
domains-regex:
  - .*projectdiscovery.io
  - .*pdtm.sh

username & password

这些字段用于指定基本认证的用户名和密码,只能与type: basicauth一起使用。 示例:
type: basicauth
domains:
  - scanme.sh
username: test
password: test

params

Params是一个键值对列表,用于指定请求的查询参数。此字段只能与type: query一起使用。 示例:
type: query
domains:
  - example.com
params:
  - key: token
    value: 1a2b3c4d5e6f7g8h9i0j

token

此字段用于指定请求的Bearer令牌,只能与type: bearertoken一起使用。 示例:
type: bearertoken
domains-regex:
  - .*scanme.sh
  - .*pdtm.sh
token: 6f7g8h9i0j1a2b3c4d5e

headers

Headers是一个键值对列表,用于指定请求的自定义headers。此字段只能与type: header一起使用。 示例:
type: header
domains:
  - api.projectdiscovery.io
  - cve.projectdiscovery.io
  - chaos.projectdiscovery.io
headers:
  - key: x-pdcp-key
    value: <api-key-here>

cookies

Cookies是一个键值对列表,用于指定请求的cookies。此字段只能与type: cookie一起使用。 示例:
type: cookie
domains:
  - scanme.sh
cookies:
  - key: PHPSESSID
    value: 1a2b3c4d5e6f7g8h9i0j
    # raw: "PHPSESSID=1a2b3c4d5e6f7g8h9i0j" (an alternative way to specify cookie value)

template

template包含将用于对目标进行认证的模板文件的绝对或相对路径(相对于nuclei-templates目录)。此字段只能与type: dynamic一起使用。 用于动态认证的模板应接受variables和可选的input作为输入,并通过提取器返回会话数据。然后可以在静态密钥中使用会话数据。 示例: 在此示例中,使用用户名和密码通过REST API登录WordPress实例,并通过提取器导出会话数据。
id: wordpress-login

info:
  name: WordPress Login
  author: pdteam
  severity: info
  description: |
    WordPress Login template to use in workflows for authenticated wordpress testing.
  tags: wordpress,login

http:
  - raw:
      - |
        POST /wp-login.php HTTP/1.1
        Host: {{Hostname}}
        Origin: {{RootURL}}
        Content-Type: application/x-www-form-urlencoded
        Cookie: wordpress_test_cookie=WP%20Cookie%20check
        
        log={{username}}&pwd={{password}}&wp-submit=Log+In&testcookie=1
    cookie-reuse: true
    matchers-condition: and
    matchers:
      - type: status
        status:
          - 302

      - type: word
        part: header
        words:
          - '/wp-admin'
          - 'wordpress_logged_in'
        condition: and
    
    extractors:
      - type: regex
        name: wp-plugin-cookie
        part: header
        internal: true
        regex:
          - "Set-Cookie: .+?; path=/wp-content/plugins; HttpOnly"

      - type: regex
        name: wp-admin-cookie
        part: header
        internal: true
        regex:
          - "Set-Cookie: .+?; path=/wp-admin; HttpOnly"

      - type: regex
        name: wp-global-cookie
        part: header
        internal: true
        regex: 
          - "Set-Cookie: .+?; path=/; HttpOnly"

variables

variables是一个键值对列表,用于指定模板的变量。此字段只能与type: dynamic一起使用,并且仅在模板需要变量时才需要。 示例:
variables:
  - key: username
    value: pdteam
  - key: password
    value: nuclei-fuzz

input

input是模板执行的可选输入/目标,仅在模板中没有硬编码目标时才需要。在此处指定input允许轻松切换开发和生产环境,相比在模板中硬编码目标更为灵活。 示例:
input: auth-server.projectdiscovery.io