Skip to content

Conversation

chovanecadam
Copy link

@chovanecadam chovanecadam commented Oct 3, 2025

Proposed changes

Adds best-effort support for SSH keyboard-interactive protocol. Although the protocol supports interactive questions, this MR adds support for a single question to which it responds with the password.

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • New Features

    • Adds keyboard-interactive SSH authentication using a provided password.
    • Auto-responds to single-prompt interactive challenges with the supplied credentials.
    • Improves compatibility with SSH servers requiring interactive auth.
  • Refactor

    • Streamlines the authentication flow to handle interactive prompts transparently for users.

@auto-assign auto-assign bot requested a review from dogancanbakir October 3, 2025 17:28
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Adds keyboard-interactive SSH authentication alongside existing password auth by registering an ssh.KeyboardInteractiveChallenge callback that logs prompts and auto-answers username/password prompts using the supplied credentials while retaining direct password authentication.

Changes

Cohort / File(s) Summary of Changes
SSH auth methods enhancement
pkg/js/libs/ssh/ssh.go
Added keyboard-interactive auth support: introduced precompiled regexes, a callback that logs prompts and auto-answers username/password prompts (returns provided password for a single interactive question), and registered it via ssh.KeyboardInteractiveChallenge; preserved existing password auth path.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as App
  participant SSHC as SSH Client
  participant Server as SSH Server

  App->>SSHC: Connect(host, user, password)
  Note over SSHC: Configure auth methods:\n- Password\n- Keyboard-Interactive (callback logs prompts & supplies answers)

  SSHC->>Server: Start authentication
  alt Server requests direct password
    SSHC->>Server: Send password
  else Server uses keyboard-interactive
    Server->>SSHC: Challenge(questions=[...])
    SSHC->>SSHC: Callback invoked for each question (logs prompt)
    alt Prompts match username/password patterns
      SSHC->>Server: Respond with username/password as provided
    else
      SSHC->>Server: Respond with empty/default per callback
    end
  end
  Server-->>SSHC: Auth success/failure
  SSHC-->>App: Connection result
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I twitch my whiskers at the gate,
One prompt, one hop — we authenticate.
I log each question, answer true,
A single pass and session’s new.
Quiet tunnel, burrowed through. 🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "SSH keyboard-interactive" accurately and succinctly describes the core addition of keyboard-interactive authentication support in the SSH library. It focuses on the main feature without extraneous detail, ensuring clarity for anyone scanning the project history. The title is concise, specific, and directly tied to the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95a0f2a and a7ad88e.

📒 Files selected for processing (1)
  • pkg/js/libs/ssh/ssh.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/js/libs/ssh/ssh.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/js/libs/ssh/ssh.go (1)

237-242: Consider returning an error for unsupported multi-question scenarios.

The callback returns an empty answer slice when len(questions) != 1, which may cause authentication to fail silently. Consider returning an explicit error to make the limitation clear.

Apply this diff:

 	cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
 		if len(questions) == 1 {
 			return []string{opts.Password}, nil
 		}
-		return []string{}, nil
+		return nil, fmt.Errorf("keyboard-interactive with %d questions not supported", len(questions))
 	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86be842 and 7f61653.

📒 Files selected for processing (1)
  • pkg/js/libs/ssh/ssh.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Format Go code using go fmt
Run static analysis with go vet

Files:

  • pkg/js/libs/ssh/ssh.go
🔇 Additional comments (1)
pkg/js/libs/ssh/ssh.go (1)

237-242: Verify that blindly answering with the password is acceptable.

The callback responds with the password for any single-question prompt without inspecting the question text. While this is documented as "best-effort," it could pose a security risk if the server asks an unexpected question (e.g., "Are you sure you want to delete all data?").

Consider whether the implementation should:

  1. Validate that the question is password-related (e.g., contains "password" or "passphrase")
  2. Add logging to track what questions are being answered
  3. Document this behavior more explicitly in code comments

If this best-effort approach is intentional for broad compatibility, add a comment explaining the trade-off.

@chovanecadam
Copy link
Author

To answer Rabbit's question, the keyboard-interactive protocol sometimes asks no questions, in which case we return no answers and the authentication flow continues. It would be an error to break the authentication flow there, as the user may be prompted for a password in a later stage. I tested this on ubuntu:24.04 container using the javascript/default-logins/ssh-default-logins.yaml template

@dogancanbakir
Copy link
Member

@coderabbitai create an issue for this PR

Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Get the repository owner and name from the PR URL
REPO="projectdiscovery/nuclei"
PR_NUMBER="6508"
PR_URL="https://github.com/projectdiscovery/nuclei/pull/6508"
COMMENT_URL="https://github.com/projectdiscovery/nuclei/pull/6508#discussion_r1899699999"

# Create the issue
gh issue create \
  --repo "$REPO" \
  --title "Follow-up: SSH keyboard-interactive protocol support" \
  --body "## Context

This issue tracks the implementation of SSH keyboard-interactive protocol support introduced in PR #${PR_NUMBER}.

## Background

PR #${PR_NUMBER} adds best-effort support for the SSH keyboard-interactive protocol with the following characteristics:
- Handles interactive questions with support limited to a single question
- Responds with the configured password
- Allows authentication flow to continue when no questions are asked

