xorl %eax, %eax

CVE-2009-2430: Solaris AuditConfig Privilege Escalation

leave a comment »

This issue was disclosed by Sun Microsystems on 25 June 2009 and it affects Solaris 8, 9 and 10 as well as OpenSolaris builds snv_01 through snv_58. The bug is located in a utility known as auditconfig. AuditConfig provides an interface to set or get kernel audit parameters. A user with RBAC execution profile for auditconfig can execute /usr/sbin/auditconfig with the following options:

– setasid session-ID [cmd]
Execute shell or cmd with specified session-ID.
– setaudit audit-ID preselect_flags term-ID session-ID [cmd]
Execute shell or cmd with the specified audit characteristics.
– setauid audit-ID [cmd]
Execute shell or cmd with the specified audit–ID.

Which are handled by do_setasid(), do_setaudit() and do_setauid() in a manner similar to:

/*
 * do_args()
 *     Desc: Do command line arguments in the order in which they appear.
 */
static void
do_args(char **argv)
{
	struct arg_entry *ae;
 
 	for (++argv; *argv; argv++) {
		ae = get_arg_ent(*argv);
 
 		switch (ae->auditconfig_cmd) {
     ...
 		case AC_ARG_SETAUID:
 			{
 				char *user;
 
 				++argv;
 				user = *argv;
 				++argv;
 				do_setauid(user, argv);
 			}
 			break;
     ...
static void
do_setauid(char *user, char **argv)
{
 	au_id_t auid;
 
 	auid = get_user_id(user);
 	esetauid(&auid);
 	execit(argv);
}

Now, execit() does just this…

static void
execit(char **argv)
{
	char *shell;

        if (*argv) {
		(void) execvp(*argv, argv);
	} else {
		if (((shell = getenv("SHELL")) == NULL) ||
			*shell != '/')
			shell = "/bin/csh";

		(void) execlp(shell, shell, NULL);
	}

	exit_error(gettext("exec(2) failed"));
}

Obviously, the user could insert any binary in SHELL environment variable since the only check is that it starts with ‘/’ and execute code through this call to execlp() system call. To fix this, execit() was completely updated like this:

- 	char *shell;
+ 	char *args, *args_pos;
+ 	size_t len = 0;
+ 	size_t n = 0;
+ 	char **argv_pos;
- 		(void) execvp(*argv, argv);
- 	} else {
- 		if (((shell = getenv("SHELL")) == NULL) ||
- 			*shell != '/')
- 			shell = "/bin/csh";
+ 
+ 		/* concatenate argument array to be passed to sh -c "..." */
+ 		for (argv_pos = argv; *argv_pos; argv_pos++)
+ 			len += strlen(*argv_pos) + 1;
- 		(void) execlp(shell, shell, NULL);
+ 
+ 		if ((args = malloc(len + 1)) == NULL)
+ 			exit_error(
+ 				gettext("Allocation for command/arguments "
+ 					"failed"));
+ 
+ 		args_pos = args;
+ 		for (argv_pos = argv; *argv_pos; argv_pos++) {
+ 			n += snprintf(args_pos, len - n, "%s ", *argv_pos);
+ 			args_pos = args + n;
+ 		}
+ 		/* strip the last space */
+ 		args[strlen(args)] = '';
+ 
+ 		(void) execl("/bin/sh", "sh", "-c", args, NULL);
+ 	} else {
+ 		(void) execl("/bin/sh", "sh", NULL);

So, now it directly uses /bin/sh instead of retrieving this information from SHELL environment variable.

Written by xorl

July 22, 2009 at 17:16

Posted in bugs, solaris

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s