Skip to content

ssh: add UnauthClientConn.RequestKeyExchange for client-requested pre-auth rekey - #89

Merged
hdm merged 1 commit into
runZeroInc:mainfrom
msuiche:ssh-client-requested-rekey
Sep 7, 2026
Merged

hdm merged 1 commit into
runZeroInc:mainfrom
msuiche:ssh-client-requested-rekey

Conversation

@msuiche

@msuiche msuiche commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds (*UnauthClientConn).RequestKeyExchange(), letting a research client trigger a key re-exchange at an arbitrary point — in particular before userauth completes.

The call is synchronous: it blocks until the key exchange completes (or the connection fails) and returns the exchange's error. This guarantees that on return, subsequent packets are sent over the rekeyed transport — callers cannot race the rekey with their next write. (kexLoop gains a requestKexSync channel whose requesters are recorded and notified when the next exchange completes or the loop exits; the existing asynchronous threshold-based path is unchanged. No interface changes, no behavior changes for existing callers.)

Motivation

Pre-authentication state-transition research. Concretely: MikroTik RouterOS CVE-2026-67279 — a client-requested rekey before authentication makes the server accept connection-protocol messages (session channels, exec) without any login. Detecting this requires initiating a rekey at a point where neither x/crypto/ssh nor this fork currently exposes one. A detection check for SSHamble that uses this API is ready and will be PRed against runZeroInc/sshamble, referencing this change.

Refs:

Test

TestUnauthClientConnRequestKeyExchange (new, client_research_test.go): performs a client-requested rekey immediately after the initial handshake and then completes password authentication over the rekeyed transport. Full x/crypto/ssh suite passes.

(Note: go test -race on this package fails on main as well — a pre-existing race in the FIPS-140 global indicator, unrelated to this change.)

…-auth rekey

Expose the ability to trigger a key re-exchange from an unauthenticated
client connection. The transport already queues packets written during a
rekey and flushes them on completion, so the connection remains usable
immediately after the request.

This enables pre-authentication state-transition research, e.g. probing
how a server handles connection-protocol messages after a rekey that was
requested before userauth completed (needed to detect RouterOS
CVE-2026-67279, where a pre-auth rekey makes the server accept session
channels without authentication).
@hdm
hdm merged commit 40370cd into runZeroInc:main Sep 7, 2026
hdm pushed a commit to runZeroInc/sshamble that referenced this pull request Sep 7, 2026
RouterOS loses track of the incomplete userauth state when the client
requests a key re-exchange before authenticating, and then accepts
connection-protocol messages anyway (fixed in 7.24.2 / 7.23.4 /
6.49.21). An unauthenticated client can open a session channel without
any credentials.

The new vuln-mikrotik-preauth-rekey check requests a rekey immediately
after the initial key exchange, skips the userauth service entirely, and
tries to open a session channel. It needs no credentials and no victim
key material (unlike the CVE-2026-67276 check, which needs the victim's
public key). Two guards keep it precise:

- negative control: the same pre-auth channel open without the rekey
  must be refused, otherwise the server accepts pre-auth sessions
  generally (a different defect)
- RouterOS attribution: the server banner (ROSSSH) or the proof command
  output must identify RouterOS before naming the CVE

Requires the client-requested rekey API from
runZeroInc/excrypto#89; go.mod temporarily
replaces excrypto with the fork branch and should be bumped to a tagged
excrypto release once that lands.

Live-tested against a vulnerable CHR 7.24.1 VM (detected) and against a
compliant Go sshd (control refuses the channel, not reported).
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.

2 participants