/** Statically analyse the given ast. * * \param ast_ The AST. * \param in_object Whether or not ast_ is within the lexical scope of an object AST. * \param vars The variables defined within lexical scope of ast_. * \returns The free variables in ast_. */ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) { IdSet r; if (auto *ast = dynamic_cast<const Apply*>(ast_)) { append(r, static_analysis(ast->target, in_object, vars)); for (AST *arg : ast->arguments) append(r, static_analysis(arg, in_object, vars)); } else if (auto *ast = dynamic_cast<const Array*>(ast_)) { for (AST *el : ast->elements) append(r, static_analysis(el, in_object, vars)); } else if (auto *ast = dynamic_cast<const Binary*>(ast_)) { append(r, static_analysis(ast->left, in_object, vars)); append(r, static_analysis(ast->right, in_object, vars)); } else if (dynamic_cast<const BuiltinFunction*>(ast_)) { // Nothing to do. } else if (auto *ast = dynamic_cast<const Conditional*>(ast_)) { append(r, static_analysis(ast->cond, in_object, vars)); append(r, static_analysis(ast->branchTrue, in_object, vars)); append(r, static_analysis(ast->branchFalse, in_object, vars)); } else if (auto *ast = dynamic_cast<const Error*>(ast_)) { return static_analysis(ast->expr, in_object, vars); } else if (auto *ast = dynamic_cast<const Function*>(ast_)) { auto new_vars = vars; IdSet params; for (auto *p : ast->parameters) { if (params.find(p) != params.end()) { throw StaticError(ast_->location, "Duplicate function parameter: " + p->name); } params.insert(p); new_vars.insert(p); } auto fv = static_analysis(ast->body, in_object, new_vars); for (auto *p : ast->parameters) fv.erase(p); append(r, fv); } else if (dynamic_cast<const Import*>(ast_)) { // Nothing to do. } else if (dynamic_cast<const Importstr*>(ast_)) { // Nothing to do. } else if (auto *ast = dynamic_cast<const Index*>(ast_)) { append(r, static_analysis(ast->target, in_object, vars)); append(r, static_analysis(ast->index, in_object, vars)); } else if (auto *ast = dynamic_cast<const Local*>(ast_)) { IdSet ast_vars; for (const auto &bind: ast->binds) { ast_vars.insert(bind.first); } auto new_vars = vars; append(new_vars, ast_vars); IdSet fvs; for (const auto &bind: ast->binds) append(fvs, static_analysis(bind.second, in_object, new_vars)); append(fvs, static_analysis(ast->body, in_object, new_vars)); for (const auto &bind: ast->binds) fvs.erase(bind.first); append(r, fvs); } else if (dynamic_cast<const LiteralBoolean*>(ast_)) { // Nothing to do. } else if (dynamic_cast<const LiteralNumber*>(ast_)) { // Nothing to do. } else if (dynamic_cast<const LiteralString*>(ast_)) { // Nothing to do. } else if (dynamic_cast<const LiteralNull*>(ast_)) { // Nothing to do. } else if (auto *ast = dynamic_cast<Object*>(ast_)) { for (auto field : ast->fields) { append(r, static_analysis(field.name, in_object, vars)); append(r, static_analysis(field.body, true, vars)); } } else if (auto *ast = dynamic_cast<ObjectComposition*>(ast_)) { auto new_vars = vars; new_vars.insert(ast->id); append(r, static_analysis(ast->field, false, new_vars)); append(r, static_analysis(ast->value, true, new_vars)); r.erase(ast->id); append(r, static_analysis(ast->array, in_object, vars)); } else if (dynamic_cast<const Self*>(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use self outside of an object."); } else if (dynamic_cast<const Super*>(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use super outside of an object."); } else if (auto *ast = dynamic_cast<const Unary*>(ast_)) { append(r, static_analysis(ast->expr, in_object, vars)); } else if (auto *ast = dynamic_cast<const Var*>(ast_)) { if (vars.find(ast->id) == vars.end()) { throw StaticError(ast->location, "Unknown variable: "+ast->id->name); } r.insert(ast->id); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); } for (auto *id : r) ast_->freeVariables.push_back(id); return r; }
int main (int argc, char **argv) { int c, valid, bnr = 9, showpopup = 0, flags = 0; /* temporary vars */ char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ libnet_t *l; /* libnet handle for address retrieval */ char libnet_errbuf[LIBNET_ERRBUF_SIZE]; /* libnet error messages */ char start_time[24], end_time[24]; time_t acurtime, bcurtime; struct tm *aloctime, *bloctime; struct configuration conf, *config=&conf; /* struct to hold config for current session */ struct validated_queue *start = NULL, *end = NULL; /* pointers to validated queue */ /* get current system time */ acurtime = time (NULL); /* convert it to local time representation */ aloctime = localtime (&acurtime); /* format time struct into a char array */ strftime (start_time, 24, "%d/%b/%Y %H:%M:%S", aloctime); /* load default params in config struct */ config->flags = 0; config->verbose = 0; config->queue_size = 0; config->dev = NULL; config->dport = HTTP; config->mode = DETECT; config->gtimeout = TIME_OUT; config->scan_type = SYN_SCAN; config->a_port_name = "HTTP"; config->a_scan_type = "SYN_SCAN"; /* parse and load cmd-line params in config struct */ while ((c = getopt (argc, argv, "hi:p:Parsfuetvg:o")) != -1) { switch (c) { case 'h': print_usage (); exit (EXIT_SUCCESS); case 'i': config->dev = optarg; break; case 'p': if (1 <= atoi (optarg) && 65535 >= atoi (optarg)) { config->dport = atoi (optarg); } break; case 'P': config->mode = PREVENT; break; case 'a': config->scan_type = ACK_SCAN; config->flags = config->flags | ACK; flags = flags | ACK; break; case 'r': config->scan_type = RST_SCAN; config->flags = config->flags | RST; flags = flags | RST; break; case 's': config->scan_type = SYN_SCAN; config->flags = config->flags | SYN; flags = flags | SYN; break; case 'f': config->scan_type = FIN_SCAN; config->flags = config->flags | FIN; flags = flags | FIN; break; case 'u': config->scan_type = UDP_SCAN; config->a_scan_type = "UDP_SCAN"; break; case 'e': config->scan_type = ECHO_SCAN; config->a_scan_type = "ECHO_SCAN"; break; case 't': config->scan_type = TSTAMP_SCAN; config->a_scan_type = "TSTAMP_SCAN"; break; case 'v': config->verbose = 1; break; case 'g': if (1 <= atoi (optarg) && 9 >= atoi (optarg)) { config->gtimeout = atoi (optarg); } break; case 'o': showpopup = 1; break; case '?': if ('i' == optopt || 'p' == optopt) { print_usage (); exit (EXIT_FAILURE); } else if (isprint (optopt)) { printf ("\n [-] unknown option `-%c'\n", optopt); print_usage (); exit (EXIT_FAILURE); } else { printf ("\n unknown option character `\\x%x'\n", optopt); print_usage (); exit (EXIT_FAILURE); } default: print_usage (); exit (EXIT_FAILURE); } } if (0 == flags) { config->flags = SYN; } else if (ACK == flags) { config->a_scan_type = "ACK_SCAN"; } else if (RST == flags) { config->a_scan_type = "RST_SCAN"; } else if (SYN == flags) { config->a_scan_type = "SYN_SCAN"; } else if (FIN == flags) { config->a_scan_type = "FIN_SCAN"; } /* print an ASCII-ART banner */ print_banner (); switch (config->dport) { case HTTP: config->a_port_name = "HTTP"; break; case FTP: config->a_port_name = "FTP"; break; case TELNET: config->a_port_name = "TELNET"; break; case SSH: config->a_port_name = "SSH"; break; case SMTP: config->a_port_name = "SMTP"; break; default: config->a_port_name = "UNKNOWN"; break; } /* check if we are root, else exit */ if (0 != getuid ()) { printf ("\n [!] you need to be root buddy...\n\n"); exit (EXIT_FAILURE); } /* find a capture device if not specified on command-line */ if (config->dev == NULL) { config->dev = pcap_lookupdev (errbuf); if (config->dev == NULL) { printf ("\n [-] could not find default device: %s\n\n", errbuf); exit (EXIT_FAILURE); } } /* initialize libnet library to find local mac and ip addresses */ l = libnet_init (LIBNET_LINK, config->dev, libnet_errbuf); if (NULL == l) { printf ("\n [-] libnet_init() failed: %s\n\n", libnet_errbuf); exit (EXIT_FAILURE); } /* fetch local mac address */ config->macaddr = libnet_get_hwaddr (l); if (NULL == config->macaddr) { printf ("\n [-] could not fetch local mac address: %s\n\n", libnet_geterror (l)); libnet_destroy (l); exit (EXIT_FAILURE); } else { snprintf (config->llmac, 18, "%02x:%02x:%02x:%02x:%02x:%02x", config->macaddr->ether_addr_octet[0], config->macaddr->ether_addr_octet[1], config->macaddr->ether_addr_octet[2], config->macaddr->ether_addr_octet[3], config->macaddr->ether_addr_octet[4], config->macaddr->ether_addr_octet[5]); } /* fetch local ip address */ config->ipaddr = libnet_get_ipaddr4 (l); if (-1 == config->ipaddr) { printf ("\n [-] could not fetch local ip address: %s\n\n", libnet_geterror (l)); libnet_destroy (l); exit (EXIT_FAILURE); } else { snprintf (config->llip, 16, "%s", libnet_addr2name4 (config->ipaddr, LIBNET_DONT_RESOLVE)); } printf (" [+] session started at %s \n", start_time); printf (" [+] default configuration and cmd-line parameters loaded\n"); printf (" [+] device: \"%s\", mode: \"%s\", port: \"%s\", scan-type: \"%s\"\n", config->dev, (config->mode)? "PREVENT" : "DETECT", config->a_port_name, config->a_scan_type); /* start repeat loop */ /* call sniffer module to fill up our config struct with packet fields */ printf (" [+] calling arp-sniffer module to capture incoming arp packets\n"); config = sniffer (config); printf ("\n [+] above arp packet was captured and respective fields were saved for analysis\n"); printf (" [+] calling anamoly-detection module to perform static analysis on saved packet fields\n"); /* call static_analysis module to perform some static checks on packet fields */ valid = static_analysis (conf); if (EXIT_FAILURE == valid) { printf (" [+] analyzed arp packet seems to be specially-crafted. kernel might have added the" " poisonous SIP-SMAC entry in arp cache\n"); if (DETECT == conf.mode) { printf (" [+] you need to clean up arp cache manually. delete entry for SIP (%s) - SMAC (%s)\n", conf.a_sip, conf.a_sha); printf (" [+] to automate this process, please terminate this session and restart arp-secur" " in PREVENT mode, i.e with -P switch\n"); } else if (PREVENT == conf.mode) { printf (" [+] cleaning up arp cache by deleting entry for SIP (%s) - SMAC (%s)\n", conf.a_sip, conf.a_sha); cache_cleanup (conf.a_sip, conf.a_sha); } } else { printf (" [+] analyzed arp packet does not seem to be specially-crafted\n"); /* check if we have already processed (and validated) the ip-mac pair... */ if (0 < conf.queue_size) { printf (" [+] calling known-traffic-filter module to check if we have validated" " IP - MAC (%s - %s) pair earlier (queue_size: %d)\n", conf.a_sip, conf.a_sha, conf.queue_size); known_traffic_filter (start, conf.a_sip, conf.a_sha, conf.queue_size); } else { printf (" [+] no IP-MAC pairs have been validated yet (queue_size: %d)\n", conf.queue_size); } /* ...hmmm, seems to be a new mac-ip pair. let's validate it then... */ printf (" [+] calling spoof-detection module to validate IP - MAC (%s - %s) pair\n", conf.a_sip, conf.a_sha); valid = spoof_detector (conf, start, end); if (0 == valid) { printf ("\n [+] try other scan types before determining the validity of the IP - MAC (%s - %s)\n", conf.a_sip, conf.a_sha); if (DETECT == conf.mode) { printf (" [+] for safety reasons, you need to clean up arp cache manually." " delete entry for (%s - %s)\n", conf.a_sip, conf.a_sha); printf (" [+] to automate this process from now onwards," " restart arp-secur in PREVENT mode, i.e with -P switch\n"); } else if (PREVENT == conf.mode) { printf (" [+] cleaning up arp cache by deleting entry for SIP (%s) - SMAC (%s)\n", conf.a_sip, conf.a_sha); cache_cleanup (conf.a_sip, conf.a_sha); } } /* display session summary in a system popup notification */ if (1 == showpopup) { alert (conf.a_sip, conf.a_sha, valid); } /* end repeat loop */ /* end arp-secur session */ bcurtime = time (NULL); bloctime = localtime (&bcurtime); strftime (end_time, 24, "%d/%b/%Y %H:%M:%S", bloctime); printf ("\n [+] session finished at %s\n\n", end_time); } return 0; }//main
void jsonnet_static_analysis(AST *ast) { static_analysis(ast, false, IdSet{}); }