/* Nessus Attack Scripting Language * * Copyright (C) 2002 - 2004 Tenable Network Security * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * This file contains all the misc. functions found in NASL */ #include "includes.h" #include "nasl_tree.h" #include "nasl_global_ctxt.h" #include "nasl_func.h" #include "nasl_var.h" #include "nasl_lex_ctxt.h" #include "exec.h" #include "strutils.h" #include "nasl_packet_forgery.h" #include "nasl_debug.h" #include "nasl_misc_funcs.h" /*---------------------------------------------------------------------*/ tree_cell * nasl_rand(lex_ctxt * lexic) { tree_cell * retc; retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = lrand48(); return retc; } /*---------------------------------------------------------------------*/ tree_cell * nasl_usleep(lex_ctxt * lexic) { int slp = get_int_var_by_num(lexic, 0, 0); usleep(slp); return FAKE_CELL; } tree_cell * nasl_sleep(lex_ctxt * lexic) { int slp = get_int_var_by_num(lexic, 0, 0); sleep(slp); return FAKE_CELL; } /*---------------------------------------------------------------------*/ tree_cell * nasl_ftp_log_in(lex_ctxt * lexic) { char * u, *p; int soc; tree_cell *retc; int res; soc = get_int_local_var_by_name(lexic, "socket", 0); if(soc <= 0) return NULL; u = get_str_local_var_by_name(lexic, "user"); if( u == NULL ) u = ""; p = get_str_local_var_by_name(lexic, "pass"); if( p == NULL ) p = ""; res = ftp_log_in(soc, u, p) == 0; retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = res; return retc; } tree_cell * nasl_ftp_get_pasv_address(lex_ctxt * lexic) { int soc; struct sockaddr_in addr; tree_cell * retc; soc = get_int_local_var_by_name(lexic, "socket", 0); if(soc <= 0) return NULL; bzero(&addr, sizeof(addr)); ftp_get_pasv_address(soc, &addr); retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = ntohs(addr.sin_port); return retc; } /*---------------------------------------------------------------------*/ tree_cell * nasl_telnet_init(lex_ctxt * lexic) { int soc = get_int_var_by_num(lexic, 0, -1); int opts; /* number of options recorded */ unsigned char buffer[1024]; #define iac buffer[0] #define code buffer[1] #define option buffer[2] tree_cell * retc; int n = 0, n2; int lm = 0; if(soc <= 0 ) { nasl_perror(lexic, "Syntax error in the telnet_init() function\n"); nasl_perror(lexic, "Correct syntax is : output = telnet_init()\n"); return NULL; } iac = 255; opts = 0; while(iac == 255) { n = read_stream_connection_min(soc, buffer, 3, 3); if((iac!=255)||(n<=0)||(n!=3))break; if((code == 251)||(code == 252))code = 254; /* WILL , WONT -> DON'T */ else if((code == 253)||(code == 254))code = 252; /* DO,DONT -> WONT */ write_stream_connection(soc, buffer,3); if ( lm == 0 ) { code = 253; option = 0x22; write_stream_connection(soc, buffer,3); lm ++; } opts++; if (opts>100) break; } if (n <= 0) { if (opts == 0) return NULL; else n = 0; } if (opts>100) /* remote telnet server is crazy */ { nasl_perror(lexic, "More than 100 options received by telnet_init() function! exiting telnet_init.\n"); return NULL; } n2 = read_stream_connection(soc, buffer + n, sizeof(buffer) - n); if (n2 > 0) n += n2; retc = alloc_typed_cell(CONST_DATA); retc->size = n; retc->x.str_val = nasl_strndup((char*)buffer, n); #undef iac #undef data #undef option return retc; } /*---------------------------------------------------------------------*/ 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; } tree_cell * nasl_end_denial(lex_ctxt * lexic) { int port = (int)arg_get_value(lexic->script_infos, "denial_port"); int soc; int to = lexic->recv_timeout; struct arglist * script_infos = lexic->script_infos; tree_cell * retc = NULL; /* * We must wait the time the DoS does its effect */ sleep(10); if(!port) { int ping = (int)arg_get_value(script_infos, "tcp_ping_result"); if(ping) return nasl_tcp_ping(lexic); else { retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = 1; return retc; } } else { retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; soc = open_stream_connection(script_infos, port, NESSUS_ENCAPS_IP, to); if(soc > 0) { /* Send some data */ #define BOGUS "are you dead ?" if((nsend(soc, BOGUS, sizeof(BOGUS)-1, 0))>=0) { retc->x.i_val = 1; close_stream_connection(soc); return retc; } } } retc->x.i_val = 0; return retc; } /*---------------------------------------------------------------------*/ tree_cell* nasl_dump_ctxt(lex_ctxt* lexic) { dump_ctxt(lexic->up_ctxt); return FAKE_CELL; } tree_cell* nasl_do_exit(lex_ctxt* lexic) { int x = get_int_var_by_num(lexic, 0, 0); tree_cell *retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = x; while (lexic != NULL) { lexic->ret_val = retc; ref_cell(retc); lexic = lexic->up_ctxt; } return retc; } /*---------------------------------------------------------------------*/ tree_cell* nasl_isnull(lex_ctxt* lexic) { int t; tree_cell *retc; t = get_var_type_by_num(lexic, 0); retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = (t == VAR2_UNDEF); return retc; } /* * This function takes any kind & any number of arguments and makes * an array from them. * If an argument is an array, its index are lost */ tree_cell* nasl_make_list(lex_ctxt* lexic) { tree_cell *retc = NULL; int i, j, vi; anon_nasl_var *v; named_nasl_var *vn; nasl_array *a, *a2; retc = alloc_tree_cell(0, NULL); retc->type = DYN_ARRAY; retc->x.ref_val = a = emalloc(sizeof(nasl_array)); for (i = vi = 0; (v = nasl_get_var_by_num(&lexic->ctx_vars, vi, 0)) != NULL; vi ++) { switch (v->var_type) { case VAR2_INT: case VAR2_STRING: case VAR2_DATA: add_var_to_list(a, i ++, v); break; case VAR2_ARRAY: a2 = &v->v.v_arr; for (j = 0; j < a2->max_idx; j ++) if (add_var_to_list(a, i, a2->num_elt[j]) >= 1) i ++; if (a2->hash_elt != NULL) { #if NASL_DEBUG > 1 nasl_perror(lexic, "make_list: named arguments in array have no order\n"); #endif for (j = 0; j < VAR_NAME_HASH; j++) for (vn = a2->hash_elt[j]; vn != NULL; vn = vn->next_var) if (vn->u.var_type != VAR2_UNDEF) if (add_var_to_list(a, i , &vn->u) >= 1) i ++; } break; case VAR2_UNDEF: nasl_perror(lexic, "nasl_make_list: undefined variable #%d skipped\n", i); continue; default: nasl_perror(lexic, "nasl_make_list: unhandled variable type 0x%x - skipped\n", v->var_type); continue; } } return retc; } /* * This function takes any _even_ number of arguments and makes * an array from them. In each pair, the 1st argument is the index, the * 2nd the value. * Illegal types are droped with a warning */ tree_cell* nasl_make_array(lex_ctxt* lexic) { tree_cell *retc = NULL; int i, vi; anon_nasl_var *v, *v2; nasl_array *a; retc = alloc_tree_cell(0, NULL); retc->type = DYN_ARRAY; retc->x.ref_val = a = emalloc(sizeof(nasl_array)); i = vi = 0; while ((v = nasl_get_var_by_num(&lexic->ctx_vars, vi ++, 0)) != NULL) { v2 = nasl_get_var_by_num(&lexic->ctx_vars, vi ++, 0); if (v2 == NULL) { nasl_perror(lexic, "make_array: odd number (%d) of argument?\n", vi); break; } switch (v2->var_type) { case VAR2_INT: case VAR2_STRING: case VAR2_DATA: switch (v->var_type) { case VAR2_INT: add_var_to_list(a, v->v.v_int, v2); break; case VAR2_STRING: case VAR2_DATA: add_var_to_array(a, (char*)var2str(v) , v2); break; } break; case VAR2_UNDEF: default: nasl_perror(lexic, "make_array: bad value type %d for arg #%d\n", v2->var_type, vi); break; } } return retc; } tree_cell* nasl_keys(lex_ctxt* lexic) { tree_cell *retc = NULL; anon_nasl_var *v, myvar; named_nasl_var *vn; nasl_array *a, *a2; int i, j, vi; retc = alloc_tree_cell(0, NULL); retc->type = DYN_ARRAY; retc->x.ref_val = a2 = emalloc(sizeof(nasl_array)); bzero(&myvar, sizeof(myvar)); for (i = vi = 0; (v = nasl_get_var_by_num(&lexic->ctx_vars, vi, 0)) != NULL; vi ++) { if (v->var_type == VAR2_ARRAY) { a = &v->v.v_arr; /* First the numerical index */ for (j = 0; j < a->max_idx; j ++) if (a->num_elt[j] != NULL && a->num_elt[j]->var_type != VAR2_UNDEF) { myvar.var_type = VAR2_INT; myvar.v.v_int = j; add_var_to_list(a2, i ++, &myvar); } /* Then the string index */ if (a->hash_elt != NULL) for (j = 0; j < VAR_NAME_HASH; j++) for (vn = a->hash_elt[j]; vn != NULL; vn = vn->next_var) if (vn->u.var_type != VAR2_UNDEF) { myvar.var_type = VAR2_STRING; myvar.v.v_str.s_val = (unsigned char*)vn->var_name; myvar.v.v_str.s_siz = strlen(vn->var_name); add_var_to_list(a2, i ++, &myvar); } } else nasl_perror(lexic, "nasl_keys: bad variable #%d skipped\n", vi); } return retc; } tree_cell* nasl_max_index(lex_ctxt* lexic) { tree_cell *retc; anon_nasl_var *v; nasl_array *a; v = nasl_get_var_by_num(&lexic->ctx_vars, 0, 0); if (v == NULL) return NULL; if (v->var_type != VAR2_ARRAY) return NULL; a = &v->v.v_arr; retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = array_max_index(a); return retc; } tree_cell* nasl_typeof(lex_ctxt* lexic) { tree_cell *retc; anon_nasl_var *u; const char* s; retc = alloc_tree_cell(0, NULL); retc->type = CONST_DATA; u = nasl_get_var_by_num(&lexic->ctx_vars, 0, 0); if (u == NULL) s = "null"; else switch (u->var_type) { case VAR2_UNDEF: s= "undef"; break; case VAR2_INT: s = "int"; break; case VAR2_STRING: s = "string"; break; case VAR2_DATA: s = "data"; break; case VAR2_ARRAY: s = "array"; break; default: s = "unknown"; break; } retc->size = strlen(s); retc->x.str_val = emalloc(retc->size); strcpy(retc->x.str_val, s); return retc; } tree_cell* nasl_defined_func(lex_ctxt* lexic) { void *f; char *s; tree_cell *retc; s = get_str_var_by_num(lexic, 0); if (s == NULL) { nasl_perror(lexic, "defined_func: missing parameter\n"); return NULL; } f = get_func_ref_by_name(lexic, s); retc = alloc_tree_cell(0, NULL); retc->type = CONST_INT; retc->x.i_val = (f != NULL); return retc; } tree_cell* nasl_func_named_args(lex_ctxt* lexic) { nasl_func *f; char *s; int i; tree_cell *retc; nasl_array *a; anon_nasl_var v; s = get_str_var_by_num(lexic, 0); if (s == NULL) { nasl_perror(lexic, "func_named_args: missing parameter\n"); return NULL; } f = get_func_ref_by_name(lexic, s); if (f == NULL) { nasl_perror(lexic, "func_named_args: unknown function \"%s\"\n", s); return NULL; } retc = alloc_typed_cell(DYN_ARRAY); retc->x.ref_val = a = emalloc(sizeof(nasl_array)); memset(&v, 0, sizeof(v)); v.var_type = VAR2_STRING; for (i = 0; i < f->nb_named_args; i ++) { v.v.v_str.s_val = (unsigned char*)f->args_names[i]; v.v.v_str.s_siz = strlen(f->args_names[i]); if (add_var_to_list(a, i, &v) < 0) nasl_perror(lexic, "func_named_args: add_var_to_list failed (internal error)\n"); } return retc; } tree_cell* nasl_func_unnamed_args(lex_ctxt* lexic) { nasl_func *f; char *s; tree_cell *retc; s = get_str_var_by_num(lexic, 0); if (s == NULL) { nasl_perror(lexic, "func_unnamed_args: missing parameter\n"); return NULL; } f = get_func_ref_by_name(lexic, s); if (f == NULL) { nasl_perror(lexic, "func_unnamed_args: unknown function \"%s\"\n", s); return NULL; } retc = alloc_typed_cell(CONST_INT); retc->x.i_val = f->nb_unnamed_args; return retc; } tree_cell* nasl_func_has_arg(lex_ctxt* lexic) { nasl_func *f; char *s; int vt, i, flag = 0; tree_cell *retc; s = get_str_var_by_num(lexic, 0); if (s == NULL) { nasl_perror(lexic, "func_has_arg: missing parameter\n"); return NULL; } f = get_func_ref_by_name(lexic, s); if (f == NULL) { nasl_perror(lexic, "func_args: unknown function \"%s\"\n", s); return NULL; } vt = get_var_type_by_num(lexic, 1); switch(vt) { case VAR2_INT: i = get_int_var_by_num(lexic, 1, -1); if (i >= 0 && i < f->nb_unnamed_args) flag = 1; break; case VAR2_STRING: case VAR2_DATA: s = get_str_var_by_num(lexic, 1); for (i = 0; i < f->nb_named_args && ! flag; i ++) if (strcmp(s, f->args_names[i]) == 0) flag = 1; break; default: nasl_perror(lexic, "func_has_arg: string or integer expected as 2nd parameter\n"); return NULL; } retc = alloc_typed_cell(CONST_INT); retc->x.i_val = flag; return retc; } /* Sorts an array */ static lex_ctxt *mylexic = NULL; static int var_cmp(const void * a, const void * b) { anon_nasl_var ** pv1 = (anon_nasl_var **)a, ** pv2 = (anon_nasl_var**)b; tree_cell *t1, *t2; t1 = var2cell((anon_nasl_var*)*pv1); t2 = var2cell((anon_nasl_var*)*pv2); return cell_cmp(mylexic, t1, t2); } tree_cell* nasl_sort_array(lex_ctxt* lexic) { tree_cell *retc = NULL; nasl_array *a; if (mylexic != NULL) { nasl_perror(lexic, "sort: this function is not reentrant!\n"); return NULL; } mylexic = lexic; retc = nasl_make_list(lexic); if (retc != NULL) { a = retc->x.ref_val; qsort(a->num_elt, a->max_idx, sizeof(a->num_elt[0]), var_cmp); } mylexic = NULL; return retc; } tree_cell* nasl_unixtime(lex_ctxt* lexic) { tree_cell *retc; retc = alloc_typed_cell(CONST_INT); retc->x.i_val = time(NULL); return retc; } tree_cell* nasl_gettimeofday(lex_ctxt* lexic) { tree_cell *retc; struct timeval t; char str[64]; if (gettimeofday(&t, NULL) < 0) { nasl_perror(lexic, "gettimeofday: %s\n", strerror(errno)); return NULL; } sprintf(str, "%u.%06u", t.tv_sec, t.tv_usec); retc = alloc_typed_cell(CONST_DATA); retc->size = strlen(str); retc->x.str_val = emalloc(retc->size); strcpy(retc->x.str_val, str); return retc; } tree_cell* nasl_localtime(lex_ctxt* lexic) { tree_cell *retc; struct tm *ptm; time_t tictac; int utc; nasl_array *a; anon_nasl_var v; tictac = get_int_var_by_num(lexic, 0, 0); if (tictac == 0) tictac = time(NULL); utc = get_int_local_var_by_name(lexic, "utc", 0); if (utc) ptm = gmtime(&tictac); else ptm = localtime(&tictac); if (ptm == NULL) { nasl_perror(lexic, "localtime(%d,utc=%d): %s\n", tictac, utc, strerror(errno)); return NULL; } retc = alloc_typed_cell(DYN_ARRAY); retc->x.ref_val = a = emalloc(sizeof(nasl_array)); memset(&v, 0, sizeof(v)); v.var_type = VAR2_INT; v.v.v_int = ptm->tm_sec; add_var_to_array(a, "sec", &v); /* seconds */ v.v.v_int = ptm->tm_min; add_var_to_array(a, "min", &v); /* minutes */ v.v.v_int = ptm->tm_hour; add_var_to_array(a, "hour", &v); /* hours */ v.v.v_int = ptm->tm_mday; add_var_to_array(a, "mday", &v); /* day of the month */ v.v.v_int = ptm->tm_mon+1; add_var_to_array(a, "mon", &v); /* month */ v.v.v_int = ptm->tm_year+1900; add_var_to_array(a, "year", &v); /* year */ v.v.v_int = ptm->tm_wday; add_var_to_array(a, "wday", &v); /* day of the week */ v.v.v_int = ptm->tm_yday+1; add_var_to_array(a, "yday", &v); /* day in the year */ v.v.v_int = ptm->tm_isdst; add_var_to_array(a, "isdst", &v); /* daylight saving time */ return retc; } tree_cell* nasl_mktime(lex_ctxt* lexic) { struct tm tm; tree_cell *retc; time_t tictac; tm.tm_sec = get_int_local_var_by_name(lexic, "sec", 0); /* seconds */ tm.tm_min = get_int_local_var_by_name(lexic, "min", 0); /* minutes */ tm.tm_hour = get_int_local_var_by_name(lexic, "hour", 0); /* hours */ tm.tm_mday = get_int_local_var_by_name(lexic, "mday", 0); /* day of the month */ tm.tm_mon = get_int_local_var_by_name(lexic, "mon", 1); /* month */ tm.tm_mon -= 1; tm.tm_year = get_int_local_var_by_name(lexic, "year", 0); /* year */ if (tm.tm_year >= 1900) tm.tm_year -= 1900; tm.tm_isdst = get_int_local_var_by_name(lexic, "isdst", -1); /* daylight saving time */ errno = 0; tictac = mktime(&tm); if (tictac == (time_t)(-1)) { nasl_perror(lexic, "mktime(sec=%02d min=%02d hour=%02d mday=%02d mon=%02d year=%04d isdst=%d): %s\n", tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_isdst, errno ? strerror(errno): "invalid value?"); return NULL; } retc = alloc_typed_cell(CONST_INT); retc->x.i_val = tictac; return retc; } tree_cell* nasl_open_sock_kdc(lex_ctxt* lexic) { tree_cell *retc; struct timeval t; int timeout = 30; int port = 88; char *hostname = NULL; /* Domain name for windows */ int tcp = 0; int ret; struct arglist *script_infos, *prefs; char *_port = NULL, *_tcp = NULL; char * val; int type; script_infos = lexic->script_infos; hostname = plug_get_key(script_infos, "Secret/kdc_hostname", &type); if ( ! hostname || type != KB_TYPE_STR ) return NULL; port = (int)plug_get_key(script_infos, "Secret/kdc_port", &type); if ( port <= 0 || type != KB_TYPE_INT ) return NULL; tcp = (int)plug_get_key(script_infos, "Secret/kdc_use_tcp", &type); if ( tcp < 0 || type != KB_TYPE_INT ) tcp = 0; if (tcp == 0) ret = open_sock_opt_hn(hostname, port, SOCK_DGRAM, IPPROTO_UDP, timeout); else ret = open_sock_opt_hn(hostname, port, SOCK_STREAM, IPPROTO_TCP, timeout); if (ret < 0) return NULL; retc = alloc_typed_cell(CONST_INT); retc->x.i_val = ret; return retc; }