void destroy_config() { if (fargc == 0) return; while (fargc-- != 0) ck_free(fargv[fargc]); ck_free(fargv); }
static void find_obj(u8* argv0) { u8 *afl_path = getenv("AFL_PATH"); u8 *slash, *tmp; if (afl_path) { tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); if (!access(tmp, R_OK)) { obj_path = afl_path; ck_free(tmp); return; } ck_free(tmp); } slash = strrchr(argv0, '/'); if (slash) { u8 *dir; *slash = 0; dir = ck_strdup(argv0); *slash = '/'; tmp = alloc_printf("%s/afl-llvm-rt.o", dir); if (!access(tmp, R_OK)) { obj_path = dir; ck_free(tmp); return; } ck_free(tmp); ck_free(dir); } if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { obj_path = AFL_PATH; return; } FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PATH"); }
static void find_binary(u8* fname) { u8* env_path = 0; struct stat st; if (strchr(fname, '/') || !(env_path = getenv("PATH"))) { target_path = ck_strdup(fname); if (stat(target_path, &st) || !S_ISREG(st.st_mode) || !(st.st_mode & 0111) || st.st_size < 4) FATAL("Program '%s' not found or not executable", fname); } else { while (env_path) { u8 *cur_elem, *delim = strchr(env_path, ':'); if (delim) { cur_elem = ck_alloc(delim - env_path + 1); memcpy(cur_elem, env_path, delim - env_path); delim++; } else cur_elem = ck_strdup(env_path); env_path = delim; if (cur_elem[0]) target_path = alloc_printf("%s/%s", cur_elem, fname); else target_path = ck_strdup(fname); ck_free(cur_elem); if (!stat(target_path, &st) && S_ISREG(st.st_mode) && (st.st_mode & 0111) && st.st_size >= 4) break; ck_free(target_path); target_path = 0; } if (!target_path) FATAL("Program '%s' not found or not executable", fname); } }
static void setup_shm(void) { u8* shm_str; shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600); if (shm_id < 0) PFATAL("shmget() failed"); atexit(remove_shm); shm_str = alloc_printf("%d", shm_id); setenv(SHM_ENV_VAR, shm_str, 1); ck_free(shm_str); trace_bits = shmat(shm_id, NULL, 0); if (!trace_bits) PFATAL("shmat() failed"); }
static void detect_file_args(char** argv) { u32 i = 0; u8* cwd = getcwd(NULL, 0); if (!cwd) PFATAL("getcwd() failed"); while (argv[i]) { u8* aa_loc = strstr(argv[i], "@@"); if (aa_loc) { u8 *aa_subst, *n_arg; if (!at_file) FATAL("@@ syntax is not supported by this tool."); /* Be sure that we're always using fully-qualified paths. */ if (at_file[0] == '/') aa_subst = at_file; else aa_subst = alloc_printf("%s/%s", cwd, at_file); /* Construct a replacement argv value. */ *aa_loc = 0; n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2); argv[i] = n_arg; *aa_loc = '@'; if (at_file[0] != '/') ck_free(aa_subst); } i++; } free(cwd); /* not tracked */ }
static void live_event_loop(void) { #ifndef __CYGWIN__ /* The huge problem with winpcap on cygwin is that you can't get a file descriptor suitable for poll() / select() out of it: http://www.winpcap.org/pipermail/winpcap-users/2009-April/003179.html The only alternatives seem to be additional processes / threads, a nasty busy loop, or a ton of Windows-specific code. If you need APi queries on Windows, you are welcome to fix this :-) */ struct pollfd *pfds; struct api_client** ctable; u32 pfd_count; /* We need room for pcap, and possibly api_fd + api_clients. */ pfds = ck_alloc((1 + (api_sock ? (1 + api_max_conn) : 0)) * sizeof(struct pollfd)); ctable = ck_alloc((1 + (api_sock ? (1 + api_max_conn) : 0)) * sizeof(struct api_client*)); pfd_count = regen_pfds(pfds, ctable); if (!daemon_mode) SAYF("[+] Entered main event loop.\n\n"); while (!stop_soon) { s32 pret, i; u32 cur; /* We use a 250 ms timeout to keep Ctrl-C responsive without resortng to silly sigaction hackery or unsafe signal handler code. */ poll_again: pret = poll(pfds, pfd_count, 250); if (pret < 0) { if (errno == EINTR) break; printf("\n FATAL: poll() failed."); } if (!pret) { if (log_file) fflush(lf); continue; } /* Examine pfds... */ for (cur = 0; cur < pfd_count; cur++) { if (pfds[cur].revents & POLLOUT) switch (cur) { case 0: case 1: printf("\n FATAL: Unexpected POLLOUT on fd %d.\n", cur); default: /* Write API response, restart state when complete. */ if (ctable[cur]->in_off < sizeof(struct p0f_api_query)) printf("\n FATAL: Inconsistent p0f_api_response state.\n"); i = write(pfds[cur].fd, ((char*)&ctable[cur]->out_data) + ctable[cur]->out_off, sizeof(struct p0f_api_response) - ctable[cur]->out_off); if (i <= 0) printf("\n FATAL: write() on API socket fails despite POLLOUT."); ctable[cur]->out_off += i; /* All done? Back to square zero then! */ if (ctable[cur]->out_off == sizeof(struct p0f_api_response)) { ctable[cur]->in_off = ctable[cur]->out_off = 0; pfds[cur].events = (POLLIN | POLLERR | POLLHUP); } } if (pfds[cur].revents & POLLIN) switch (cur) { case 0: /* Process traffic on the capture interface. */ if (pcap_dispatch(pt, -1, (pcap_handler)parse_packet, 0) < 0) printf("\n FATAL: Packet capture interface is down."); break; case 1: /* Accept new API connection, limits permitting. */ if (!api_sock) printf("\n FATAL: Unexpected API connection."); if (pfd_count - 2 < api_max_conn) { for (i = 0; i < api_max_conn && api_cl[i].fd >= 0; i++); if (i == api_max_conn) printf("\n FATAL: Inconsistent API connection data."); api_cl[i].fd = accept(api_fd, NULL, NULL); if (api_cl[i].fd < 0) { WARN("Unable to handle API connection: accept() fails."); } else { if (fcntl(api_cl[i].fd, F_SETFL, O_NONBLOCK)) printf("\n FATAL: fcntl() to set O_NONBLOCK on API connection fails."); api_cl[i].in_off = api_cl[i].out_off = 0; pfd_count = regen_pfds(pfds, ctable); DEBUG("[#] Accepted new API connection, fd %d.\n", api_cl[i].fd); goto poll_again; } } else WARN("Too many API connections (use -S to adjust).\n"); break; default: /* Receive API query, dispatch when complete. */ if (ctable[cur]->in_off >= sizeof(struct p0f_api_query)) printf("\n FATAL: Inconsistent p0f_api_query state.\n"); i = read(pfds[cur].fd, ((char*)&ctable[cur]->in_data) + ctable[cur]->in_off, sizeof(struct p0f_api_query) - ctable[cur]->in_off); if (i < 0) printf("\n FATAL: read() on API socket fails despite POLLIN."); ctable[cur]->in_off += i; /* Query in place? Compute response and prepare to send it back. */ if (ctable[cur]->in_off == sizeof(struct p0f_api_query)) { handle_query(&ctable[cur]->in_data, &ctable[cur]->out_data); pfds[cur].events = (POLLOUT | POLLERR | POLLHUP); } } if (pfds[cur].revents & (POLLERR | POLLHUP)) switch (cur) { case 0: printf("\n FATAL: Packet capture interface is down."); case 1: printf("\n FATAL: API socket is down."); default: /* Shut down API connection and free its state. */ DEBUG("[#] API connection on fd %d closed.\n", pfds[cur].fd); close(pfds[cur].fd); ctable[cur]->fd = -1; pfd_count = regen_pfds(pfds, ctable); goto poll_again; } /* Processed all reported updates already? If so, bail out early. */ if (pfds[cur].revents && !--pret) break; } } ck_free(ctable); ck_free(pfds); #else if (!daemon_mode) SAYF("[+] Entered main event loop.\n\n"); /* Ugh. The only way to keep SIGINT and other signals working is to have this funny loop with dummy I/O every 250 ms. Signal handlers don't get called in pcap_dispatch() or pcap_loop() unless there's I/O. */ while (!stop_soon) { s32 ret = pcap_dispatch(pt, -1, (pcap_handler)parse_packet, 0); if (ret < 0) return; if (log_file && !ret) fflush(lf); write(2, NULL, 0); } #endif /* ^!__CYGWIN__ */ WARN("User-initiated shutdown."); }
static void prepare_bpf(void) { struct bpf_program flt; u8* final_rule; u8 vlan_support; /* VLAN matching is somewhat brain-dead: you need to request it explicitly, and it alters the semantics of the remainder of the expression. */ vlan_support = (pcap_datalink(pt) == DLT_EN10MB); retry_no_vlan: if (!orig_rule) { if (vlan_support) { final_rule = (u8*)"tcp or (vlan and tcp)"; } else { final_rule = (u8*)"tcp"; } } else { if (vlan_support) { final_rule = ck_alloc(strlen((char*)orig_rule) * 2 + 64); sprintf((char*)final_rule, "(tcp and (%s)) or (vlan and tcp and (%s))", orig_rule, orig_rule); } else { final_rule = ck_alloc(strlen((char*)orig_rule) + 16); sprintf((char*)final_rule, "tcp and (%s)", orig_rule); } } DEBUG("[#] Computed rule: %s\n", final_rule); if (pcap_compile(pt, &flt, (char*)final_rule, 1, 0)) { if (vlan_support) { if (orig_rule) ck_free(final_rule); vlan_support = 0; goto retry_no_vlan; } pcap_perror(pt, "[-] pcap_compile"); if (!orig_rule) printf("\n FATAL: pcap_compile() didn't work, strange"); else printf("\n FATAL: Syntax error! See 'man tcpdump' for help on filters."); } if (pcap_setfilter(pt, &flt)) printf("\n FATAL: pcap_setfilter() didn't work, strange."); pcap_freecode(&flt); if (!orig_rule) { SAYF("[+] Default packet filtering configured%s.\n", vlan_support ? " [+VLAN]" : ""); } else { SAYF("[+] Custom filtering rule enabled: %s%s\n", orig_rule ? orig_rule : (u8*)"tcp", vlan_support ? " [+VLAN]" : ""); ck_free(final_rule); } }
void read_config(u8* fname) { s32 f; struct stat st; u8 *data, *cur; f = open((char*)fname, O_RDONLY); if (f < 0) PFATAL("Cannot open '%s' for reading.", fname); if (fstat(f, &st)) PFATAL("fstat() on '%s' failed.", fname); if (!st.st_size) { close(f); goto end_fp_read; } cur = data = ck_alloc(st.st_size + 1); if (read(f, data, st.st_size) != st.st_size) FATAL("Short read from '%s'.", fname); data[st.st_size] = 0; close(f); /* If you put NUL in your p0f.fp... Well, sucks to be you. */ while (1) { u8 *eol; line_no++; while (isblank(*cur)) cur++; eol = cur; while (*eol && *eol != '\n') eol++; if (*cur != ';' && cur != eol) { u8* line = ck_memdup_str(cur, eol - cur); config_parse_line(line); ck_free(line); } if (!*eol) break; cur = eol + 1; } ck_free(data); end_fp_read: if (!sig_cnt) SAYF("[!] No signatures found in '%s'.\n", fname); else SAYF("[+] Loaded %u signature%s from '%s'.\n", sig_cnt, sig_cnt == 1 ? "" : "s", fname); }
struct tcp_sig* fingerprint_tcp(u8 to_srv, struct packet_data* pk, struct packet_flow* f) { struct tcp_sig* sig; struct tcp_sig_record* m; sig = ck_alloc(sizeof(struct tcp_sig)); packet_to_sig(pk, sig); /* Detect packets generated by p0f-sendsyn; they require special handling to provide the user with response fingerprints, but not interfere with NAT scores and such. */ if (pk->tcp_type == TCP_SYN && pk->win == SPECIAL_WIN && pk->mss == SPECIAL_MSS) f->sendsyn = 1; if (to_srv) start_observation(f->sendsyn ? "sendsyn probe" : "syn", 4, 1, f); else start_observation(f->sendsyn ? "sendsyn response" : "syn+ack", 4, 0, f); tcp_find_match(to_srv, sig, 0, f->syn_mss); if ((m = sig->matched)) { OBSERVF((m->class_id == -1 || f->sendsyn) ? "app" : "os", "%s%s%s", fp_os_names[m->name_id], m->flavor ? " " : "", m->flavor ? m->flavor : (u8*)""); } else { add_observation_field("os", NULL); } if (m && m->bad_ttl) { OBSERVF("dist", "<= %u", sig->dist); } else { if (to_srv) f->client->distance = sig->dist; else f->server->distance = sig->dist; OBSERVF("dist", "%u", sig->dist); } add_observation_field("params", dump_flags(pk, sig)); add_observation_field("raw_sig", dump_sig(pk, sig, f->syn_mss)); if (pk->tcp_type == TCP_SYN) f->syn_mss = pk->mss; /* That's about as far as we go with non-OS signatures. */ if (m && m->class_id == -1) { verify_tool_class(to_srv, f, m->sys, m->sys_cnt); ck_free(sig); return NULL; } if (f->sendsyn) { ck_free(sig); return NULL; } score_nat(to_srv, sig, f); return sig; }