Logo Search packages:      
Sourcecode: nessus-plugins version File versions

ftp_write_dirs.c

/*
 * ftp writeable dirs
 *
 * This plugin explores a FTP server and searches for 
 * world writeable directories
 *
 * This plugin was written by Alexis de Bernis <alexis@nessus.org>,
 * based on the work of Renaud Deraison and is distributed
 * under the GPL
 */
 
#include <includes.h>


/* Globals */
static char **writable_dirs = NULL;
static unsigned int num_found = 0;


/* Functions declarations */
PlugExport int plugin_init(struct arglist *);
PlugExport int plugin_run(struct arglist *);
void check_directory(struct arglist *, char *, unsigned int, int, unsigned int);
void add_writable_directory(char *);

/* plug-in description */
#define EN_NAME "ftp writeable directories"
#define FR_NAME "Répertoires ftp sur lequel on peut ecrire"
 
#define EN_DESC "\
It is usually a bad idea to have world writeable\n\
directories in a public FTP server, since it may\n\
allow anyone to use the FTP server as a 'warez'\n\
server (this means that the FTP server will be\n\
used to exchange non-free software between\n\
software pirates). It may also allow anyone to\n\
make a denial of service by filling up the FTP\n\
server filesystem\n\n\
Risk factor : Medium"

#define FR_DESC "\
C'est generalement une mauvaise idée que d'avoir\n\
des répertoires en écriture libre sur un serveur FTP\n\
puisque cela permet à n'importe qui de le transformer\n\
en serveur de 'warez' (permettant l'echange de logiciels\n\
payants). Cela peut aussi permettre à n'importe qui de\n\
créer un déni de service en remplissant le disque dur\n\
du serveur FTP.\n\
Facteur de risque : moyen"


#define COPYRIGHT "this plugin is distributed under the GPL"
#define SUMMARY "checks if the remote FTP server has any world writeable dirs"
#define FR_SUMM "vérifie si le serveur FTP distant contient des repertoires writeable"

#define OPTION "How to check if directories are writeable : "
#define OPT1 "Trust the permissions (drwxrwx---)"
#define OPT2 "Attempt to store a file"

#define OPTALL OPT1";"OPT2

#define MOD_WRITE 1
#define MOD_CHK_PERM 2
#define CHECKFILE_NAME "nessus_check"

static int connection_encaps;


/* functions implementation */

/*
 * Initialize the descriptions
 */
PlugExport int plugin_init(struct arglist * desc)
{
      plug_set_id(desc, 10332);
      plug_set_version(desc, "$Revision: 1.22 $");
      plug_set_cve_id(desc, "CAN-1999-0527");
 
      plug_set_name(desc, FR_NAME, "francais");
      plug_set_name(desc, EN_NAME, NULL);
  
      plug_set_description(desc, FR_DESC, "francais");
      plug_set_description(desc, EN_DESC, NULL);
  
      plug_set_summary(desc, FR_SUMM, "francais");
      plug_set_summary(desc, SUMMARY, NULL);
      plug_set_copyright(desc, COPYRIGHT, NULL);
      plug_set_category(desc, ACT_ATTACK);
      plug_set_family(desc, "FTP",NULL);
      add_plugin_preference(desc, OPTION, PREF_RADIO, OPTALL);
      plug_set_dep(desc, "find_service.nes");
      plug_set_dep(desc, "ftp_anonymous.nasl");
      plug_require_port(desc, "Services/ftp");
      plug_require_port(desc, "21");
      return(0);
}


/*
 * The plugin starts here
 */
PlugExport int plugin_run(struct arglist * env)
{     
      int soc;
#ifdef NEW_KB_MGMT
      int type;
      char *asc_port =  plug_get_key(env, "Services/ftp", &type);
      int port = asc_port != NULL ? ( type == KB_TYPE_STR ? atoi(asc_port) : (int)asc_port) : 21;
#else
      char *asc_port =  plug_get_key(env, "Services/ftp");
      int port = asc_port != NULL ? atoi(asc_port) : 21;
#endif
      unsigned int test_mode = MOD_CHK_PERM;
      char *option;
      connection_encaps = plug_get_port_transport(env, port);
      
#ifdef NEW_KB_MGMT
      if(!plug_get_key(env, "ftp/anonymous", &type))
            return(0);
#else
      if(!plug_get_key(env, "ftp/anonymous"))
            return(0);
#endif
      if(host_get_port_state(env, port) <= 0)
            return(0);
      if((soc = open_stream_connection(env, port, connection_encaps, 10)) < 0)
            return(0);
      if(ftp_log_in(soc, "anonymous", "nessus@nessus.org"))
            return(0);

      option = (char *) get_plugin_preference(env, OPTION);
      if(option && !strcmp(option, OPT2))
            test_mode = MOD_WRITE;

      /* Launch the recursive test */
      check_directory(env, "/", test_mode, soc, 0);
      
      /* Analyze the results */
      if(num_found > 0) {
            char *result;
            char *report;
            unsigned int result_len = 1;
            unsigned int i;

            plug_set_key(env, "ftp/writeable_dir", ARG_STRING, writable_dirs[0]);

            for(i = 0; i < num_found; i++) {
                  result_len += 1 + strlen(writable_dirs[i]) + 1;
            }
            result = emalloc(result_len);
            for(i = 0; i < num_found; i++) {
                  result = strcat(result, "\t");
                  result = strcat(result, writable_dirs[i]);
                  result = strcat(result, "\n");
                  efree(&writable_dirs[i]);
            }
            
            report = emalloc(255 + strlen(result));
            sprintf(report, "\
The following directories are world-writeable. You should\n\
correct this problem quickly\n%s\nRisk factor : Medium\n", result);
            post_hole(env, port, report);
            efree(&report);
            efree(&result);
      }
    close_stream_connection(soc);
      return 0;
}


