What is an Authenticated Scan ?

There are some scenarios when running a Nuclei scan on a target might not be enough to find vulnerabilities. If a target is protected by login, then the scan will not be able to access those protected endpoints. This means vulnerabilities that are only accessible after logging in will not be found.

This is why authenticating with targets is important, before Nuclei v3.2.0, you could only authenticate by passing header in -H flag, but this limits the scope of authentication and is a not a scalable solution since authentication would need to be performed manually and the headers would need to be updated manually.

To solve this issue, Nuclei v3.2.0 introduces a new specification for generic client side Authentication, this allows apps like Nuclei to authenticate with targets using this format. We call this format Secret File, and it is managed through a YAML file that contains authentication related configuration.

This functionality is under development for other ProjectDiscovery Tools.

Specification

Since authentication can be done in multiple ways, for example, using 3rd party services like OAuth, Custom Login , SSO , Bearer Auth and more - this specification categorizes authentication into two types: static authentication and dynamic authentication.

Static Authentication

This approach involves a single, static secret that doesn’t change frequently and serves as a direct indicator of an authenticated HTTP session. Examples include API Keys or credentials used in Basic Authentication (username and password).

Dynamic Authentication

This method requires multiple, frequently changing secrets to manage a session. It’s typical of processes like a social login or OAuth. In dynamic authentication, one set of credentials (for example: username and password) is used for the initial authentication, while additional elements (such as a session cookie or header) are employed to maintain the session’s state.

Dealing with Dynamic Authentication

Implementing and managing Static Authentication is easy, but dealing with Dynamic Authentication is a bit complex due to multiple entities and secrets and the flow of authentication being involved. Some might require a browser guided authentication while some might be achievable with auth flow. A common solution for this is to capture and generate a login flow/sequence using a browser and then feed that script to app handling the authentication._createMdxContent

To focus on making this process easy, familiar, and scalable (users should be able to scan thousands of targets with authentication without much hassle), we leverage the existing rich ecosystem of nuclei-templates. These are written in YAML, are scalable, and comes with a powerful engine.

We achieve this scalability by reusing and extending our default-login templates library. We are continuously adding templates for different apps and services, and these templates can then be referenced in the Secret File to perform authentication.

Scope of Authentication

It is recommended to send authentication-related data to only those targets that use and require them, instead of sharing them globally and risk leaking secrets to third parties.

To limit scope of a particular secret, we have introducd two fields domains & domains-regex (mutually exclusive) which can be used to limit the scope of a secret to a particular set of targets.

Use a wildcard like .* to send a secret to all targets.
Only one secret can be used for a particular target, if multiple secrets are found for a target, the first one will be used with priority given to domains over domains-regex.

Security & Storing Secret

We have not imposed the need to hardcode secrets in the Secret File configuration, and support the use of third-party secret management systems to templatize and manage secrets.

Integrations with Secret Management Systems

We are currently exploring integrations with popular secret management systems for easy and secure management of secrets

We are prioritizng support for:

  • 1Password
  • Hashicorp Vault
  • AWS Secrets Manager

Skipping Secret File

This feature is available in Nuclei v3.3.1.

If you provide a secret file to the Nuclei engine, it will automatically configure authentication or authorization for each request in the executed templates. In case you want to skip the secret configuration from the secret file and instead use hardcoded secrets or variables in specific templates, you can use the skip-secret-file (bool) option. By setting this property to true, Nuclei will not apply the secrets to each request in that templates.

Example

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

Secret File Formats

YAML format of Secret File as of Nuclei v3.2.0:

# 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`.

Secret File Fields

Here’s a brief explaination of each field in the secret file:

type

This field specifies the type of static secret being used and determines where the secret should be updated in the request. The following types are supported:

  • basicauth: Basic Authentication
  • query: Query Parameters
  • bearertoken: Bearer Token
  • header: Custom Header
  • cookie: Cookie

domains

This field is used to specify the domains for which the secret should be used. If the target domain matches any of the domains specified here, the secret will be used for that target. This field is mutually exclusive with domains-regex and can be used to limit the scope of a secret to a particular set of targets.

Example:

domains:
  - scanme.sh
  - example.com

domains-regex

This field is used to specify the domains for which the secret should be used using regex. If the target domain matches any of the regex specified here, the secret will be used for that target. This field is mutually exclusive with domains and can be used to limit the scope of a secret to a particular set of targets.

Example:

domains-regex:
  - .*projectdiscovery.io
  - .*pdtm.sh

username & password

These fields are used to specify the username and password for Basic Authentication and can only be used with type: basicauth.

Example:

type: basicauth
domains:
  - scanme.sh
username: test
password: test

params

Params is a list of key-value pairs that are used to specify the query parameters for the request. This field can only be used with type: query.

Example:

type: query
domains:
  - example.com
params:
  - key: token
    value: 1a2b3c4d5e6f7g8h9i0j

token

This field is used to specify the Bearer Token for the request and can only be used with type: bearertoken.

Example:

type: bearertoken
domains-regex:
  - .*scanme.sh
  - .*pdtm.sh
token: 6f7g8h9i0j1a2b3c4d5e

headers

Headers is a list of key-value pairs that are used to specify the custom headers for the request. This field can only be used with type: header.

Example:

type: header
domains:
  - api.projectdiscovery.io
  - cve.projectdiscovery.io
  - chaos.projectdiscovery.io
headers:
  - key: x-pdcp-key
    value: <api-key-here>

cookies

Cookies is a list of key-value pairs that are used to specify the cookies for the request. This field can only be used with type: cookie.

Example:

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

template

template contains the absolute or relative path (of nuclei-templates directory) to the template file that will be used to authenticate with the target. This field can only be used with type: dynamic.

A template used for dynamic authentication should accept variables and optionally input as input, and should return the session data via extractor. The session data can then be used in the static secret.

Example:

In this example, a username and password are used to login to a Wordpress instance using REST API and the session data is exported via extractors.

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 is a list of key-value pairs that are used to specify the variables for the template. This field can only be used with type: dynamic and is only required if the template requires variables.

Example:

variables:
  - key: username
    value: pdteam
  - key: password
    value: nuclei-fuzz

input

input is a optional input/target for the template to be executed on and is only required if the target is not hardcoded in the template. Specifying input here allows easy switching of dev and prod environments easily compared to hardcoding the target in the template.

Example:

input: auth-server.projectdiscovery.io