rlogind,rshd: Protect against source route spoofing.

An old attack vector was open in the legacy code.
This commit is contained in:
Mats Erik Andersson
2011-12-20 01:42:10 +01:00
parent 2c22913427
commit 59fafc02de
5 changed files with 90 additions and 9 deletions

View File

@@ -23,6 +23,7 @@ Karl Berry
Kaveh R. Ghazi
Ludovic Courtès
Marcus Brinkmann
Mats Erik Andersson
Matt Roberds
Michael Weiser
Michal Svoboda

View File

@@ -1,3 +1,14 @@
2011-12-20 Mats Erik Andersson <gnu@gisladisker.se>
* src/rlogind.c (rlogind_auth) [IP_OPTIONS]: Abort connection as soon
either of IPOPT_SSRR or IPOPT_LSRR is found. Other options are recorded,
and reported, but immediately erased.
* src/rshd.c (doit) [IP_OPTIONS]: Likewise.
[HAVE_NETINET_IN_SYSTM_H]: Include <netinet/in_systm.h>.
[HAVE_NETINET_IP_H]: Include <netinet/ip.h>.
* NEWS: Mention security issue inherent in source routing.
* AUTHORS: Mention myself as contributing author.
2011-12-19 Mats Erik Andersson <gnu@gisladisker.se>
* src/rcp.c (main) [!KERBEROS]: Exit at non-zero geteuid().

8
NEWS
View File

@@ -25,6 +25,14 @@ Handle IPv6 connections. The server can forward messages
without using a listening INET socket. It can also bind
to a single INET/INET6 address.
* rlogind, rshd
This legacy code was vulnerable to an attack based on source routing.
Whenever either of IPOPT_SSRR or IPOPT_LSRR is encountered, the newly
initiated connection is now server-side aborted. The advisory issued
by Secure Networks, Inc., February 1997, was adapted. It was found at
http://www.citi.umich.edu/u/provos/papers/secnet-spoof.txt
* ifconfig
Now under GNU/Linux "ifconfig -a" shows also interfaces without an address.

View File

@@ -599,8 +599,33 @@ rlogind_auth (int fd, struct auth_data *ap)
&optsize) == 0 && optsize != 0)
{
lp = lbuf;
for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
sprintf (lp, " %2.2x", *cp);
for (cp = optbuf; optsize > 0; )
{
sprintf (lp, " %2.2x", *cp);
lp += 3;
/* These two open an attack vector. */
if (*cp == IPOPT_SSRR || *cp == IPOPT_LSRR)
{
syslog (LOG_NOTICE,
"Discarding connection from %s with set source routing",
inet_ntoa (ap->from.sin_addr));
exit (EXIT_FAILURE);
}
if (*cp == IPOPT_EOL)
break;
if (*cp == IPOPT_NOP)
cp++, optsize--;
else
{
/* Options using a length octet, see RFC 791. */
int inc = cp[1];
optsize -= inc;
cp += inc;
}
}
syslog (LOG_NOTICE, "Ignoring IP options: %s", lbuf);
if (setsockopt (0, ipproto, IP_OPTIONS, (char *) NULL, optsize))
{

View File

@@ -48,7 +48,7 @@
*/
/*
* remote shell server:
* remote shell server exchange protocol:
* [port]\0
* remuser\0
* locuser\0
@@ -69,6 +69,12 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_NETINET_IN_SYSTM_H
# include <netinet/in_systm.h> /* n_time */
#endif
#ifdef HAVE_NETINET_IP_H
# include <netinet/ip.h> /* IPOPT_* */
#endif
#include <unistd.h>
#include <errno.h>
@@ -353,16 +359,46 @@ doit (int sockfd, struct sockaddr_in *fromp)
&optsize) && optsize != 0)
{
lp = lbuf;
/* The clent has set IP options. This isn't allowd.
* Use syslog() to record the fact.
/* The client has set IP options. This isn't allowed.
* Use syslog() to record the fact. Only the option
* types are printed, not their contents.
*/
for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
sprintf (lp, " %2.2x", *cp);
for (cp = optbuf; optsize > 0; )
{
sprintf (lp, " %2.2x", *cp);
lp += 3;
if (*cp == IPOPT_SSRR || *cp == IPOPT_LSRR)
{
/* Already the TCP handshake suffices for
* a man-in-the-middle attack vector.
*/
syslog (LOG_NOTICE,
"Discarding connection from %s with set source routing",
inet_ntoa (fromp->sin_addr));
exit (EXIT_FAILURE);
}
if (*cp == IPOPT_EOL)
break;
if (*cp == IPOPT_NOP)
cp++, optsize--;
else
{
/* Options using a length octet, see RFC 791. */
int inc = cp[1];
optsize -= inc;
cp += inc;
}
}
/* At this point presumably harmless options are present.
* Make a report about them, erase them, and continue. */
syslog (LOG_NOTICE,
"Connection received from %s using IP options (ignored):%s",
"Connection received from %s using IP options (erased):%s",
inet_ntoa (fromp->sin_addr), lbuf);
/* Turn off the options. If this doesn't work, we quit */
/* Turn off the options. If this doesn't work, we quit. */
if (setsockopt (sockfd, ipproto, IP_OPTIONS,
(char *) NULL, optsize) != 0)
{