struct arglist * str2arglist(char * str) { struct arglist * ret; char * t = strchr(str, ','); if(!str || str[0] == '\0') { return NULL; } ret = emalloc ( sizeof(struct arglist) ); while((t = strchr(str, ',')) != NULL) { t[0] = 0; while(str[0]==' ')str++; if(str[0] != '\0') { arg_add_value(ret, str, ARG_INT, 0, (void*)1); } str = t+1; } while(str[0]==' ')str++; if(str[0] != '\0') arg_add_value(ret, str, ARG_INT, 0, (void*)1); return ret; }
struct arglist * plug_get_oldstyle_kb(struct arglist * desc ) { struct kb_item ** kb = arg_get_value(desc, "key"); struct arglist * ret; struct kb_item * k; int i; if ( kb == NULL ) return NULL; ret = emalloc ( sizeof(struct arglist) ); for ( i = 0 ; i < HASH_MAX ; i ++ ) { k = kb[i]; while ( k != NULL ) { if ( k->type == KB_TYPE_INT ) arg_add_value(ret, k->name, ARG_INT, -1, (void*)k->v.v_int); else if ( k->type == KB_TYPE_STR ) arg_add_value(ret, k->name, ARG_STRING, strlen(k->v.v_str), estrdup(k->v.v_str)); k = k->next; } } return ret; }
static void main_loop () { log_write ("openvassd %s started\n", OPENVASSD_VERSION); proctitle_set ("openvassd: Waiting for incoming connections"); for (;;) { int soc; int family; unsigned int lg_address; struct sockaddr_in6 address6; struct sockaddr_in6 *p_addr; struct arglist *globals; struct addrinfo *ai; check_and_reload (); wait_for_children1 (); ai = arg_get_value (g_options, "addr"); lg_address = sizeof (struct sockaddr_in6); soc = accept (global_iana_socket, (struct sockaddr *) (&address6), &lg_address); if (soc == -1) continue; /* * MA: you cannot share an open SSL connection through fork/multithread * The SSL connection shall be open _after_ the fork */ globals = emalloc (sizeof (struct arglist)); arg_add_value (globals, "global_socket", ARG_INT, -1, GSIZE_TO_POINTER (soc)); arg_add_value (globals, "plugins", ARG_ARGLIST, -1, global_plugins); arg_add_value (globals, "preferences", ARG_ARGLIST, -1, global_preferences); p_addr = emalloc (sizeof (struct sockaddr_in6)); family = ai->ai_family; memcpy (p_addr, &address6, sizeof (address6)); arg_add_value (globals, "client_address", ARG_PTR, -1, p_addr); arg_add_value (globals, "family", ARG_INT, -1, GSIZE_TO_POINTER (family)); /* we do not want to create an io thread, yet so the last argument is -1 */ if (create_process ((process_func_t) scanner_thread, globals) < 0) { log_write ("Could not fork - client won't be served"); sleep (2); } close (soc); arg_free (globals); } }
static void arg_replace_value (struct arglist *arglist, char *name, int type, int length, void *value) { if (arg_get_type (arglist, name) < 0) arg_add_value (arglist, name, type, length, value); else arg_set_value (arglist, name, length, value); }
void add_socket(struct arglist *script_infos, int socket) { struct arglist *socket_list = NULL; struct arglist *temp_list = NULL; char line[10] = {0}; if (socket <= 0) return; socket_list = (struct arglist *)arg_get_value(script_infos, "socket_list"); if (!socket_list) { socket_list = emalloc(sizeof(struct arglist)); if (!socket_list) return; arg_add_value(script_infos, "socket_list", ARG_PTR, -1, socket_list); } sprintf(line, "%d", socket); if (arg_get_value(socket_list, line) <= 0) arg_add_value(socket_list, line, ARG_INT, -1, (void *)socket); }
void plugin_set_running_state(struct arglist * plugin, int state) { if(plugin == NULL) return; if(arg_get_value(plugin, "RUNNING_STATE") != NULL) arg_set_value(plugin, "RUNNING_STATE", sizeof(state), (void*)state); else arg_add_value(plugin, "RUNNING_STATE", ARG_INT, sizeof(state), (void*)state); }
struct arglist * store_load_plugin(char * dir, char * file, char * md5, struct arglist * prefs) { char desc_file[PATH_MAX+1]; char plug_file[PATH_MAX+1]; char * str; char store_dir[PATH_MAX+1]; struct plugin p; struct pprefs pp[MAX_PREFS]; struct arglist * ret; int i; bzero(pp, sizeof(pp)); snprintf(desc_file, sizeof(desc_file), "%s/.desc/%s", dir, file); str = strrchr(desc_file, '.'); if( str != NULL ) { str[0] = '\0'; if( strlen(desc_file) + 6 < sizeof(desc_file) ) strcat(desc_file, ".desc"); } snprintf(plug_file, sizeof(plug_file), "%s/%s", dir, file); snprintf(store_dir, sizeof(store_dir), "%s/.desc", dir); if(store_get_plugin_f(&p, pp, store_dir, file) < 0) return NULL; if(p.magic != MAGIC) return NULL; if(p.id > 0) { if(md5 != NULL && strcmp(p.md5, md5) != 0) return NULL; } else return NULL; ret = emalloc(sizeof(struct arglist)); plug_set_id(ret, p.id); plug_set_category(ret, p.category); plug_set_fname(ret, file); arg_add_value(ret, "preferences", ARG_ARGLIST, -1, prefs); if(p.has_prefs) { for(i=0;pp[i].type[0] != '\0';i++) { _add_plugin_preference(prefs, p.name, pp[i].name, pp[i].type, pp[i].dfl); } } return ret; }
/** * @brief Inits an arglist which can be used by the plugins. * * The arglist will have following keys and (type, value): * - NAME (string, The hostname parameter) * - FQDN (string, Fully qualified domain name, e.g. host.domain.net) * - MAC (string, The mac parameter if non-NULL) * - IP (*in_adrr, The ip parameter) * - VHOSTS (string, comma separated list of vhosts for this IP) * * @param mac MAC- adress of host or NULL. * @param hostname Hostname to be set. * @param ip in_adress struct to be set. * @param vhosts vhosts list to be set * * @return A 'hostinfo' arglist. */ static struct arglist * attack_init_hostinfos_vhosts (char *mac, char *hostname, struct in6_addr *ip, char *vhosts, char *fqdn) { struct arglist *hostinfos; hostinfos = emalloc (sizeof (struct arglist)); if (mac) { arg_add_value (hostinfos, "NAME", ARG_STRING, strlen (mac), mac); arg_add_value (hostinfos, "MAC", ARG_STRING, strlen (mac), mac); } else arg_add_value (hostinfos, "NAME", ARG_STRING, strlen (hostname), estrdup (hostname)); if (fqdn) arg_add_value (hostinfos, "FQDN", ARG_STRING, strlen (fqdn), estrdup (fqdn)); arg_add_value (hostinfos, "IP", ARG_PTR, sizeof (struct in6_addr), ip); if (vhosts) arg_add_value (hostinfos, "VHOSTS", ARG_STRING, strlen (vhosts), estrdup (vhosts)); return (hostinfos); }
tree_cell * nasl_start_denial(lex_ctxt * lexic) { struct arglist * script_infos = lexic->script_infos; int to = lexic->recv_timeout; int port = plug_get_host_open_port(script_infos); int soc; int alive = 0; tree_cell * p; if(port) { soc = open_stream_connection(script_infos, port, NESSUS_ENCAPS_IP, to); if(soc>=0) { if(arg_get_value(script_infos, "denial_port") != 0) arg_set_value(script_infos, "denial_port", sizeof(int), (void*)port); else arg_add_value(script_infos, "denial_port", ARG_INT, sizeof(int), (void*)port); close_stream_connection(soc); return FAKE_CELL; } } p = nasl_tcp_ping(lexic); if (p != NULL) alive = p->x.i_val; if(arg_get_value(script_infos, "tcp_ping_result") != 0) arg_set_value(script_infos, "tcp_ping_result", sizeof(int), (void*)alive); else arg_add_value(script_infos, "tcp_ping_result", ARG_INT, sizeof(int), (void*)alive); deref_cell(p); return FAKE_CELL; }
/* add udp data in our cache */ static int add_udp_data(struct arglist * script_infos, int soc, char * data, int len) { harglst * udp_data = arg_get_value(script_infos, "udp_data"); char name[12] = {0}; if(udp_data == NULL) { udp_data = harg_create(123); arg_add_value(script_infos, "udp_data", ARG_PTR, -1, udp_data); } snprintf(name, sizeof(name)-1, "%d", soc); if(harg_get_blob(udp_data, name) != NULL) harg_set_blob(udp_data, name, len, data); else harg_add_blob( udp_data, name, len, data); return 0; }
/* add udp data in our cache */ static int add_udp_data (struct arglist *script_infos, int soc, char *data, int len) { GHashTable * udp_data = arg_get_value (script_infos, "udp_data"); struct udp_record * data_record = g_malloc0 (sizeof(struct udp_record)); int * key = g_memdup (&soc, sizeof(int)); data_record->len = len; data_record->data = g_memdup ((gconstpointer)data, (guint)len); if (udp_data == NULL) { udp_data = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, g_free); arg_add_value (script_infos, "udp_data", ARG_PTR, -1, udp_data); } g_hash_table_replace (udp_data, (gpointer)key, (gpointer)data_record); return 0; }
/** * @brief Returns \<port\> if the lists of the required ports between * @brief plugin 1 and plugin 2 have at least one port in common. */ struct arglist * requirements_common_ports (struct scheduler_plugin *plugin1, struct scheduler_plugin *plugin2) { struct arglist *ret = NULL; struct arglist *req1; struct arglist *req2; if (!plugin1 || !plugin2) return 0; req1 = plugin1->required_ports; if (req1 == NULL) return 0; req2 = plugin2->required_ports; if (req2 == NULL) return 0; while (req1->next != NULL) { struct arglist *r = req2; if (r != NULL) while (r->next != NULL) { if (req1->type == r->type) { if (r->name && req1->name && !strcmp (r->name, req1->name)) { if (!ret) ret = emalloc (sizeof (struct arglist)); arg_add_value (ret, r->name, ARG_INT, 0, (void *) 1); } } r = r->next; } req1 = req1->next; } return ret; }
int execute_nasl_script(struct arglist * script_infos, const char* name, int mode) { naslctxt ctx; nasl_func *pf; int err = 0; tree_cell *ret; lex_ctxt *lexic; char old_dir[MAXPATHLEN+1]; char *newdir; char *old; tree_cell description; struct arglist* prefs = arg_get_value(script_infos, "preferences"); char *str; int to; srand48(getpid() + getppid() + (long)time(NULL)); old_dir[sizeof(old_dir) - 1] = '\0'; getcwd(old_dir, sizeof(old_dir) - 1); #if NASL_DEBUG > 2 nasl_trace_fp = stderr; #endif if((old = arg_get_value(script_infos, "script_name")) == NULL) arg_add_value(script_infos, "script_name", ARG_STRING, strlen(name), estrdup(name)); else { efree(&old); arg_set_value(script_infos, "script_name", strlen(name), estrdup(name)); } newdir = strrchr(name, '/'); if(newdir != NULL) { char dir[MAXPATHLEN+1]; char *s; dir[sizeof(dir) - 1] = '\0'; strncpy(dir, name, sizeof(dir) - 1); s = strrchr(dir, '/'); s[0] = '\0'; chdir(dir); } if (init_nasl_ctx(&ctx, name) < 0) { chdir(old_dir); return -1; } if (naslparse(&ctx)) { nasl_perror(NULL, "\nParse error at or near line %d\n", ctx.line_nb); nasl_clean_ctx(&ctx); chdir(old_dir); return -1; } #if NASL_DEBUG > 4 nasl_dump_tree(ctx.tree); #endif lexic = init_empty_lex_ctxt(); lexic->script_infos = script_infos; str = arg_get_value(prefs, "checks_read_timeout"); if( str != NULL ) to = atoi(str); else to = 5; if(to <= 0)to = 5; lexic->recv_timeout = to; init_nasl_library(lexic); if (! (mode & NASL_EXEC_PARSE_ONLY)) { bzero(&description, sizeof(description)); description.type = CONST_INT; description.x.i_val = (mode & NASL_EXEC_DESCR) != 0; add_named_var_to_ctxt(lexic, "description", &description); truc = (lex_ctxt*)ctx.tree; if ((ret = nasl_exec(lexic, ctx.tree)) == NULL) err = -1; else deref_cell(ret); if ((pf = get_func_ref_by_name(lexic, "on_exit")) != NULL) nasl_func_call(lexic, pf, NULL); } #if NASL_DEBUG > 2 { struct rusage ru; if (getrusage(RUSAGE_SELF, &ru) < 0) perror("getrusage"); else { nasl_perror(lexic, "rusage: utime=%d.%02d stime=%d.%02d minflt=%d majflt=%d\n", ru.ru_utime.tv_sec, ru.ru_utime.tv_usec / 10000, ru.ru_stime.tv_sec, ru.ru_stime.tv_usec / 10000, ru.ru_minflt, ru.ru_majflt); } } #endif #if NASL_DEBUG > 3 nasl_dump_tree(ctx.tree); #endif nasl_clean_ctx(&ctx); free_lex_ctxt(lexic); chdir(old_dir); return err; }
/** * @brief Attack one host. */ static void attack_host (struct arglist *globals, struct arglist *hostinfos, char *hostname, plugins_scheduler_t sched) { /* Used for the status */ int num_plugs = 0; int cur_plug = 1; kb_t kb; gboolean new_kb = FALSE; int forks_retry = 0; struct arglist *plugins = arg_get_value (globals, "plugins"); struct arglist *tmp; proctitle_set ("openvassd: testing %s", arg_get_value (hostinfos, "NAME")); kb = init_host_kb (globals, hostname, hostinfos, &new_kb); num_plugs = get_active_plugins_number (plugins); tmp = emalloc (sizeof (struct arglist)); arg_add_value (tmp, "HOSTNAME", ARG_ARGLIST, -1, hostinfos); /* launch the plugins */ pluginlaunch_init (globals); for (;;) { struct scheduler_plugin *plugin; pid_t parent; /* Check that our father is still alive */ parent = getppid (); if (parent <= 1 || process_alive (parent) == 0) { pluginlaunch_stop (); return; } /* Idle if the scan has been paused. */ if (pause_whole_test) { /* Let the running NVTs complete. */ pluginlaunch_wait (); /* Send the PAUSE status to the client. */ if (comm_send_status (globals, hostname, "pause", cur_plug, num_plugs) < 0) { pluginlaunch_stop (); goto host_died; } /* Wait for resume. */ while (pause_whole_test) sleep (1); /* Send the RESUME status to the client. */ if (comm_send_status (globals, hostname, "resume", cur_plug, num_plugs) < 0) { pluginlaunch_stop (); goto host_died; } } plugin = plugins_scheduler_next (sched); if (plugin != NULL && plugin != PLUG_RUNNING) { int e; again: e = launch_plugin (globals, sched, plugin, hostname, &cur_plug, num_plugs, hostinfos, kb, new_kb); if (e < 0) { /* * Remote host died */ if (e == ERR_HOST_DEAD) goto host_died; else if (e == ERR_CANT_FORK) { if (forks_retry < MAX_FORK_RETRIES) { forks_retry++; log_write ("fork() failed - sleeping %d seconds (%s)", forks_retry, strerror (errno)); fork_sleep (forks_retry); goto again; } else { log_write ("fork() failed too many times - aborting"); goto host_died; } } } } else if (plugin == NULL) break; else pluginlaunch_wait_for_free_process (); } pluginlaunch_wait (); host_died: comm_send_status (globals, hostname, "attack", num_plugs, num_plugs); arg_free (tmp); pluginlaunch_stop (); plugins_scheduler_free (sched); gchar *network_scan_status = arg_get_value (globals, "network_scan_status"); if (network_scan_status != NULL) { if (g_ascii_strcasecmp (network_scan_status, "busy") == 0) { save_kb_close (globals, "network"); } } else if (new_kb == TRUE) save_kb_close (globals, hostname); }
struct arglist * store_plugin(struct arglist * plugin, char * file, char * md5) { char desc_file[PATH_MAX+1]; char path[PATH_MAX+1]; struct plugin plug; struct pprefs pp[MAX_PREFS+1]; char * str; char * dir; struct arglist * arglist, * ret, *prefs; int e; int fd; int num_plugin_prefs = 0; if( current_mode == MODE_SYS ) dir = sys_store_dir; else dir = usr_store_dir; if(strlen(file) + 2 > sizeof(path)) return NULL; strncpy(path, dir, sizeof(path) - 2 - strlen(file)); str = strrchr(path, '/'); if(str != NULL) { str[0] = '\0'; } strcat(path, "/"); strcat(path, file); snprintf(desc_file, sizeof(desc_file), "%s/%s", dir, file); str = strrchr(desc_file, '.'); if( str != NULL ) { str[0] = '\0'; if(strlen(desc_file) + 6 < sizeof(desc_file) ) strcat(desc_file, ".desc"); } bzero(&plug, sizeof(plug)); bzero(pp, sizeof(pp)); plug.magic = MAGIC; plug.id = _plug_get_id(plugin); e = safe_copy(path, plug.path, sizeof(plug.path), path, "path"); if(e < 0)return NULL; e = safe_copy(md5, plug.md5, sizeof(plug.md5), path, "md5"); if(e < 0)return NULL; plug.timeout = _plug_get_timeout(plugin); plug.category = _plug_get_category(plugin); str = _plug_get_name(plugin); e = safe_copy(str, plug.name, sizeof(plug.name), path, "name"); if(e < 0)return NULL; str = _plug_get_version(plugin); e = safe_copy(str, plug.version, sizeof(plug.version), path, "version"); if(e < 0)return NULL; str = _plug_get_summary(plugin); e = safe_copy(str, plug.summary, sizeof(plug.summary), path, "summary"); if(e < 0)return NULL; str = _plug_get_description(plugin); e = safe_copy(str, plug.description, sizeof(plug.description), path, "description"); if(e < 0)return NULL; str = _plug_get_copyright(plugin); e = safe_copy(str, plug.copyright, sizeof(plug.copyright), path, "copyright"); if(e < 0)return NULL; str = _plug_get_family(plugin); e = safe_copy(str, plug.family, sizeof(plug.family), path, "family"); if(e < 0)return NULL; str = _plug_get_cve_id(plugin); e = safe_copy(str, plug.cve_id, sizeof(plug.cve_id), path, "cve_id"); if(e < 0)return NULL; str = _plug_get_bugtraq_id(plugin); e = safe_copy(str, plug.bid, sizeof(plug.bid), path, "bugtraq id"); if(e < 0)return NULL; str = _plug_get_xref(plugin); e = safe_copy(str, plug.xref, sizeof(plug.xref), path, "xref id"); if(e < 0)return NULL; arglist = _plug_get_deps(plugin); str = arglist2str(arglist); e = safe_copy(str, plug.dependencies, sizeof(plug.dependencies), path, "dependencies"); efree(&str); if(e < 0)return NULL; arglist = _plug_get_required_keys(plugin); str = arglist2str(arglist); e = safe_copy(str, plug.required_keys, sizeof(plug.required_keys), path, "required keys"); efree(&str); if(e < 0)return NULL; arglist = _plug_get_excluded_keys(plugin); str = arglist2str(arglist); e = safe_copy(str, plug.excluded_keys, sizeof(plug.excluded_keys), path, "excluded_keys"); efree(&str); if(e < 0)return NULL; arglist = _plug_get_required_ports(plugin); str = arglist2str(arglist); e = safe_copy(str, plug.required_ports, sizeof(plug.required_ports), path, "required ports"); efree(&str); if(e < 0)return NULL; arglist = _plug_get_required_udp_ports(plugin); str = arglist2str(arglist); e = safe_copy(str, plug.required_udp_ports, sizeof(plug.required_udp_ports), path, "required udp ports"); efree(&str); if(e < 0)return NULL; prefs = arg_get_value(plugin, "preferences"); arglist = arg_get_value(plugin, "PLUGIN_PREFS"); if( arglist != NULL ) { char * p_name = _plug_get_name(plugin); while(arglist->next != NULL) { char * name = arglist->name; char * dfl = arglist->value; char * type, * str; type = arglist->name; str = strchr(type, '/'); str[0] = '\0'; name = str + 1; e = safe_copy(type, pp[num_plugin_prefs].type, sizeof(pp[num_plugin_prefs].type), path, "preference-type"); if(e < 0)return NULL; e = safe_copy(name, pp[num_plugin_prefs].name, sizeof(pp[num_plugin_prefs].name), path, "preference-name"); if(e < 0)return NULL; e = safe_copy(dfl, pp[num_plugin_prefs].dfl, sizeof(pp[num_plugin_prefs].dfl), path, "preference-default"); if(e < 0)return NULL; num_plugin_prefs ++; if(num_plugin_prefs >= MAX_PREFS) { fprintf(stderr, "%s: too many preferences\n", path); return NULL; } _add_plugin_preference(prefs, p_name, name, type, dfl); str[0] = '/'; arglist = arglist->next; } } if(num_plugin_prefs > 0) plug.has_prefs = 1; fd = open(desc_file, O_RDWR|O_CREAT|O_TRUNC, 0644); if(fd < 0) { return NULL; } if(write(fd, &plug, sizeof(plug)) < 0) { perror("write "); } if(num_plugin_prefs > 0) { write(fd, pp, sizeof(pp)); } close(fd); ret = emalloc(sizeof(struct arglist)); plug_set_id(ret, _plug_get_id(plugin)); plug_set_category(ret, _plug_get_category(plugin)); plug_set_fname(ret, file); arg_add_value(ret, "preferences", ARG_ARGLIST, -1, arg_get_value(plugin, "preferences")); arg_set_value(plugin, "preferences", -1, NULL); arg_free_all(plugin); return ret; }
/** * @brief Set up some data and jump into attack_host() */ static void attack_start (struct attack_start_args *args) { struct arglist *globals = args->globals; char host_str[1024]; char *mac = args->host_mac_addr; struct arglist *plugs = arg_get_value (globals, "plugins"); struct in6_addr *hostip = &(args->hostip); struct arglist *hostinfos; struct arglist *preferences = arg_get_value (globals, "preferences"); char *non_simult = arg_get_value (preferences, "non_simult_ports"); char *vhosts = arg_get_value (preferences, "vhosts"); char *vhosts_ip = arg_get_value (preferences, "vhosts_ip"); int thread_socket = args->thread_socket; int soc; struct timeval then, now; plugins_scheduler_t sched = args->sched; int i; /* Stringify the IP address. */ if (IN6_IS_ADDR_V4MAPPED (&args->hostip)) inet_ntop (AF_INET, ((char *)(&args->hostip))+12, host_str, sizeof (host_str)); else inet_ntop (AF_INET6, &args->hostip, host_str, sizeof (host_str)); openvas_signal (SIGUSR1, attack_handle_sigusr1); openvas_signal (SIGUSR2, attack_handle_sigusr2); thread_socket = dup2 (thread_socket, 4); /* Close all file descriptors >= 6 */ for (i = 6; i < getdtablesize (); i++) close (i); gettimeofday (&then, NULL); if (non_simult == NULL) { non_simult = estrdup ("139, 445"); arg_add_value (preferences, "non_simult_ports", ARG_STRING, strlen (non_simult), non_simult); } arg_add_value (preferences, "non_simult_ports_list", ARG_ARGLIST, -1, (void *) list2arglist (non_simult)); /* Options regarding the communication with our parent */ openvas_deregister_connection (GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket"))); arg_set_value (globals, "global_socket", -1, GSIZE_TO_POINTER (thread_socket)); /* Wait for the server to confirm it read our data (prevents client desynch) */ arg_add_value (globals, "confirm", ARG_INT, sizeof (int), (void *) 1); soc = thread_socket; if (vhosts == NULL || vhosts_ip == NULL) hostinfos = attack_init_hostinfos (mac, host_str, hostip, args->fqdn); else { char *txt_ip; struct in_addr inaddr; inaddr.s_addr = hostip->s6_addr32[3]; if (IN6_IS_ADDR_V4MAPPED (hostip)) txt_ip = estrdup (inet_ntoa (inaddr)); else { char name[512]; txt_ip = estrdup (inet_ntop (AF_INET6, hostip, name, sizeof (name))); } if (strcmp (vhosts_ip, txt_ip) != 0) vhosts = NULL; hostinfos = attack_init_hostinfos_vhosts (mac, host_str, hostip, vhosts, args->fqdn); } if (mac) strcpy (host_str, mac); plugins_set_socket (plugs, soc); ntp_timestamp_host_scan_starts (globals, host_str); // Start scan attack_host (globals, hostinfos, host_str, sched); // Calculate duration, clean up ntp_timestamp_host_scan_ends (globals, host_str); gettimeofday (&now, NULL); if (now.tv_usec < then.tv_usec) { then.tv_sec++; now.tv_usec += 1000000; } log_write ("Finished testing %s. Time : %ld.%.2ld secs\n", host_str, (long) (now.tv_sec - then.tv_sec), (long) ((now.tv_usec - then.tv_usec) / 10000)); shutdown (soc, 2); close (soc); }
/** * @brief Attack a whole network. */ void attack_network (struct arglist *globals) { int max_hosts = 0, max_checks; int num_tested = 0; char *hostlist; openvas_hosts_t *hosts, *hosts_allow, *hosts_deny; openvas_hosts_t *sys_hosts_allow, *sys_hosts_deny; openvas_host_t *host; int global_socket = -1; struct arglist *preferences = NULL; struct arglist *plugins = NULL; plugins_scheduler_t sched; int fork_retries = 0; GHashTable *files; struct timeval then, now; char buffer[INET6_ADDRSTRLEN]; int network_phase = 0; gchar *network_targets, *port_range; int do_network_scan = 0; int scan_stopped; gettimeofday (&then, NULL); preferences = arg_get_value (globals, "preferences"); if ((do_network_scan = preferences_get_bool (preferences, "network_scan")) == -1) do_network_scan = 0; network_targets = arg_get_value (preferences, "network_targets"); if (network_targets != NULL) arg_add_value (globals, "network_targets", ARG_STRING, strlen (network_targets), network_targets); if (do_network_scan) { gchar *network_scan_status = arg_get_value (globals, "network_scan_status"); if (network_scan_status != NULL) if (g_ascii_strcasecmp (network_scan_status, "done") == 0) network_phase = 0; else network_phase = 1; else { arg_add_value (globals, "network_scan_status", ARG_STRING, strlen ("busy"), "busy"); network_phase = 1; } } num_tested = 0; global_socket = GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket")); plugins = arg_get_value (globals, "plugins"); /* Init and check Target List */ hostlist = arg_get_value (preferences, "TARGET"); if (hostlist == NULL) { error_message_to_client (globals, "Missing target hosts", NULL, NULL); return; } /* Verify the port range is a valid one */ port_range = arg_get_value (preferences, "port_range"); if (validate_port_range (port_range)) { error_message_to_client (globals, "Invalid port range", NULL, port_range); return; } /* Initialize the attack. */ sched = plugins_scheduler_init (plugins, preferences_get_bool (preferences, "auto_enable_dependencies") == 1 ? 1 : 0, network_phase); max_hosts = get_max_hosts_number (preferences); max_checks = get_max_checks_number (preferences); if (network_phase) { network_targets = arg_get_value (preferences, "network_targets"); if (network_targets == NULL) { log_write ("WARNING: In network phase, but without targets! Stopping.\n"); host = NULL; } else { log_write ("Start a new scan. Target(s) : %s, in network phase with target %s\n", hostlist, network_targets); } } else { log_write ("Starts a new scan. Target(s) : %s, with max_hosts = %d and" " max_checks = %d\n", hostlist, max_hosts, max_checks); } hosts = openvas_hosts_new (hostlist); /* Apply Hosts preferences. */ apply_hosts_preferences (hosts, preferences); /* Don't start if the provided interface is unauthorized. */ if (apply_source_iface_preference (globals, preferences) != 0) { openvas_hosts_free (hosts); error_message_to_client (globals, "Interface not authorized for scanning", NULL, NULL); return; } /* hosts_allow/deny lists. */ hosts_allow = openvas_hosts_new (preferences_get_string (preferences, "hosts_allow")); hosts_deny = openvas_hosts_new (preferences_get_string (preferences, "hosts_deny")); /* sys_* preferences, which can't be overriden by the client. */ sys_hosts_allow = openvas_hosts_new (preferences_get_string (preferences, "sys_hosts_allow")); sys_hosts_deny = openvas_hosts_new (preferences_get_string (preferences, "sys_hosts_deny")); host = openvas_hosts_next (hosts); if (host == NULL) goto stop; hosts_init (global_socket, max_hosts); /* * Start the attack ! */ while (host) { int pid; char *hostname; struct in6_addr host_ip; hostname = openvas_host_value_str (host); if (openvas_host_get_addr6 (host, &host_ip) == -1) { log_write ("Couldn't resolve target %s\n", hostname); error_message_to_client (globals, "Couldn't resolve hostname.", hostname, NULL); g_free (hostname); host = openvas_hosts_next (hosts); continue; } /* Do we have the right to test this host ? */ if (!host_authorized (host, &host_ip, hosts_allow, hosts_deny)) { error_message_to_client (globals, "Host access denied.", hostname, NULL); log_write ("Host %s access denied.", hostname); } else if (!host_authorized (host, &host_ip, sys_hosts_allow, sys_hosts_deny)) { error_message_to_client (globals, "Host access denied" " (system-wide restriction.)", hostname, NULL); log_write ("Host %s access denied (sys_* preference restriction.)", hostname); } else { struct attack_start_args args; int s; char *MAC = NULL; int mac_err = -1; gchar *name; if (preferences_get_bool (preferences, "use_mac_addr") > 0 && v6_is_local_ip (&host_ip)) { mac_err = v6_get_mac_addr (&host_ip, &MAC); if (mac_err > 0) { /* remote host is down */ g_free (hostname); host = openvas_hosts_next (hosts); continue; } } s = hosts_new (globals, hostname); if (s < 0) goto scan_stop; args.globals = globals; memcpy (&args.hostip, &host_ip, sizeof (struct in6_addr)); name = openvas_host_value_str (host); strncpy (args.fqdn, name, sizeof (args.fqdn)); g_free (name); args.host_mac_addr = MAC; args.sched = sched; args.thread_socket = s; forkagain: pid = create_process ((process_func_t) attack_start, &args); if (pid < 0) { fork_retries++; if (fork_retries > MAX_FORK_RETRIES) { /* Forking failed - we go to the wait queue. */ log_write ("fork() failed - %s. %s won't be tested\n", strerror (errno), hostname); efree (&MAC); goto stop; } log_write ("fork() failed - sleeping %d seconds and trying again...\n", fork_retries); fork_sleep (fork_retries); goto forkagain; } hosts_set_pid (hostname, pid); if (network_phase) log_write ("Testing %s (network level) [%d]\n", network_targets, pid); else log_write ("Testing %s (%s) [%d]\n", hostname, inet_ntop (AF_INET6, &args.hostip, buffer, sizeof (buffer)), pid); if (MAC != NULL) efree (&MAC); } num_tested++; if (network_phase) { host = NULL; arg_set_value (globals, "network_scan_status", strlen ("done"), "done"); } else { g_free (hostname); host = openvas_hosts_next (hosts); } } /* Every host is being tested... We have to wait for the processes * to terminate. */ while (hosts_read (globals) == 0) ; log_write ("Test complete"); scan_stop: /* Free the memory used by the files uploaded by the user, if any. */ files = arg_get_value (globals, "files_translation"); if (files) g_hash_table_foreach_remove (files, (GHRFunc) free_uploaded_file, NULL); stop: scan_stopped = GPOINTER_TO_SIZE(arg_get_value (globals, "stop_required")); openvas_hosts_free (hosts); openvas_hosts_free (hosts_allow); openvas_hosts_free (hosts_deny); openvas_hosts_free (sys_hosts_allow); openvas_hosts_free (sys_hosts_deny); plugins_scheduler_free (sched); gettimeofday (&now, NULL); log_write ("Total time to scan all hosts : %ld seconds\n", now.tv_sec - then.tv_sec); if (do_network_scan && network_phase && !scan_stopped) attack_network (globals); return; }
/** * @brief openvassd. * @param argc Argument count. * @param argv Argument vector. */ int main (int argc, char *argv[]) { int exit_early = 0, scanner_port = 9391; pid_t handler_pid; char *myself; struct arglist *options = emalloc (sizeof (struct arglist)); struct addrinfo *mysaddr; struct addrinfo hints; struct addrinfo ai; struct sockaddr_in saddr; struct sockaddr_in6 s6addr; proctitle_init (argc, argv); gcrypt_init (); if ((myself = strrchr (*argv, '/')) == 0) myself = *argv; else myself++; static gboolean display_version = FALSE; static gboolean dont_fork = FALSE; static gchar *address = NULL; static gchar *port = NULL; static gchar *config_file = NULL; static gchar *gnutls_priorities = "NORMAL"; static gchar *dh_params = NULL; static gboolean print_specs = FALSE; static gboolean print_sysconfdir = FALSE; static gboolean only_cache = FALSE; GError *error = NULL; GOptionContext *option_context; static GOptionEntry entries[] = { {"version", 'V', 0, G_OPTION_ARG_NONE, &display_version, "Display version information", NULL}, {"foreground", 'f', 0, G_OPTION_ARG_NONE, &dont_fork, "Do not run in daemon mode but stay in foreground", NULL}, {"listen", 'a', 0, G_OPTION_ARG_STRING, &address, "Listen on <address>", "<address>"}, {"port", 'p', 0, G_OPTION_ARG_STRING, &port, "Use port number <number>", "<number>"}, {"config-file", 'c', 0, G_OPTION_ARG_FILENAME, &config_file, "Configuration file", "<.rcfile>"}, {"cfg-specs", 's', 0, G_OPTION_ARG_NONE, &print_specs, "Print configuration settings", NULL}, {"sysconfdir", 'y', 0, G_OPTION_ARG_NONE, &print_sysconfdir, "Print system configuration directory (set at compile time)", NULL}, {"only-cache", 'C', 0, G_OPTION_ARG_NONE, &only_cache, "Exit once the NVT cache has been initialized or updated", NULL}, {"gnutls-priorities", '\0', 0, G_OPTION_ARG_STRING, &gnutls_priorities, "GnuTLS priorities string", "<string>"}, {"dh-params", '\0', 0, G_OPTION_ARG_STRING, &dh_params, "Diffie-Hellman parameters file", "<string>"}, {NULL} }; option_context = g_option_context_new ("- Scanner of the Open Vulnerability Assessment System"); g_option_context_add_main_entries (option_context, entries, NULL); if (!g_option_context_parse (option_context, &argc, &argv, &error)) { g_print ("%s\n\n", error->message); exit (0); } g_option_context_free (option_context); if (print_sysconfdir) { g_print ("%s\n", SYSCONFDIR); exit (0); } /* Switch to UTC so that OTP times are always in UTC. */ if (setenv ("TZ", "utc 0", 1) == -1) { g_print ("%s\n\n", strerror (errno)); exit (0); } tzset (); if (print_specs) exit_early = 2; /* no cipher initialization */ if (address != NULL) { memset (&hints, 0, sizeof (hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo (address, NULL, &hints, &mysaddr)) { printf ("Invalid IP address.\n"); printf ("Please use %s --help for more information.\n", myself); exit (0); } /* deep copy */ ai.ai_family = mysaddr->ai_family; if (ai.ai_family == AF_INET) { memcpy (&saddr, mysaddr->ai_addr, mysaddr->ai_addrlen); ai.ai_addr = (struct sockaddr *) &saddr; } else { memcpy (&s6addr, mysaddr->ai_addr, mysaddr->ai_addrlen); ai.ai_addr = (struct sockaddr *) &s6addr; } ai.ai_family = mysaddr->ai_family; ai.ai_protocol = mysaddr->ai_protocol; ai.ai_socktype = mysaddr->ai_socktype; ai.ai_addrlen = mysaddr->ai_addrlen; freeaddrinfo (mysaddr); } else { /* Default to IPv4 */ /*Warning: Not filling all the fields */ saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_family = ai.ai_family = AF_INET; ai.ai_addrlen = sizeof (saddr); ai.ai_addr = (struct sockaddr *) &saddr; } if (port != NULL) { scanner_port = atoi (port); if ((scanner_port <= 0) || (scanner_port >= 65536)) { printf ("Invalid port specification.\n"); printf ("Please use %s --help for more information.\n", myself); exit (1); } } if (display_version) { printf ("OpenVAS Scanner %s\n", OPENVASSD_VERSION); printf ("Nessus origin: (C) 2004 Renaud Deraison <*****@*****.**>\n"); printf ("Most new code since OpenVAS: (C) 2013 Greenbone Networks GmbH\n"); printf ("License GPLv2: GNU GPL version 2\n"); printf ("This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n\n"); exit (0); } if (config_file != NULL) arg_add_value (options, "acc_hint", ARG_INT, sizeof (int), (void *) 1); if (!config_file) { config_file = emalloc (strlen (OPENVASSD_CONF) + 1); strncpy (config_file, OPENVASSD_CONF, strlen (OPENVASSD_CONF)); } arg_add_value (options, "scanner_port", ARG_INT, sizeof (gpointer), GSIZE_TO_POINTER (scanner_port)); arg_add_value (options, "config_file", ARG_STRING, strlen (config_file), config_file); arg_add_value (options, "addr", ARG_PTR, -1, &ai); if (only_cache) { init_openvassd (options, 0, 1, dont_fork); init_plugins (options); exit (0); } init_openvassd (options, 1, exit_early, dont_fork); g_options = options; global_iana_socket = GPOINTER_TO_SIZE (arg_get_value (options, "isck")); global_plugins = arg_get_value (options, "plugins"); /* special treatment */ if (print_specs) dump_cfg_specs (global_preferences); if (exit_early) exit (0); init_ssl_ctx (gnutls_priorities, dh_params); // Daemon mode: if (dont_fork == FALSE) set_daemon_mode (); pidfile_create ("openvassd"); handler_pid = loading_handler_start (); init_plugins (options); loading_handler_stop (handler_pid); main_loop (); exit (0); }
struct arglist * store_load_plugin(char * dir, char * file, struct arglist * prefs) { char desc_file[PATH_MAX+1]; char plug_file[PATH_MAX+1]; char * str; char store_dir[PATH_MAX+1]; struct plugin p; struct pprefs pp[MAX_PREFS]; struct arglist * ret; int i; struct stat st1, st2; struct arglist * al; bzero(pp, sizeof(pp)); snprintf(desc_file, sizeof(desc_file), "%s/.desc/%s", dir, file); str = strrchr(desc_file, '.'); if( str != NULL ) { str[0] = '\0'; if( strlen(desc_file) + 6 < sizeof(desc_file) ) strcat(desc_file, ".desc"); } snprintf(plug_file, sizeof(plug_file), "%s/%s", dir, file); if ( stat(plug_file, &st1) < 0 || stat(desc_file, &st2) < 0 ) return NULL; /* * Look if the plugin is newer, and if that's the case also make sure that * the plugin mtime is not in the future... */ if ( st1.st_mtime > st2.st_mtime && st1.st_mtime <= time(NULL) ) return NULL; snprintf(store_dir, sizeof(store_dir), "%s/.desc", dir); if(store_get_plugin_f(&p, pp, store_dir, file) < 0) return NULL; if(p.magic != MAGIC) return NULL; if(p.id <= 0) return NULL; ret = emalloc(sizeof(struct arglist)); plug_set_id(ret, p.id); plug_set_category(ret, p.category); plug_set_fname(ret, file); plug_set_path(ret, p.path); plug_set_family(ret, p.family, NULL); al = str2arglist(p.required_ports); if ( al != NULL ) arg_add_value(ret, "required_ports", ARG_ARGLIST, -1, al); al = str2arglist(p.required_keys); if ( al != NULL ) arg_add_value(ret, "required_keys", ARG_ARGLIST, -1, al); al = str2arglist(p.required_udp_ports); if ( al != NULL ) arg_add_value(ret, "required_udp_ports", ARG_ARGLIST, -1, al) ; al = str2arglist(p.excluded_keys); if ( al != NULL ) arg_add_value(ret, "excluded_keys", ARG_ARGLIST, -1, al); al = str2arglist(p.dependencies); if ( al != NULL ) arg_add_value(ret, "DEPENDENCIES", ARG_ARGLIST, -1, al); if ( p.timeout != 0 ) arg_add_value(ret, "TIMEOUT", ARG_INT, -1, (void*)p.timeout); arg_add_value(ret, "NAME", ARG_STRING, strlen(p.name), estrdup(p.name)); arg_add_value(ret, "preferences", ARG_ARGLIST, -1, prefs); if(p.has_prefs) { for(i=0;pp[i].type[0] != '\0';i++) { _add_plugin_preference(prefs, p.name, pp[i].name, pp[i].type, pp[i].dfl); } } return ret; }
/** * @brief Inits or loads the knowledge base for a single host. * * Fills the knowledge base with host-specific login information for local * checks if defined. * * @param globals Global preference arglist. * @param hostname Name of the host. * @param new_kb[out] TRUE if the kb is new and shall be saved. * * @return A knowledge base. * * @see fill_host_kb_ssh_credentials */ static kb_t init_host_kb (struct arglist *globals, char *hostname, struct arglist *hostinfos, gboolean * new_kb) { kb_t kb, network_kb; (*new_kb) = FALSE; gchar *vhosts; struct kb_item *host_network_results = NULL; struct kb_item *result_iter; gchar *network_scan_status = (gchar *) arg_get_value (globals, "network_scan_status"); if (network_scan_status != NULL) { if (g_ascii_strcasecmp (network_scan_status, "done") == 0) { gchar *hostname_pattern = g_strdup_printf ("%s/*", hostname); network_kb = save_kb_load_kb (globals, "network"); host_network_results = kb_item_get_pattern (network_kb, hostname_pattern); } if (g_ascii_strcasecmp (network_scan_status, "busy") == 0) { arg_add_value (globals, "CURRENTLY_TESTED_HOST", ARG_STRING, strlen ("network"), "network"); save_kb_new (globals, "network"); kb = kb_new (); (*new_kb) = TRUE; return kb; } } // Check if kb should be saved. if (save_kb (globals)) { // Check if a saved kb exists and we shall restore it. if (save_kb_exists (hostname) != 0) { save_kb_backup (hostname); kb = save_kb_load_kb (globals, hostname); } else { // We shall not or cannot restore. save_kb_new (globals, hostname); kb = kb_new (); (*new_kb) = TRUE; } arg_add_value (globals, "CURRENTLY_TESTED_HOST", ARG_STRING, strlen (hostname), hostname); } else /* save_kb(globals) */ { kb = kb_new (); } /* Add local check (SSH)- related knowledge base items. */ fill_host_kb_ssh_credentials (kb, globals, hostname); /* If vhosts is set, split it and put it in the KB. */ vhosts = (gchar *)arg_get_value (hostinfos, "VHOSTS"); if (vhosts) { gchar **vhosts_array = g_strsplit (vhosts, ",", 0); guint i = 0; while (vhosts_array[i] != NULL) { kb_item_add_str (kb, "hostinfos/vhosts", vhosts_array[i]); save_kb_write_str (globals, hostname, "hostinfos/vhosts", vhosts_array[i]); i++; } g_strfreev (vhosts_array); } result_iter = host_network_results; while (result_iter != NULL) { char *newname = strstr (result_iter->name, "/") + 1; if (result_iter->type == KB_TYPE_STR) { kb_item_add_str (kb, newname, result_iter->v.v_str); save_kb_write_str (globals, hostname, newname, result_iter->v.v_str); } else if (result_iter->type == KB_TYPE_INT) { kb_item_add_int (kb, newname, result_iter->v.v_int); save_kb_write_int (globals, hostname, newname, result_iter->v.v_int); } result_iter = result_iter->next; } return kb; }
int execute_nasl_script(struct arglist * script_infos, const char* name, const char * cache_dir, int mode) { naslctxt ctx; nasl_func *pf; int err = 0; tree_cell *ret; lex_ctxt *lexic; char old_dir[MAXPATHLEN+1]; char *newdir; char *old; tree_cell tc; struct arglist* prefs = arg_get_value(script_infos, "preferences"); char *str; int to; char * basename; #ifdef ENABLE_PLUGIN_SERVER char * cached_script = NULL; unsigned int cached_script_len = 0; #endif srand48(getpid() + getppid() + (long)time(NULL)); old_dir[sizeof(old_dir) - 1] = '\0'; getcwd(old_dir, sizeof(old_dir) - 1); #if NASL_DEBUG > 2 nasl_trace_fp = stderr; #endif if((old = arg_get_value(script_infos, "script_name")) == NULL) arg_add_value(script_infos, "script_name", ARG_STRING, strlen(name), estrdup(name)); else { efree(&old); arg_set_value(script_infos, "script_name", strlen(name), estrdup(name)); } newdir = strrchr(name, '/'); if(newdir != NULL) { char dir[MAXPATHLEN+1]; char *s; dir[sizeof(dir) - 1] = '\0'; strncpy(dir, name, sizeof(dir) - 1); s = strrchr(dir, '/'); s[0] = '\0'; chdir(dir); basename = newdir + 1; } else basename = (char*)name; bzero(&ctx, sizeof(ctx)); if ( mode & NASL_ALWAYS_SIGNED ) ctx.always_authenticated = 1; #ifdef ENABLE_PLUGIN_SERVER if ( nasl_index_fetch(basename, &cached_script, &cached_script_len) >= 0 ) { if ( nasl_load_parsed_tree_buf(&ctx, cached_script, cached_script_len, basename) < 0 ) { printf("Could not load plugin\n"); efree(&cached_script); chdir(old_dir); return -1; } efree(&cached_script); } else #endif { if (nasl_load_or_parse(&ctx, name, basename, cache_dir) < 0 ) { chdir(old_dir); return -1; } } #if NASL_DEBUG > 4 nasl_dump_tree(ctx.tree); #endif lexic = init_empty_lex_ctxt(); lexic->script_infos = script_infos; if ( mode & NASL_ALWAYS_SIGNED ) lexic->authenticated = 1; else lexic->authenticated = ctx.authenticated; str = arg_get_value(prefs, "checks_read_timeout"); if( str != NULL ) to = atoi(str); else to = 5; if(to <= 0)to = 5; lexic->recv_timeout = to; init_nasl_library(lexic); if (mode & NASL_LINT) { if (nasl_lint(lexic, ctx.tree) == NULL) err --; } else if (! (mode & NASL_EXEC_PARSE_ONLY)) { char *p; bzero(&tc, sizeof(tc)); tc.type = CONST_INT; tc.x.i_val = (mode & NASL_COMMAND_LINE) != 0; add_named_var_to_ctxt(lexic, "COMMAND_LINE", &tc); bzero(&tc, sizeof(tc)); tc.type = CONST_INT; tc.x.i_val = (mode & NASL_EXEC_DESCR) != 0; add_named_var_to_ctxt(lexic, "description", &tc); tc.type = CONST_DATA; p = strrchr(name, '/'); if (p == NULL) p = (char*)name; else p ++; tc.x.str_val = p; tc.size = strlen(p); add_named_var_to_ctxt(lexic, "SCRIPT_NAME", &tc); truc = (lex_ctxt*)ctx.tree; if ((ret = nasl_exec(lexic, ctx.tree)) == NULL) err = -1; else deref_cell(ret); if ((pf = get_func_ref_by_name(lexic, "on_exit")) != NULL) nasl_func_call(lexic, pf, NULL); } #if NASL_DEBUG > 2 { struct rusage ru; if (getrusage(RUSAGE_SELF, &ru) < 0) perror("getrusage"); else { nasl_perror(lexic, "rusage: utime=%d.%03d stime=%d.%03d minflt=%d majflt=%d nswap=%d\n", ru.ru_utime.tv_sec, ru.ru_utime.tv_usec / 1000, ru.ru_stime.tv_sec, ru.ru_stime.tv_usec / 1000, ru.ru_minflt, ru.ru_majflt, ru.ru_nswap); } } #endif #if NASL_DEBUG > 3 nasl_dump_tree(ctx.tree); #endif chdir(old_dir); if ( mode & NASL_EXEC_DONT_CLEANUP ) return err; nasl_clean_ctx(&ctx); free_lex_ctxt(lexic); return err; }