[
https://issues.apache.org/jira/browse/SSHD-695?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Matthew Pitts updated SSHD-695:
-------------------------------
Description:
If an SSHD client receives a SSH_MSG_USERAUTH_BANNER packet from the server
immediately after KEX and user-auth
SSH_MSG_SERVICE_REQUEST/SSH_MSG_SERVICE_ACCEPT exchanges it can be processed
prior to the using code calling ClientSession#auth. This situation leads to
AuthFuture being null in ClientUserAuthService#process which results in a
validation exception and subsequent short-circuiting of the auth exchange and
session communication.
This was discovered testing 1.2.0 against a Cisco ASA device configured with a
login banner that shows prior to the user entering credentials.
I can confirmed that the same tests work fine using the below patched process
method in ClientUserAuthService which allows for AuthFuture to be null.
This implementation could allow #processUserAuth to be invoked while AuthFuture
is null if some packets come in that are not banners or handled by
ClientSession. However, #processUserAuth seems to also assert the presence of
AuthFuture so I'm thinking the side effect would just be the assertion
exception coming from that method instead of #process.
{code}
@Override
public void process(int cmd, Buffer buffer) throws Exception {
ClientSession session = getClientSession();
// let authFuture be null (not yet present) for handling packets coming
in before
// the client code has auth()'d
AuthFuture authFuture = authFutureHolder.get();
if (authFuture != null && authFuture.isSuccess()) {
throw new IllegalStateException("UserAuth message delivered to
authenticated client");
} else if (authFuture != null && authFuture.isDone()) {
if (log.isDebugEnabled()) {
log.debug("process({}) Ignoring random message - cmd={}",
session, SshConstants.getCommandMessageName(cmd));
}
// ignore for now; TODO: random packets
} else if (cmd == SshConstants.SSH_MSG_USERAUTH_BANNER) {
String welcome = buffer.getString();
String lang = buffer.getString();
if (log.isDebugEnabled()) {
log.debug("process({}) Welcome banner(lang={}): {}", session,
lang, welcome);
}
UserInteraction ui = session.getUserInteraction();
try {
if ((ui != null) && ui.isInteractionAllowed(session)) {
ui.welcome(session, welcome, lang);
}
} catch (Error e) {
log.warn("process({}) failed ({}) to consult interaction: {}",
session, e.getClass().getSimpleName(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("process(" + session + ") interaction
consultation failure details", e);
}
throw new RuntimeSshException(e);
}
} else {
buffer.rpos(buffer.rpos() - 1);
processUserAuth(buffer);
}
}
{code}
was:
If an SSHD client receives a SSH_MSG_USERAUTH_BANNER packet from the server
immediately after KEX and user-auth
SSH_MSG_SERVICE_REQUEST/SSH_MSG_SERVICE_ACCEPT exchanges it can be processed
prior to the using code calling ClientSession#auth. This situation leads to
AuthFuture being null in ClientUserAuthService#process which results in a
validation exception and subsequent short-circuiting of the auth exchange and
session communication.
This was discovered testing 1.2.0 against a Cisco ASA device configured with a
login banner that shows prior to the user entering credentials.
I can confirmed that the same tests work fine using the below patched process
method in ClientUserAuthService which allows for AuthFuture to be null.
{code}
@Override
public void process(int cmd, Buffer buffer) throws Exception {
ClientSession session = getClientSession();
// let authFuture be null (not yet present) for handling packets coming
in before
// the client code has auth()'d
AuthFuture authFuture = authFutureHolder.get();
if (authFuture != null && authFuture.isSuccess()) {
throw new IllegalStateException("UserAuth message delivered to
authenticated client");
} else if (authFuture != null && authFuture.isDone()) {
if (log.isDebugEnabled()) {
log.debug("process({}) Ignoring random message - cmd={}",
session, SshConstants.getCommandMessageName(cmd));
}
// ignore for now; TODO: random packets
} else if (cmd == SshConstants.SSH_MSG_USERAUTH_BANNER) {
String welcome = buffer.getString();
String lang = buffer.getString();
if (log.isDebugEnabled()) {
log.debug("process({}) Welcome banner(lang={}): {}", session,
lang, welcome);
}
UserInteraction ui = session.getUserInteraction();
try {
if ((ui != null) && ui.isInteractionAllowed(session)) {
ui.welcome(session, welcome, lang);
}
} catch (Error e) {
log.warn("process({}) failed ({}) to consult interaction: {}",
session, e.getClass().getSimpleName(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("process(" + session + ") interaction
consultation failure details", e);
}
throw new RuntimeSshException(e);
}
} else {
buffer.rpos(buffer.rpos() - 1);
processUserAuth(buffer);
}
}
{code}
> Client - support receiving of banner prior to auth()
> ----------------------------------------------------
>
> Key: SSHD-695
> URL: https://issues.apache.org/jira/browse/SSHD-695
> Project: MINA SSHD
> Issue Type: Bug
> Affects Versions: 1.2.0
> Reporter: Matthew Pitts
> Attachments: sshd-banner-prior-to-auth-error.log
>
>
> If an SSHD client receives a SSH_MSG_USERAUTH_BANNER packet from the server
> immediately after KEX and user-auth
> SSH_MSG_SERVICE_REQUEST/SSH_MSG_SERVICE_ACCEPT exchanges it can be processed
> prior to the using code calling ClientSession#auth. This situation leads to
> AuthFuture being null in ClientUserAuthService#process which results in a
> validation exception and subsequent short-circuiting of the auth exchange and
> session communication.
> This was discovered testing 1.2.0 against a Cisco ASA device configured with
> a login banner that shows prior to the user entering credentials.
> I can confirmed that the same tests work fine using the below patched process
> method in ClientUserAuthService which allows for AuthFuture to be null.
> This implementation could allow #processUserAuth to be invoked while
> AuthFuture is null if some packets come in that are not banners or handled by
> ClientSession. However, #processUserAuth seems to also assert the presence of
> AuthFuture so I'm thinking the side effect would just be the assertion
> exception coming from that method instead of #process.
> {code}
> @Override
> public void process(int cmd, Buffer buffer) throws Exception {
> ClientSession session = getClientSession();
> // let authFuture be null (not yet present) for handling packets
> coming in before
> // the client code has auth()'d
> AuthFuture authFuture = authFutureHolder.get();
> if (authFuture != null && authFuture.isSuccess()) {
> throw new IllegalStateException("UserAuth message delivered to
> authenticated client");
> } else if (authFuture != null && authFuture.isDone()) {
> if (log.isDebugEnabled()) {
> log.debug("process({}) Ignoring random message - cmd={}",
> session, SshConstants.getCommandMessageName(cmd));
> }
> // ignore for now; TODO: random packets
> } else if (cmd == SshConstants.SSH_MSG_USERAUTH_BANNER) {
> String welcome = buffer.getString();
> String lang = buffer.getString();
> if (log.isDebugEnabled()) {
> log.debug("process({}) Welcome banner(lang={}): {}", session,
> lang, welcome);
> }
> UserInteraction ui = session.getUserInteraction();
> try {
> if ((ui != null) && ui.isInteractionAllowed(session)) {
> ui.welcome(session, welcome, lang);
> }
> } catch (Error e) {
> log.warn("process({}) failed ({}) to consult interaction: {}",
> session, e.getClass().getSimpleName(),
> e.getMessage());
> if (log.isDebugEnabled()) {
> log.debug("process(" + session + ") interaction
> consultation failure details", e);
> }
> throw new RuntimeSshException(e);
> }
> } else {
> buffer.rpos(buffer.rpos() - 1);
> processUserAuth(buffer);
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)