COMMAND
ssh
SYSTEMS AFFECTED
Systems running ssh
PROBLEM
Tatu Ylonen posted following. This advisory contains information
relevant to people who compile ssh with --with-kerberos5. There
is one or more potential security problem in the Kerberos code.
These issues are not relevant for people who have not explicitly
specified --with-kerberos5 on the configure command line. Peter
Benie found a buffer overflow in the kerberos authentication code.
To quote from his mail:
> What about sshconnect.c, line 1139
>
> sprintf(server_name,"host/%s@", remotehost);
>
> where remotehost is (char *) get_canonical_hostname() (up to
> 255 chars), is copied into server_name (a 128 char buffer)?
This buffer overflow is, however, extremely hard to exploit:
1. The victim must have have client compiled with
--with-kerberos5 and --enable-kerberos-tgt-passing.
2. The victim must be connecting to a server running with the
same options (i.e., krb5 with tgt passing).
3. You must do the following DNS spoofing:
- fake reverse map for the *server*
- fake forward map for the fake reversed name
4. You must fake your attack code to look like valid DNS
records; this is highly untrivial with modern versions of
bind that reject all domain names with invalid characters
in them.
5. Only the part of the DNS name beyond 128 bytes can be
exploited; that must be made to align with stack frames and
must contain appropriate return addresses and jump
addresses. It has been shown that this can generally be
done, but the space and structural constraints here are
extremely tight compared to most instances of buffer
overflow exploits.
6. Since the client with Kerberos TGT passing is only used
interactively, the user will almost certainly notice that
something went wrong. Hard that you can, within the
structure and space constraints, construct the code so that
the user would not notice at least the client crashing.
7. You cannot try again after a failed attack until the client
again tries to log into the same host.
This might yield an attack against the *client*. However, there
are also a few other potential problems in the Kerberos code.
Special thanks to Barry Irwin for pointing out one of them.
SOLUTION
A fix will be included in the next release. The patch:
--- sshconnect.c.orig Thu Nov 5 02:09:55 1998
+++ sshconnect.c Thu Nov 5 02:10:53 1998
@@ -282,7 +282,7 @@
/* Child. Permanently give up superuser privileges. */
if (setuid(getuid()) < 0)
- fatal("setuid: %s", strerror(errno));
+ fatal("setuid: %.100s", strerror(errno));
/* Redirect stdin and stdout. */
close(pin[1]);
@@ -944,7 +944,7 @@
if (!ssh_context)
{
if ((r = krb5_init_context(&ssh_context)))
- fatal("Kerberos V5: %s while initializing krb5.", error_message(r));
+ fatal("Kerberos V5: %.100s while initializing krb5.", error_message(r));
krb5_init_ets(ssh_context);
}
@@ -959,14 +959,14 @@
"host", KRB5_NT_SRV_HST,
&creds.server)))
{
- debug("Kerberos V5: error while constructing service name: %s.",
+ debug("Kerberos V5: error while constructing service name: %.100s.",
error_message(r));
goto cleanup;
}
if ((r = krb5_cc_get_principal(ssh_context, ccache,
&creds.client)))
{
- debug("Kerberos V5: failure on principal (%s).",
+ debug("Kerberos V5: failure on principal (%.100s).",
error_message(r));
goto cleanup;
}
@@ -975,7 +975,7 @@
if ((r = krb5_get_credentials(ssh_context, 0,
ccache, &creds, &new_creds)))
{
- debug("Kerberos V5: failure on credentials(%s).",
+ debug("Kerberos V5: failure on credentials(%.100s).",
error_message(r));
goto cleanup;
}
@@ -987,7 +987,7 @@
{
if ((r = krb5_auth_con_init(ssh_context, &auth_context)))
{
- debug("Kerberos V5: failed to init auth_context (%s)",
+ debug("Kerberos V5: failed to init auth_context (%.100s)",
error_message(r));
goto cleanup;
}
@@ -998,7 +998,7 @@
if ((r = krb5_mk_req_extended(ssh_context, &auth_context, ap_opts,
0, new_creds, &auth)))
{
- debug("Kerberos V5: failed krb5_mk_req_extended (%s)",
+ debug("Kerberos V5: failed krb5_mk_req_extended (%.100s)",
error_message(r));
goto cleanup;
}
@@ -1046,7 +1046,7 @@
if (r = krb5_rd_rep(ssh_context, auth_context, &auth, &repl))
{
- packet_disconnect("Kerberos V5 Authentication failed: %s",
+ packet_disconnect("Kerberos V5 Authentication failed: %.100s",
error_message(r));
goto cleanup;
}
@@ -1090,7 +1090,7 @@
krb5_data outbuf;
krb5_error_code r;
int type;
- char server_name[128];
+ char server_name[512];
remotehost = (char *) get_canonical_hostname();
memset(&outbuf, 0 , sizeof(outbuf));
@@ -1100,14 +1100,14 @@
if (!ssh_context)
{
if ((r = krb5_init_context(&ssh_context)))
- fatal("Kerberos V5: %s while initializing krb5.", error_message(r));
+ fatal("Kerberos V5: %.100s while initializing krb5.", error_message(r));
krb5_init_ets(ssh_context);
}
if (!auth_context)
{
if ((r = krb5_auth_con_init(ssh_context, &auth_context)))
{
- debug("Kerberos V5: failed to init auth_context (%s)",
+ debug("Kerberos V5: failed to init auth_context (%.100s)",
error_message(r));
return 0 ;
}
@@ -1124,7 +1124,7 @@
if ((r = krb5_cc_get_principal(ssh_context, ccache,
&client)))
{
- debug("Kerberos V5: failure on principal (%s)",
+ debug("Kerberos V5: failure on principal (%.100s)",
error_message(r));
return 0 ;
}
@@ -1136,7 +1136,7 @@
principal and point it to clients realm. This way
we pass over a TGT of the clients realm. */
- sprintf(server_name,"host/%s@", remotehost);
+ sprintf(server_name,"host/%.100s@", remotehost);
strncat(server_name,client->realm.data,client->realm.length);
krb5_parse_name(ssh_context,server_name, &server);
server->type = KRB5_NT_SRV_HST;
@@ -1145,7 +1145,7 @@
if ((r = krb5_fwd_tgt_creds(ssh_context, auth_context, 0, client,
server, ccache, 1, &outbuf)))
{
- debug("Kerberos V5 krb5_fwd_tgt_creds failure (%s)",
+ debug("Kerberos V5 krb5_fwd_tgt_creds failure (%.100s)",
error_message(r));
krb5_free_principal(ssh_context, client);
krb5_free_principal(ssh_context, server);
@@ -1416,7 +1416,7 @@
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
error("It is also possible that the host key has just been changed.");
error("Please contact your system administrator.");
- error("Add correct host key in %s to get rid of this message.",
+ error("Add correct host key in %.100s to get rid of this message.",
options->user_hostfile);
/* If strict host key checking is in use, the user will have to edit
@@ -1589,7 +1589,7 @@
if (!ssh_context)
{
if ((problem = krb5_init_context(&ssh_context)))
- fatal("Kerberos V5: %s while initializing krb5.",
+ fatal("Kerberos V5: %.100s while initializing krb5.",
error_message(problem));
krb5_init_ets(ssh_context);
}
@@ -1605,7 +1605,7 @@
if ((problem = krb5_cc_get_principal(ssh_context, ccache,
&client)))
{
- debug("Kerberos V5: failure on principal (%s).",
+ debug("Kerberos V5: failure on principal (%.100s).",
error_message(problem));
}
else {
--- auth-kerberos.c.orig Thu Nov 5 02:06:02 1998
+++ auth-kerberos.c Thu Nov 5 02:08:14 1998
@@ -63,11 +63,11 @@
krb5_auth_con_free(ssh_context, auth_context);
auth_context = 0;
}
- log_msg("Kerberos ticket authentication of user %s failed: %s",
+ log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
server_user, error_message(problem));
- debug("Kerberos krb5_auth_con_genaddrs (%s).", error_message(problem));
- packet_send_debug("Kerberos krb5_auth_con_genaddrs: %s",
+ debug("Kerberos krb5_auth_con_genaddrs (%.100s).", error_message(problem));
+ packet_send_debug("Kerberos krb5_auth_con_genaddrs: %.100s",
error_message(problem));
return 0;
}
@@ -80,11 +80,11 @@
krb5_auth_con_free(ssh_context, auth_context);
auth_context = 0;
}
- log_msg("Kerberos ticket authentication of user %s failed: %s",
+ log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
server_user, error_message(problem));
- debug("Kerberos V5 rd_req failed (%s).", error_message(problem));
- packet_send_debug("Kerberos V5 krb5_rd_req: %s", error_message(problem));
+ debug("Kerberos V5 rd_req failed (%.100s).", error_message(problem));
+ packet_send_debug("Kerberos V5 krb5_rd_req: %.100s", error_message(problem));
return 0;
}
@@ -93,22 +93,22 @@
if (problem)
{
krb5_free_ticket(ssh_context, ticket);
- log_msg("Kerberos ticket authentication of user %s failed: %s",
+ log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
server_user, error_message(problem));
- debug("Kerberos krb5_unparse_name failed (%s).", error_message(problem));
- packet_send_debug("Kerberos krb5_unparse_name: %s",
+ debug("Kerberos krb5_unparse_name failed (%.100s).", error_message(problem));
+ packet_send_debug("Kerberos krb5_unparse_name: %.100s",
error_message(problem));
return 0;
}
if (strncmp(server, "host/", strlen("host/")))
{
krb5_free_ticket(ssh_context, ticket);
- log_msg("Kerberos ticket authentication of user %s failed: invalid service name (%s)",
+ log_msg("Kerberos ticket authentication of user %.100s failed: invalid service name (%.100s)",
server_user, server);
- debug("Kerberos invalid service name (%s).", server);
- packet_send_debug("Kerberos invalid service name (%s).", server);
+ debug("Kerberos invalid service name (%.100s).", server);
+ packet_send_debug("Kerberos invalid service name (%.100s).", server);
krb5_xfree(server);
return 0;
}
@@ -122,11 +122,11 @@
if (problem)
{
- log_msg("Kerberos ticket authentication of user %s failed: %s",
+ log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
server_user, error_message(problem));
- debug("Kerberos krb5_copy_principal failed (%s).",
+ debug("Kerberos krb5_copy_principal failed (%.100s).",
error_message(problem));
- packet_send_debug("Kerberos krb5_copy_principal: %s",
+ packet_send_debug("Kerberos krb5_copy_principal: %.100s",
error_message(problem));
return 0;
}
@@ -135,11 +135,11 @@
/* Make the reply - so that mutual authentication can be done */
if ((problem = krb5_mk_rep(ssh_context, auth_context, &reply)))
{
- log_msg("Kerberos ticket authentication of user %s failed: %s",
+ log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
server_user, error_message(problem));
- debug("Kerberos krb5_mk_rep failed (%s).",
+ debug("Kerberos krb5_mk_rep failed (%.100s).",
error_message(problem));
- packet_send_debug("Kerberos krb5_mk_rep failed: %s",
+ packet_send_debug("Kerberos krb5_mk_rep failed: %.100s",
error_message(problem));
return 0;
}
@@ -160,7 +160,7 @@
{
krb5_creds **creds;
krb5_error_code retval;
- static char ccname[128];
+ static char ccname[512];
krb5_ccache ccache = NULL;
struct passwd *pwd;
extern char *ticket;
@@ -208,9 +208,9 @@
if (retval = krb5_rd_cred(ssh_context, auth_context, krb5data, &creds, NULL))
{
- log_msg("Kerberos V5 tgt rejected for user %.100s : %s", server_user,
+ log_msg("Kerberos V5 tgt rejected for user %.100s : %.100s", server_user,
error_message(retval));
- packet_send_debug("Kerberos V5 tgt rejected for %.100s : %s",
+ packet_send_debug("Kerberos V5 tgt rejected for %.100s : %.100s",
server_user,
error_message(retval));
packet_start(SSH_SMSG_FAILURE);
@@ -234,7 +234,7 @@
goto errout;
ticket = xmalloc(strlen(ccname) + 1);
- (void) sprintf(ticket, "%s", ccname);
+ (void) sprintf(ticket, "%.100s", ccname);
/* Successful */
packet_start(SSH_SMSG_SUCCESS);
@@ -244,9 +244,9 @@
errout:
krb5_free_tgt_creds(ssh_context, creds);
- log_msg("Kerberos V5 tgt rejected for user %.100s :%s", server_user,
+ log_msg("Kerberos V5 tgt rejected for user %.100s :%.100s", server_user,
error_message(retval));
- packet_send_debug("Kerberos V5 tgt rejected for %.100s : %s", server_user,
+ packet_send_debug("Kerberos V5 tgt rejected for %.100s : %.100s", server_user,
error_message(retval));
packet_start(SSH_SMSG_FAILURE);
packet_send();