/*
 * Recursive function. It analyzes the given directory
 * then is launched against the subdirectories
 */
void check_directory(struct arglist * env, char *abs_name, unsigned int test_mode, int soc, unsigned int total_dirs)
{
      int data_soc;
      unsigned int i;
      struct sockaddr_in addr;
      char command[4096];
      char line[4096];
      char **subdirs = NULL;
      unsigned int subdirs_num = 0;
#if 0
      printf("CHECKING '%s'\n", abs_name);fflush(stdout);
#endif      

        if ( total_dirs > 255 ) return;
        
      /* initiate PASV mode */
      if(ftp_get_pasv_address(soc, &addr))
            return;

      if ((data_soc = open_stream_connection(env, ntohs(addr.sin_port), connection_encaps, 10)) < 0)
        return;


      if(test_mode == MOD_WRITE) {
            int code;   
                int e;
                
            snprintf(command, sizeof(command), "STOR %s%s\r\n", abs_name, CHECKFILE_NAME);
            write_stream_connection(soc, command, strlen(command));
                e = recv_line(soc, command, sizeof(command) - 1);
                if ( e <= 3 ) return;
            command[3] = '\0';
            code = atoi(command);
            if(code == 425 || code == 150) {
                  add_writable_directory(abs_name);
                  write_stream_connection(data_soc, "nessus", 6);
                  close_stream_connection(data_soc);
                  snprintf(command, sizeof(command), "DELE %s%s\r\n", abs_name, CHECKFILE_NAME);
                  write_stream_connection(soc, command, strlen(command));
                  recv_line(soc, command, sizeof(command) - 1);
                  if(ftp_get_pasv_address(soc, &addr))
                        return;
                  data_soc = open_stream_connection(env, ntohs(addr.sin_port), connection_encaps, 10);
            }
            }


      /* Get directory content */
      
      snprintf(command, sizeof(command), "LIST %s\r\n", abs_name);
      write_stream_connection(soc, command, strlen(command));



      /*
       * Get a list of the subdirectories
       */
      for(;;) {
            char *new_name = NULL;
            char *rel_name;
                int e;
                
            bzero(line, sizeof(line));
            e = recv_line(data_soc, line, sizeof(line) - 1);
            if( e < 2 || line[0] == '\0' )
                  break;

            line[strlen(line) - 2] = '\0';  /* kill the '\r\n' */

            if(line[0] != 'd')
                  continue;
                  
            
            rel_name = strrchr(line, ' ');
            if( rel_name != NULL )
                  rel_name++;
            else
                  continue;                   /* No space found */
            

            if(!strcmp(rel_name, ".") || !strcmp(rel_name, ".."))
                  continue;
            
            /* Go on to the new directory */
            new_name = emalloc(strlen(abs_name) + strlen(rel_name) + 2);
            sprintf(new_name, "%s%s/", abs_name, rel_name);

            if(test_mode == MOD_CHK_PERM && line[8] == 'w')
                  add_writable_directory(new_name);

            /* Add it to the queue if browsable */
            if(line[9] == 'x') {
                  subdirs = erealloc(subdirs, (subdirs_num + 1) * sizeof(char *));
                  subdirs[subdirs_num] = new_name;
                  subdirs_num++;
                        if ( subdirs_num > 255 ) break;
            } else {
                  efree(&new_name);
            }
      }

      /* Free the input buffer (two ACK lines) */
      close_stream_connection(data_soc);
      recv_line(soc, line, sizeof(line) - 1);
      recv_line(soc, line, sizeof(line) - 1);
      

      /*
       * Then analyze them
       */
      for(i = 0; i < subdirs_num; i++) {
            check_directory(env, subdirs[i], test_mode, soc, total_dirs + subdirs_num);
            efree(&(subdirs[i]));
      }
      efree(&subdirs);
}


/*
 * Just add a name to the list
 */
void add_writable_directory(char *name)
{
      writable_dirs = erealloc(writable_dirs, (num_found + 1) * sizeof(char *));
      writable_dirs[num_found] = emalloc(strlen(name) + 1);
      strcpy(writable_dirs[num_found], name);
      num_found++;
}

Generated by  Doxygen 1.6.0   Back to index