diff --git a/AUTHORS b/AUTHORS index 581aa55f..dc610c0e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -23,6 +23,7 @@ Karl Berry Kaveh R. Ghazi Ludovic Courtès Marcus Brinkmann +Mats Erik Andersson Matt Roberds Michael Weiser Michal Svoboda diff --git a/ChangeLog b/ChangeLog index 36562f54..6a15c717 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2011-12-20 Mats Erik Andersson + + * 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 . + [HAVE_NETINET_IP_H]: Include . + * NEWS: Mention security issue inherent in source routing. + * AUTHORS: Mention myself as contributing author. + 2011-12-19 Mats Erik Andersson * src/rcp.c (main) [!KERBEROS]: Exit at non-zero geteuid(). diff --git a/NEWS b/NEWS index 9ba0d281..306ce33b 100644 --- a/NEWS +++ b/NEWS @@ -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. diff --git a/src/rlogind.c b/src/rlogind.c index 6a0f08bf..63cbe8f4 100644 --- a/src/rlogind.c +++ b/src/rlogind.c @@ -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)) { diff --git a/src/rshd.c b/src/rshd.c index f57e5761..c1a572a6 100644 --- a/src/rshd.c +++ b/src/rshd.c @@ -48,7 +48,7 @@ */ /* - * remote shell server: + * remote shell server exchange protocol: * [port]\0 * remuser\0 * locuser\0 @@ -69,6 +69,12 @@ #include #include #include +#ifdef HAVE_NETINET_IN_SYSTM_H +# include /* n_time */ +#endif +#ifdef HAVE_NETINET_IP_H +# include /* IPOPT_* */ +#endif #include #include @@ -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) {