Irssi 0.8.16-rc1 setuid() BUG

Authors:Hector Marco & Ismael Ripoll
BUG:Lack of checking setuid() return code
Dates:10 December 2013 - Discovered the bug
10 December 2013 - Contacted affected vendor
13 December 2014 - Fixed
25 March 2014    - Public disclosure


Description

A bug in irssi for versions prior to 0.8.16-rc1 have been found. The bug is caused by not checking the return values of setuid() and getuid() calls. The process must not continue its normal execution when any of these calls fail (return an error) to drop privileges.

Impact

The drop privileges in irssi has the purpose to prevent careless users to unconsciously damage the system. In the irssi application, the drop privileges is not actually a security issue, but this code was added as a generic defensive programming technique. It is not necessary (and not advisable) to execute irssi by root or with the bit setuid activated. See discussion section.

Vulnerable packages

Irssi package 0.8.16-rc1 is vulnerable, versions from 8.10 (released on May-2008) to the current 0.8.16-rc1 (released Dec-2013) are also affected.

The bug

The bug appears because the return value of the setuid() call is not checked. When the setuid() fails the application continue executing (does not terminate) and the following code is executed with the original privileges. The bug appears in fe-common/core/fe-exec.c file, on line 325:
...
setuid(getuid());
setgid(getgid());
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_DFL);
...
if (rec->shell) {
        execvp(shell_args[0], (char **) shell_args);

        fprintf(stderr, "Exec: /bin/sh: %s\n", g_strerror(errno));
} else {
        args = g_strsplit(cmd, " ", -1);
        execvp(args[0], args);
        fprintf(stderr, "Exec: %s: %s\n", args[0], g_strerror(errno));
}
...

Exploit

The strategy to exploit this kind of bugs consists in creating as many processes as the target user is allowed to make (which is given by RLIMIT_NPROC), and then the next attempt to drop privileges will fail, letting the process alive and with the original privileges.

FIX

We have created a non official patch for irssi-0.8.15:
--- irssi-0.8.15/src/fe-common/core/fe-exec.c 2010-04-03 18:19:24.000000000 +0200
+++ irssi-0.8.15-patched/src/fe-common/core/fe-exec.c 2013-12-10 16:40:15.015052397 +0100
@@ -317,8 +317,10 @@ static void process_exec(PROCESS_REC *re

        /* child process, try to clean up everything */
        setsid();
-       setuid(getuid());
-       setgid(getgid());
+        if ( (setgid(getgid()) != 0) || (setuid(getuid()) != 0) ){
+           printf(stderr, "Failed to drop privileges\n");
+           exit(-1);
+        }
         signal(SIGINT, SIG_IGN);
         signal(SIGQUIT, SIG_DFL);
[ irssi-0.8.15-fix-setuid.patch ]

Patching irssi-0.8.15:
$ wget http://hmarco.org/bugs/patches/irssi-0.8.15-fix-setuid.patch
$ cd irssi-0.8.15
$ patch -p1 < ../irssi-0.8.15-fix-setuid.patch

Discussion

A official path have been released. According to irssi staff, the privileges are droped to help careless users that executes irssi with root permissions. For example by invoking irssi with the sudo command.

A careless user using irssi root privileges would have to reach the maximum number of processes (RLIMIT_NPROC) before attempting to do any accidental damage, which is a very unlikely scenario.


Hector Marco - http://hmarco.org