1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

Anti-spoofing protection for SSH auth banners.

The banner text sent by the server was already being run through a
StripCtrlChars. Now it's run through one in line-limiting mode, and
surrounded by header and footer lines long enough that the line-length
limit wouldn't allow the server to counterfeit one. So it should now
be reliably possible to tell what is banner text sent by the server,
and what is not.
This commit is contained in:
Simon Tatham 2019-03-03 19:38:35 +00:00
parent 3936616feb
commit 530b6fed5d

View File

@ -104,6 +104,8 @@ static void ssh2_userauth_add_session_id(
static PktOut *ssh2_userauth_gss_packet( static PktOut *ssh2_userauth_gss_packet(
struct ssh2_userauth_state *s, const char *authtype); struct ssh2_userauth_state *s, const char *authtype);
#endif #endif
static void ssh2_userauth_antispoof_msg(
struct ssh2_userauth_state *s, const char *msg);
static const struct PacketProtocolLayerVtable ssh2_userauth_vtable = { static const struct PacketProtocolLayerVtable ssh2_userauth_vtable = {
ssh2_userauth_free, ssh2_userauth_free,
@ -191,6 +193,8 @@ static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s)
if (!s->banner_scc_initialised) { if (!s->banner_scc_initialised) {
s->banner_scc = seat_stripctrl_new( s->banner_scc = seat_stripctrl_new(
s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER); s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER);
if (s->banner_scc)
stripctrl_enable_line_limiting(s->banner_scc);
s->banner_scc_initialised = true; s->banner_scc_initialised = true;
} }
if (s->banner_scc) if (s->banner_scc)
@ -461,30 +465,41 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
* that we've accumulated. (This should ensure that when * that we've accumulated. (This should ensure that when
* we exit the auth loop, we haven't any left to deal * we exit the auth loop, we haven't any left to deal
* with.) * with.)
*/ *
{ * Don't show the banner if we're operating in non-verbose
/* * non-interactive mode. (It's probably a script, which
* Don't show the banner if we're operating in * means nobody will read the banner _anyway_, and
* non-verbose non-interactive mode. (It's probably * moreover the printing of the banner will screw up
* a script, which means nobody will read the * processing on the output of (say) plink.)
* banner _anyway_, and moreover the printing of
* the banner will screw up processing on the
* output of (say) plink.)
* *
* The banner data has been sanitised already by this * The banner data has been sanitised already by this
* point, so we can safely pass it straight to * point, but we still need to precede and follow it with
* seat_stderr. * anti-spoofing header lines.
*/ */
if (bufchain_size(&s->banner) && if (bufchain_size(&s->banner) &&
(flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {
if (s->banner_scc)
ssh2_userauth_antispoof_msg(
s, "Pre-authentication banner message from server:");
bool mid_line = false;
while (bufchain_size(&s->banner) > 0) { while (bufchain_size(&s->banner) > 0) {
ptrlen data = bufchain_prefix(&s->banner); ptrlen data = bufchain_prefix(&s->banner);
seat_stderr_pl(s->ppl.seat, data); seat_stderr_pl(s->ppl.seat, data);
bufchain_consume(&s->banner, data.len); bufchain_consume(&s->banner, data.len);
} mid_line =
(((const char *)data.ptr)[data.len-1] != '\n');
} }
bufchain_clear(&s->banner); bufchain_clear(&s->banner);
if (mid_line)
seat_stderr_pl(s->ppl.seat, PTRLEN_LITERAL("\r\n"));
if (s->banner_scc)
ssh2_userauth_antispoof_msg(
s, "End of banner message from server");
} }
if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
ppl_logevent("Access granted"); ppl_logevent("Access granted");
goto userauth_success; goto userauth_success;
@ -1760,3 +1775,15 @@ static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
container_of(ppl, struct ssh2_userauth_state, ppl); container_of(ppl, struct ssh2_userauth_state, ppl);
ssh_ppl_reconfigure(s->successor_layer, conf); ssh_ppl_reconfigure(s->successor_layer, conf);
} }
static void ssh2_userauth_antispoof_msg(
struct ssh2_userauth_state *s, const char *msg)
{
strbuf *sb = strbuf_new();
strbuf_catf(sb, "-- %s ", msg);
while (sb->len < 78)
put_byte(sb, '-');
put_datapl(sb, PTRLEN_LITERAL("\r\n"));
seat_stderr_pl(s->ppl.seat, ptrlen_from_strbuf(sb));
strbuf_free(sb);
}