Lucene search
+L

ssh-1.2.26-kerberos.txt

🗓️ 17 Aug 1999 00:00:00Reported by Packet StormType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 39 Views

Potential buffer overflow in Kerberos code for ssh-1.2.26, hard to exploit under conditions.

Code
`Date: Thu, 5 Nov 1998 02:38:51 +0200  
From: Tatu Ylonen <[email protected]>  
To: [email protected]  
Subject: security patch for ssh-1.2.26 kerberos code  
  
-----BEGIN PGP SIGNED MESSAGE-----  
  
This message 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 <[email protected]> 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)?  
  
It looks to me like this is a genuine buffer overflow. I had not  
noticed it when going through the code.  
  
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. I don't think 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*.  
  
I've fixed this in the source tree.  
  
I'd like to thank Peter for reporting this. A fix will be included in  
the next release (which I expect in about a week).  
  
The patch for this problem is quote simple:  
- --- sshconnect.c.orig Thu Nov 5 02:09:55 1998  
+++ sshconnect.c Thu Nov 5 02:10:53 1998  
@@ -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));  
@@ -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;  
  
However, there are also a few other potential problems in the Kerberos  
code. Special thanks to Barry Irwin <[email protected]> for pointing  
out one of them. I'm not yet sure whether they are exploitable (we  
don't have Kerberos installed here, nor documentation for it, so I  
can't easily check; however, they might be more serious than the  
above). I'd recommend everyone using ssh with Kerberos authentication  
compiled in to install the following full patch, just to make sure.  
In addition to the above, it explicitly restricts the length of  
various strings. This also includes the above.  
  
Tatu  
  
- --- 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();  
  
  
- --  
SSH Communications Security http://www.ssh.fi/  
SSH IPSEC Toolkit http://www.ipsec.com/  
Free Unix SSH http://www.ssh.fi/sshprotocols2/  
  
-----BEGIN PGP SIGNATURE-----  
Version: 2.6.3i  
Charset: noconv  
  
iQCVAwUBNkDyOakZxfGWH0o1AQGYOQP/bUNnE/ZpSQqWVc0ngxLG50+CtyksugLJ  
wD0X2yIoc8jmY+UNPL7weQatgv6CmUUoWWpLctzKr8A6G/HrD2sh0OHPBwhIxg1i  
3mPj7WrcIX9g/K5LaEksiZ0vv4h/gvSJty5y+wRiu0QLRmuAy91CyaKTV7Sab0YT  
/W/s1NazNIg=  
=iABB  
-----END PGP SIGNATURE-----  
  
----------------------------------------------------------------  
  
Date: Wed, 4 Nov 1998 13:50:49 +0100  
From: Joel Eriksson <[email protected]>  
To: [email protected]  
Subject: Re: ssh-1.2.26 buffer overflow patch  
  
On Sun, 1 Nov 1998, Andy Church wrote:  
  
> [login.c:538]  
> log_msg("putuserattr S_LASTTTY %.900s failed: %.100s", /*...*/);  
>  
> [log-server.c:130]  
> void log_msg(const char *fmt, ...)  
> {  
> char buf[1024];  
> /*...*/  
> vsprintf(buf, fmt, args);  
> /*...*/  
> }  
>  
> Granted, I haven't checked whether this is exploitable, but I could never  
> call that secure. (Count the bytes.)  
  
I don't think there's any reason of not using snprintf, but, in this  
particular case they seem to be rather well protected anyway. I have  
noticed the line you mention above, and a few others that woke my  
interest. But since the whole log_msg-call reads:  
  
log_msg("putuserattr S_LASTTTY %.900s failed: %.100s",  
ttyname, strerror(errno));  
  
It means that strerror() must return a string with a length around 100  
bytes *and* ttyname should be around 900 bytes, I have not checked if that  
is possible, but I certainly don't think so.  
  
There are a few other places that made me wonder, like when lines like:  
  
log_msg("Connection for %.200s not allowed from %s\n",  
user, get_canonical_hostname());  
  
were used, when tracing back to get_canonical_hostname() and then back to  
get_remote_hostname() it seems as the name is limited to 255 bytes anyway.  
  
In auth-kerberos.c there are frequent use of %s in the log_msg()-calls and  
it sure looks dangerous.. In the places where I have tracked the origin of  
the strings supplied their length have been checked *before* log_msg() is  
used. I think that IBM's statements about not having found any exploitable  
overflows in ssh-1.2.26 can probably be trusted, but since the functions  
for logging uses vsprintf to a buffer on 1024 bytes it certainly is very  
possible to introduce a severe securityhole if not being careful. It  
certainly seems a lot easier to me to use vsnprintf's instead and limit  
the length to 1023 bytes instead of having to track back every use of the  
functions to be certain no securityproblem exists.  
  
> --Andy Church | If Bell Atlantic really is the heart  
> [email protected] | of communication, then it desperately  
> http://achurch.dragonfire.net/ | needs a quadruple bypass.  
  
/Joel Eriksson  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

17 Aug 1999 00:00Current
7.4High risk
Vulners AI Score7.4
39