## Outstanding Items

As noted in the PR checklist, the following items need attention:
- [ ] Tests
- [ ] CI checks  
- [ ] Documentation

## References

- PR: ${PR_URL}
- Requested by: @dogancanbakir
- Implementation: Tested on ubuntu:24.04 container using \`javascript/default-logins/ssh-default-logins.yaml\` template" \
  --assignee "dogancanbakir"

Length of output: 54


@dogancanbakir: I've created issue #6514 to track this PR. The issue includes:

  • Context about the SSH keyboard-interactive protocol implementation
  • Outstanding items from the PR checklist (tests, CI checks, documentation)
  • References to this PR and your request

You can view it here: #6514

@dogancanbakir dogancanbakir linked an issue Oct 7, 2025 that may be closed by this pull request
3 tasks
@dogancanbakir dogancanbakir requested review from dwisiswant0 and removed request for dogancanbakir October 7, 2025 12:51
Copy link
Member

@dwisiswant0 dwisiswant0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor:

  • It (len(questions) == 1 expr) blindly assumed it was a password prompt. It could send a password to non-password questions like "Enter username:" or "Accept terms? (y/n)". I mean, what about servers that ask username + password in separate questions?
  • Password fields usually do not display the input characters, which makes the echos param a reliable indicator of this behavior.
  • No analysis of question text content. Couldn't distinguish between different types of single questions. Which comes with some unresolved questions:
    • What if servers use non-English prompts?
    • What if they use unusual question formats?
    • What about servers that send empty questions or instructions?

nit:

  • When keyboard-interactive fails, users get a generic "auth failed" with no indication that it was due to complex auth requirements.
  • No way to log when keyboard-interactive auth is attempted vs. when it fails due to complexity.

@chovanecadam
Copy link
Author

In general, this MR does not intend to implement full keyboard-interactive fuzzing. Adding such feature would require also designing API that would allow to specify questions/answers in templates. This MR does not intend to do that. This MR only adds support in cases when

  1. keyboard-interactive is enabled
  2. only password is required

Although keyboard-interactive support would be nice to have in Nuclei, I have no interest in implementing that. The common usecases for keyboard-interactive are requiring TOTP on login. So I think most of the points raised are out of scope. I think this MR is useful and enhances Nuclei in the current state without the nice to have features you described above. Nevertheless I still try to respond to them below:

  • It (len(questions) == 1 expr) blindly assumed it was a password prompt. It could send a password to non-password questions like "Enter username:" or "Accept terms? (y/n)". I mean, what about servers that ask username + password in separate questions?

These are theoretical issues. Username in SSH is provided before the authentication flow starts, asking for it during the flow doesn't make sense. Accepting terms? I have never seen anything like this ever.

  • Password fields usually do not display the input characters, which makes the echos param a reliable indicator of this behavior.

That's probably true.

  • No analysis of question text content. Couldn't distinguish between different types of single questions. Which comes with some unresolved questions:

    • What if servers use non-English prompts?
    • What if they use unusual question formats?
    • What about servers that send empty questions or instructions?

I don't check questions in this MR. I don't log the questions either.

nit:

  • When keyboard-interactive fails, users get a generic "auth failed" with no indication that it was due to complex auth requirements.

That's true. The user is only notified if the authentication was successful and there is a server with a weak password. I don't think it is interesting / useful to know if the auth failed due to other reasons. I could log the questions though, if you think it would be useful

  • No way to log when keyboard-interactive auth is attempted vs. when it fails due to complexity.

I don't understand the distinction here.

@dwisiswant0
Copy link
Member

I have never seen anything like this ever.

SSH servers are not limited to OpenSSH. Some use Cisco, F5, etc, and with custom auth flows. Even if you've never encountered them prompts, they exist1 in some VPN gateways and/or enterprise access controls.

My point is, "len(questions) == 1" expr is particularly problematic as it blindly assumes single questions are password prompts without analyzing content and/or context -- which could totally leak passwords to random prompts, in unexpected scenarios.

Implementing a reliable and cautious approach is more suitable than relying on assumptions that could result in UB.

That's true. The user is only notified if the authentication was successful and there is a server with a weak password. I don't think it is interesting / useful to know if the auth failed due to other reasons. [...]

This is an API-level change, and it should NOT be treated/scoped/reasoned as something that only applies to a specific template or case.

Footnotes

  1. the SSH RFC 4256 explicitly permits arbitrary challenge formats.

@chovanecadam
Copy link
Author

I see. So let's only handle out password if the question matches case-insensitive password and echo is True? And let's also log questions to allow debugging the protocol?

@dwisiswant0
Copy link
Member

I see. So let's only handle out password if the question matches case-insensitive password and echo is True? And let's also log questions to allow debugging the protocol?

Yea that works.

by:
* implement regex-based prompt matching for
  password variants.
* add support for filling username prompts in
  keyboard interactive challenges.
* improve debug logging with structured output.

this addresses issues with servers using
non-standard prompt formats and provides better
visibility into auth failures.

Signed-off-by: Dwi Siswanto <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-up: SSH keyboard-interactive protocol support

4 participants