Monday, February 12, 2007

1994 called, it wants its bug back!

Sometimes I wonder why we bother with all these impossibly hard to exploit heap corruption vulnerabilities when there are still remote code execution bugs that can be exploited with nothing more than a simple command.

This weekend there was a post on the Full-Disclosure mailing list describing a mindblowingly simple remote root vulnerability in Solaris:

telnet -l -fusername hostname

The telnet command above will log you in on any Solaris box with any username, without authentication. All you have to do is put '-f' before the username. On some system the root login is disabled, but you can log in as user bin and easily escalate your privileges to root.

Amusingly, it turns out that this is a ancient bug, first reported in 1994 on AIX. You can read its entry in OSVDB, including a link to the original discussion on Bugtraq.

The cause of the vulnerability is the -f option of /usr/sbin/login. This option tells login that the user is pre-authenticated and should be allowed to log in with the username specified after the option. As a security mechanism, login allows the use of the -f option only when it is invoked with root permissions. The relevant Solaris code in login.c is given below:

1399 case 'f':
1400 /*
1401 * Must be root to bypass authentication
1402 * otherwise we exit() as punishment for trying.
1403 */

1404 if (getuid() != 0 || geteuid() != 0) {
1405 audit_error = ADT_FAIL_VALUE_AUTH_BYPASS;
1406
1407 login_exit(1); /* sigh */
1408 /*NOTREACHED*/
1409 }
1410 /* save fflag user name for future use */
1411 SCPYL(user_name, optarg);
1412 fflag = B_TRUE;
1413 break;

If the fflag variable is set by the code above, the authentication step is skipped:

528 /* we are already authenticated. fill in what we must, then continue */
529 if (fflag) {
530
531 if ((pwd = getpwnam(user_name)) == NULL) {
532 audit_error = ADT_FAIL_VALUE_USERNAME;
533
534 log_bad_attempts();
535 (void) printf("Login failed: unknown user '%s'.\n",
536 user_name);
537 login_exit(1);
538 }
539
540 } else {
541 /*
542 * Perform the primary login authentication activity.
543 */

544 login_authenticate();
545 }

As long as untrusted users are not allowed to specify the -f option to login,
this code will be safe. Unfortunately, the in.telnetd daemon does not sanitize
the username before it passes it to /usr/sbin/login. Look at the code in
in.telnetd.c:

3199 } else /* default, no auth. info available, login does it all */ {
3200 (void) execl(LOGIN_PROGRAM, "login",
3201 "-p", "-h", host, "-d", slavename,
3202 getenv("USER"), 0);
3203 }

If the username passed by the telnet client starts with '-f', login will interpret it as a command line option and the user will be logged it without any authentication.

If you still have telnetd enabled on your servers, now is a good time to turn it off.

UPDATE: The fix for this bug is available in the OpenSolaris CVS

Labels: ,