Example #1
0
static void edit_params(int argc, char** argv) {

  u8* tmp_dir = getenv("TMPDIR");

  if (!tmp_dir) tmp_dir = "/tmp";

  as_params = ck_alloc((argc + 1) * sizeof(u8*));

  memcpy(as_params, argv, argc * sizeof(u8*));

  as_params[0] = "as";
  as_params[argc] = 0;

  input_file = as_params[argc - 1];

  if (input_file[0] == '-') {

    if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)");
      else input_file = NULL;

  }

  modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(),
                               (u32)time(NULL));

  as_params[argc - 1] = modified_file;

}
Example #2
0
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);

  }

}
void parse_opts(int argc, char** argv){
  int longIndex;
  int mode=MODE_ATTACK;
  int i;
  unsigned int f;
  int t=0;
  int recent=0;
  int code=0;
  int query_all=0;
  char *post_key=NULL;
  char *url=NULL;
  char *mime=NULL;
  char *trigger=NULL;
  char *feature=NULL;
  char *description="";
  char *upload_file=NULL;
  unsigned int flags=0;
  struct option long_options[] = {        /* long options array. Items are all caSe SensiTivE! */
    { "add-url", no_argument, &mode, MODE_ADD_URL   }, 
    { "add-trigger", no_argument, &mode, MODE_ADD_TRIGGER},
    { "brute-backup", required_argument, NULL, MODE_BRUTE_BACKUP},
    { "brute-backup-days", required_argument, NULL, BRUTE_BACKUP_DAYS},
    { "brute-backup-pattern", required_argument, NULL, BRUTE_BACKUP_PATTERN},
    { "brute-backup-no-stop", no_argument, &backup_bruteforce_stop, 0},
    { "brute-backup-no-slash", no_argument, &backup_bruteforce_slash, 0},
    { "store-successes", no_argument, NULL, 'S'},
    { "query", no_argument, &mode, MODE_QUERY}, 
    { "all", no_argument, &query_all, 1}, 
    { "code", required_argument, NULL, CODE}, 
    { "post-key", required_argument, NULL, POST_KEY}, 
    { "mime-type", required_argument, NULL, MIME}, 
    { "recent", required_argument, NULL, RECENT}, 
    { "no-async-resolve", no_argument, &async_dns, 0}, 
    { "trigger", required_argument,NULL, TRIGGER},
    { "max-hosts", required_argument,NULL, 'n'},
    { "idle-timeout", required_argument,NULL, RESP_TIMEOUT},
    { "rw-timeout", required_argument,NULL, RW_TIMEOUT},
    { "conn-timeout", required_argument,NULL, CONN_TIMEOUT},
    { "max-connections", required_argument,NULL, 'c'},
    { "max-requests", required_argument,NULL, 'r'},
    { "max-time", required_argument,NULL, MAX_TIME},
    { "progress", required_argument, NULL, 'P' },
    { "file", required_argument, NULL, 'f' },
    { "statistics", no_argument, NULL, STATISTICS },
    { "browser", required_argument, NULL, 'B' },
    { "train",  optional_argument, NULL, 'T' },
    { "feature", required_argument,NULL, FEATURE},
    { "url", required_argument, NULL, URL },
    { "flags", required_argument, NULL, FLAGS },
    { "help", required_argument, NULL, 'h' },
    { "skip-sig", no_argument, &skip_sig, 1},
    { "skip-other-probes", no_argument, &skip_other_probes, 1},
    { "skip-blacklist-success", no_argument, &blacklist_success, 0},
    { "force-save", no_argument, &force_save, 1},
    { "analyze", no_argument, &mode, MODE_ANALYZE},
    { "find-uploaded-file", required_argument, NULL, MODE_FIND_UPLOAD },
    { 0,    0,    0,    0   }       /* terminating -0 item */
  };
  int opt;
  struct t_list *target;
  while((opt=getopt_long( argc, argv, "-n:Sf:P:c:B:h:r:T::", long_options, &longIndex ))!=-1){
    switch(opt){
      case 1:
        target=calloc(sizeof(struct t_list),1);
        target->host=(unsigned char *) optarg;
        unqueued_hosts++;
        LL_APPEND(target_list,target);
        t++;
        break;
      case MODE_BRUTE_BACKUP:
        backup_bruteforce_url=optarg;
        mode=MODE_BRUTE_BACKUP;
        break;
      case BRUTE_BACKUP_DAYS:
        backup_bruteforce_days_back=atoi(optarg);
        break;
      case RESP_TIMEOUT:
        resp_tmout=atoi(optarg);
        break;
      case RW_TIMEOUT:
        rw_tmout=atoi(optarg);
        break;
      case MAX_TIME:
        max_time=atoi(optarg);
        break;
      case CONN_TIMEOUT:
        idle_tmout=atoi(optarg);
        break;
      case BRUTE_BACKUP_PATTERN:
        backup_bruteforce_pattern=optarg;
        break;
      case 'B':
        if (!strcasecmp("metal",optarg)) browser_type=BROWSER_METAL;
        else if (!strcasecmp("minimal",optarg)) browser_type=BROWSER_FAST;
        else if (!strcasecmp("firefox",optarg)) browser_type=BROWSER_FFOX;
        else if (!strcasecmp("explorer",optarg)) browser_type=BROWSER_MSIE;
        else if (!strcasecmp("iphone",optarg)) browser_type=BROWSER_PHONE;
        else {
          printf("ERROR: Browser type '%s' is not supported.\n",optarg);
          exit(1);
        }
        break;
      case 'h':
        usage();
        exit(0);
      case 'S':
        store_successes=1;
        break;
      case URL:
        url=optarg;
        break;
      case 'c':
        max_conn_host=atoi(optarg);
        break;
      case 'f':
        if(!strcmp("-",optarg)) file=stdin;
        else{
          if(!(file=fopen(optarg,"r"))){
            printf("Can't open '%s' for reading!",optarg);
            exit(1);
          }
        }
        int fd = fileno(file);
        int fflags = fcntl(fd, F_GETFL, 0);
        fflags |= O_NONBLOCK;
        fcntl(fd, F_SETFL, fflags);
        t++;
      case 'r':
        max_requests=atoi(optarg);
        break;
      case 'P':
        progress=atoi(optarg);
        break;
      case STATISTICS:
        load_tests();
        load_features();
        show_feature_predictive_values();
        exit(0);
        break;
      case 'T':
        train=1;
        if(optarg) max_train_count=atoi(optarg);
        break;
      case 'n':
        max_hosts=atoi(optarg);
        break;
      case FEATURE:
        feature=optarg;
        break;
      case POST_KEY:
        post_key=optarg;
        break;
      case MIME:
        mime=optarg;
        break;
      case CODE:
        code=atoi(optarg);
        break;
      case RECENT:
        recent=atoi(optarg);
        break;
      case TRIGGER:
        trigger=optarg;
        break;
      case FLAGS:
        for(i=0; i<strlen(optarg); i++){
          f=tolower(optarg[i]);
          switch(f){
            case 'c':
              flags|=F_CRITICAL;
              break;
            case 'i':
              flags|=F_INFO;
              break;
            case 'd':
              flags|=F_DIRECTORY;
              break;
            case 'g':
              flags|=F_CGI;
              break;
            default:
              fprintf (stderr, "Unknown flag: '%c'",f ); 
              exit(1);
          }
        }
        break;
      case MODE_FIND_UPLOAD:
        mode=MODE_FIND_UPLOAD;
        upload_file=optarg;
        break;
    }
  
  }

  if(train){

    /* force aggressive 404 pruning */

    max_requests=0;
    blacklist_success=1;
    skip_other_probes=0;
  }

  switch(mode){
    case MODE_FIND_UPLOAD:
      do {
        struct target *tar;
        if(!t){
          fprintf(stderr, "You must specify a host\n");
          exit(1);
        }
        skip_other_probes=1;
        tar=add_target(target_list->host) ; /* first target only */
        no_add_from_queue=1;
        if(!tar){
          fprintf(stderr,"Couldn't create target '%s'\n",target_list->host);
          exit(1);
        }

        tar->upload_file=upload_file;
        tar->after_probes=start_find_uploaded_file;
        do_scan();
      } while(0);
      break;
    case MODE_ADD_URL:
      add_or_update_url(url, description, flags);
      exit(0);
      break;
    case MODE_ATTACK:
      if(!t){
        usage();
        exit(0);
      }
      max_connections=max_hosts * max_conn_host;
      scan_flags=flags;
      do_scan();
      exit(0);
      break;
    case MODE_ADD_TRIGGER:
      add_aho_corasick_trigger(trigger, feature);
      exit(0);
      break;
    case MODE_QUERY:
      do {
        if(!url && !code && !mime && !flags && !recent && !post_key && !query_all){
          fprintf(stderr,"You must specify at least one attribute to search on (or --all)\n");
          exit(1);
        }
        struct query *q=ck_alloc(sizeof(struct query));
        q->url=url;
        q->code=code;
        q->mime=mime;
        q->flags=flags;
        q->recent=recent;
        q->post_key=post_key;
        store_successes=0;
        do_query(q);
        exit(0);
      break;
      } while(0);
    case MODE_ANALYZE:
      load_tests();
      load_features();
      info("performing feature selection...");
      do_feature_selection();
      exit(0);
    case MODE_BRUTE_BACKUP:
      do {
      struct target *tar;
      skip_other_probes=1;
      tar=add_target(backup_bruteforce_url);
      if(!tar) exit(1);
      tar->after_probes=start_bruteforce_backup;
      do_scan();
      } while(0);
      break;
  }

}
Example #4
0
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.");

}
Example #5
0
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);

    }

}
Example #6
0
int main(int argc, char** argv) {
  s32 opt;
  u32 loop_cnt = 0, purge_age = 0, seed;
  u8 sig_loaded = 0, show_once = 0, no_statistics = 0,
     display_mode = 0, has_fake = 0;
  s32 oindex = 0;
  u8 *wordlist = NULL, *output_dir = NULL;
  u8 *sig_list_strg = NULL;
  u8 *gtimeout_str = NULL;
  u32 gtimeout = 0;

  struct termios term;
  struct timeval tv;
  u64 st_time, en_time;

  signal(SIGINT, ctrlc_handler);
  signal(SIGWINCH, resize_handler);
  signal(SIGPIPE, SIG_IGN);
  SSL_library_init();

/* Options, options, and options */

  static struct option long_options[] = {
    {"auth", required_argument, 0, 'A' },
    {"host", required_argument, 0, 'F' },
    {"cookie", required_argument, 0, 'C' },
    {"reject-cookies", required_argument, 0, 'N' },
    {"header", required_argument, 0, 'H' },
    {"user-agent", required_argument, 0, 'b' },
#ifdef PROXY_SUPPORT
    {"proxy", required_argument, 0, 'J' },
#endif /* PROXY_SUPPORT */
    {"max-depth", required_argument, 0, 'd' },
    {"max-child", required_argument, 0, 'c' },
    {"max-descendants", required_argument, 0, 'x' },
    {"max-requests", required_argument, 0, 'r' },
    {"max-rate", required_argument, 0, 'l'},
    {"probability", required_argument, 0, 'p' },
    {"seed", required_argument, 0, 'q' },
    {"include", required_argument, 0, 'I' },
    {"exclude", required_argument, 0, 'X' },
    {"skip-param", required_argument, 0, 'K' },
    {"skip-forms", no_argument, 0, 'O' },
    {"include-domain", required_argument, 0, 'D' },
    {"ignore-links", no_argument, 0, 'P' },
    {"no-ext-fuzzing", no_argument, 0, 'Y' },
    {"log-mixed-content", no_argument, 0, 'M' },
    {"skip-error-pages", no_argument, 0, 'Z' },
    {"log-external-urls", no_argument, 0, 'U' },
    {"log-cache-mismatches", no_argument, 0, 'E' },
    {"form-value", no_argument, 0, 'T' },
    {"rw-wordlist", required_argument, 0, 'W' },
    {"no-keyword-learning", no_argument, 0, 'L' },
    {"mode", required_argument, 0, 'J' },
    {"wordlist", required_argument, 0, 'S'},
    {"trust-domain", required_argument, 0, 'B' },
    {"max-connections", required_argument, 0, 'g' },
    {"max-host-connections", required_argument, 0, 'm' },
    {"max-fail", required_argument, 0, 'f' },
    {"request-timeout", required_argument, 0, 't' },
    {"network-timeout", required_argument, 0, 'w' },
    {"idle-timeout", required_argument, 0, 'i' },
    {"response-size", required_argument, 0, 's' },
    {"discard-binary", required_argument, 0, 'e' },
    {"output", required_argument, 0, 'o' },
    {"help", no_argument, 0, 'h' },
    {"quiet", no_argument, 0, 'u' },
    {"verbose", no_argument, 0, 'v' },
    {"scan-timeout", required_argument, 0, 'k'},
    {"signatures", required_argument, 0, 'z'},
    {"checks", no_argument, 0, 0},
    {"checks-toggle", required_argument, 0, 0},
    {"no-checks", no_argument, 0, 0},
    {"fast", no_argument, 0, 0},
    {"auth-form", required_argument, 0, 0},
    {"auth-form-target", required_argument, 0, 0},
    {"auth-user", required_argument, 0, 0},
    {"auth-user-field", required_argument, 0, 0},
    {"auth-pass", required_argument, 0, 0},
    {"auth-pass-field", required_argument, 0, 0},
    {"auth-verify-url", required_argument, 0, 0},
    {0, 0, 0, 0 }

  };
  /* Come up with a quasi-decent random seed. */

  gettimeofday(&tv, NULL);
  seed = tv.tv_usec ^ (tv.tv_sec << 16) ^ getpid();

  SAY("skipfish version " VERSION " by <*****@*****.**>\n");

  while ((opt = getopt_long(argc, argv,
          "+A:B:C:D:EF:G:H:I:J:K:LMNOPQR:S:T:UW:X:YZ"
          "b:c:d:ef:g:hi:k:l:m:o:p:q:r:s:t:uvw:x:z:",
          long_options, &oindex)) >= 0)

    switch (opt) {

      case 'A': {
          u8* x = (u8*)strchr(optarg, ':');
          if (!x) FATAL("Credentials must be in 'user:pass' form.");
          *(x++) = 0;
          auth_user = (u8*)optarg;
          auth_pass = x;
          auth_type = AUTH_BASIC;
          break;
        }

#ifdef PROXY_SUPPORT
      case 'J':  {
          u8* x = (u8*)strchr(optarg, ':');
          if (!x) FATAL("Proxy data must be in 'host:port' form.");
          *(x++) = 0;
          use_proxy = (u8*)optarg;
          use_proxy_port = atoi((char*)x);
          if (!use_proxy_port) FATAL("Incorrect proxy port number.");
          break;
        }
#endif /* PROXY_SUPPORT */

      case 'F': {
          u8* x = (u8*)strchr(optarg, '=');
          u32 fake_addr;
          if (!x) FATAL("Fake mappings must be in 'host=IP' form.");
          *x = 0;
          fake_addr = inet_addr((char*)x + 1);
          if (fake_addr == (u32)-1)
            FATAL("Could not parse IP address '%s'.", x + 1);
          fake_host((u8*)optarg, fake_addr);
          has_fake = 1;
          break;
        }

      case 'H': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Extra headers must be in 'name=value' form.");
          *x = 0;
          if (!strcasecmp(optarg, "Cookie"))
            FATAL("Do not use -H to set cookies (try -C instead).");
          SET_HDR((u8*)optarg, x + 1, &global_http_par);
          break;
        }

      case 'C': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Cookies must be in 'name=value' form.");
          if (strchr(optarg, ';'))
            FATAL("Split multiple cookies into separate -C options.");
          *x = 0;
          SET_CK((u8*)optarg, x + 1, &global_http_par);
          break;
        }

      case 'D':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(allow_domains, num_allow_domains, optarg);
        break;

      case 'K':
        APPEND_FILTER(skip_params, num_skip_params, optarg);
        break;

      case 'B':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(trust_domains, num_trust_domains, optarg);
        break;

      case 'I':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(allow_urls, num_allow_urls, optarg);
        break;

      case 'X':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(deny_urls, num_deny_urls, optarg);
        break;

      case 'T': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Rules must be in 'name=value' form.");
          *x = 0;
          add_form_hint((u8*)optarg, x + 1);
          break;
        }

      case 'N':
        ignore_cookies = 1;
        break;

      case 'Y':
        no_fuzz_ext = 1;
        break;

      case 'q':
        if (sscanf(optarg, "0x%08x", &seed) != 1)
          FATAL("Invalid seed format.");
        srandom(seed);
        break;

      case 'Q':
        suppress_dupes = 1;
        break;

      case 'P':
        no_parse = 1;
        break;

      case 'M':
        warn_mixed = 1;
        break;

      case 'U':
        log_ext_urls = 1;
        break;

      case 'L':
        dont_add_words = 1;
        break;

      case 'E':
        pedantic_cache = 1;
        break;

      case 'O':
        no_forms = 1;
        break;

      case 'R':
        purge_age = atoi(optarg);
        if (purge_age < 3) FATAL("Purge age invalid or too low (min 3).");
        break;

      case 'd':
        max_depth = atoi(optarg);
        if (max_depth < 2) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'c':
        max_children = atoi(optarg);
        if (!max_children) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'x':
        max_descendants = atoi(optarg);
        if (!max_descendants) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'p':
        crawl_prob = atoi(optarg);
        if (!crawl_prob) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'W':
        if (wordlist)
          FATAL("Only one -W parameter permitted (use -S to load supplemental dictionaries).");

        if (!strcmp(optarg, "-")) wordlist = (u8*)"/dev/null";
        else wordlist = (u8*)optarg;

        break;

      case 'S':
        load_keywords((u8*)optarg, 1, 0);
        break;

      case 'z':
        load_signatures((u8*)optarg);
        sig_loaded = 1;
        break;

      case 'b':
        if (optarg[0] == 'i') browser_type = BROWSER_MSIE; else
        if (optarg[0] == 'f') browser_type = BROWSER_FFOX; else
        if (optarg[0] == 'p') browser_type = BROWSER_PHONE; else
          usage(argv[0]);
        break;

      case 'g':
        max_connections = atoi(optarg);
        if (!max_connections) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'm':
        max_conn_host = atoi(optarg);
        if (!max_conn_host) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'G':
        max_guesses = atoi(optarg);
        if (!max_guesses) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'r':
        max_requests = atoi(optarg);
        if (!max_requests) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'l':
        max_requests_sec = atof(optarg);
        if (!max_requests_sec) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'f':
        max_fail = atoi(optarg);
        if (!max_fail) FATAL("Invalid value '%s'.", optarg);
        break;

      case 't':
        resp_tmout = atoi(optarg);
        if (!resp_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'w':
        rw_tmout = atoi(optarg);
        if (!rw_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'i':
        idle_tmout = atoi(optarg);
        if (!idle_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 's':
        size_limit = atoi(optarg);
        if (!size_limit) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'o':
        if (output_dir) FATAL("Multiple -o options not allowed.");
        output_dir = (u8*)optarg;

        rmdir(optarg);

        if (mkdir(optarg, 0755))
          PFATAL("Unable to create '%s'.", output_dir);

        break;

      case 'u':
        no_statistics = 1;
        break;

      case 'v':
        verbosity++;
        break;


      case 'e':
        delete_bin = 1;
        break;

      case 'k':
        if (gtimeout_str) FATAL("Multiple -k options not allowed.");
        gtimeout_str = (u8*)optarg;
        break;

      case 'Z':
        no_500_dir = 1;
        break;

      case 0:
        if (!strcmp("checks", long_options[oindex].name ))
          display_injection_checks();
        if (!strcmp("checks-toggle", long_options[oindex].name ))
          toggle_injection_checks((u8*)optarg, 1, 1);
        if (!strcmp("no-checks", long_options[oindex].name ))
          no_checks = 1;
        if (!strcmp("signatures", long_options[oindex].name ))
          load_signatures((u8*)optarg);
        if(!strcmp("fast", long_options[oindex].name ))
          toggle_injection_checks((u8*)"2,4,5,13,14,15,16", 0, 0);
        if (!strcmp("auth-form", long_options[oindex].name ))
          auth_form = (u8*)optarg;
        if (!strcmp("auth-user", long_options[oindex].name ))
          auth_user = (u8*)optarg;
        if (!strcmp("auth-pass", long_options[oindex].name ))
          auth_pass = (u8*)optarg;
        if (!strcmp("auth-pass-field", long_options[oindex].name ))
          auth_pass_field = (u8*)optarg;
        if (!strcmp("auth-user-field", long_options[oindex].name ))
          auth_user_field = (u8*)optarg;
        if (!strcmp("auth-form-target", long_options[oindex].name ))
          auth_form_target = (u8*)optarg;
        if (!strcmp("auth-verify-url", long_options[oindex].name ))
          auth_verify_url = (u8*)optarg;

        break;

      default:
        usage(argv[0]);

  }

#ifdef PROXY_SUPPORT
  if (has_fake && use_proxy)
    FATAL("-F and -J should not be used together.");
#endif /* PROXY_SUPPORT */

  if (access(ASSETS_DIR "/index.html", R_OK))
    PFATAL("Unable to access '%s/index.html' - wrong directory?", ASSETS_DIR);

  srandom(seed);

  if (optind == argc)
    FATAL("Scan target not specified (try -h for help).");

  if (!output_dir)
    FATAL("Output directory not specified (try -h for help).");

  if(verbosity && !no_statistics && isatty(2))
    FATAL("Please use -v in combination with the -u flag or, "
          "run skipfish while redirecting stderr to a file. ");


  if (resp_tmout < rw_tmout)
    resp_tmout = rw_tmout;

  if (max_connections < max_conn_host)
    max_connections = max_conn_host;

  /* Parse the timeout string - format h:m:s */
  if (gtimeout_str) {
    int i = 0;
    int m[3] = { 1, 60, 3600 };

    u8* tok = (u8*)strtok((char*)gtimeout_str, ":");

    while(tok && i <= 2) {
      gtimeout += atoi((char*)tok) * m[i];
      tok = (u8*)strtok(NULL, ":");
      i++;
    }

    if(!gtimeout)
      FATAL("Wrong timeout format, please use h:m:s (hours, minutes, seconds)");
    DEBUG("* Scan timeout is set to %d seconds\n", gtimeout);
  }


  if (!wordlist) {
    wordlist = (u8*)"/dev/null";
    DEBUG("* No wordlist specified with -W: defaulting to /dev/null\n");
  }

  /* If no signature files have been specified via command-line: load
     the default file */
  if (!sig_loaded)
    load_signatures((u8*)SIG_FILE);

  load_keywords(wordlist, 0, purge_age);

  /* Load the signatures list for the matching */
  if (sig_list_strg) load_signatures(sig_list_strg);

  /* Try to authenticate when the auth_user and auth_pass fields are set. */
  if (auth_user && auth_pass) {
    authenticate();

    while (next_from_queue()) {
      usleep(1000);
    }

    switch (auth_state) {
      case ASTATE_DONE:
        DEBUGC(L1, "*- Authentication succeeded!\n");
        break;

      default:
        DEBUG("Auth state: %d\n", auth_state);
        FATAL("Authentication failed (use -uv for more info)\n");
        break;
    }
  }

  /* Schedule all URLs in the command line for scanning. */

  while (optind < argc) {
    struct http_request *req;

    /* Support @ notation for reading URL lists from files. */

    if (argv[optind][0] == '@') {
      read_urls((u8*)argv[optind++] + 1);
      continue;
    }

    req = ck_alloc(sizeof(struct http_request));

    if (parse_url((u8*)argv[optind], req, NULL))
      FATAL("Scan target '%s' is not a valid absolute URL.", argv[optind]);

    if (!url_allowed_host(req))
      APPEND_FILTER(allow_domains, num_allow_domains,
                    __DFL_ck_strdup(req->host));

    if (!url_allowed(req))
      FATAL("URL '%s' explicitly excluded by -I / -X rules.", argv[optind]);

    maybe_add_pivot(req, NULL, 2);
    destroy_request(req);

    optind++;
  }

  /* Char-by char stdin. */

  tcgetattr(0, &term);
  term.c_lflag &= ~ICANON;
  tcsetattr(0, TCSANOW, &term);
  fcntl(0, F_SETFL, O_NONBLOCK);

  gettimeofday(&tv, NULL);
  st_time = tv.tv_sec * 1000LL + tv.tv_usec / 1000;

#ifdef SHOW_SPLASH
  if (!no_statistics) splash_screen();
#endif /* SHOW_SPLASH */

  if (!no_statistics) SAY("\x1b[H\x1b[J");
  else SAY(cLGN "[*] " cBRI "Scan in progress, please stay tuned...\n");

  u64 refresh_time = 0;

  /* Enter the crawler loop */
  while ((next_from_queue() && !stop_soon) || (!show_once++)) {

    u8 keybuf[8];

    u64 end_time;
    u64 run_time;
    struct timeval tv_tmp;

    gettimeofday(&tv_tmp, NULL);
    end_time = tv_tmp.tv_sec * 1000LL + tv_tmp.tv_usec / 1000;

    run_time = end_time - st_time;
    if (gtimeout > 0 && run_time && run_time/1000 > gtimeout) {
      DEBUG("* Stopping scan due to timeout\n");
      stop_soon = 1;
    }

    req_sec = (req_count - queue_cur / 1.15) * 1000 / (run_time + 1);

    if (no_statistics || ((loop_cnt++ % 100) && !show_once && idle == 0))
      continue;

    if (end_time > refresh_time) {
      refresh_time = (end_time + 10);

      if (clear_screen) {
        SAY("\x1b[H\x1b[2J");
        clear_screen = 0;
      }

      SAY(cYEL "\x1b[H"
          "skipfish version " VERSION " by [email protected]\n\n"
           cBRI "  -" cPIN " %s " cBRI "-\n\n" cNOR,
           allow_domains[0]);


      if (!display_mode) {
        http_stats(st_time);
        SAY("\n");
        database_stats();
      } else {
        http_req_list();
      }

      SAY("        \r");
    }

    if (fread(keybuf, 1, sizeof(keybuf), stdin) > 0) {
      display_mode ^= 1;
      clear_screen = 1;
    }
  }

  gettimeofday(&tv, NULL);
  en_time = tv.tv_sec * 1000LL + tv.tv_usec / 1000;

  SAY("\n");

  if (stop_soon)
    SAY(cYEL "[!] " cBRI "Scan aborted by user, bailing out!" cNOR "\n");

  term.c_lflag |= ICANON;
  tcsetattr(0, TCSANOW, &term);
  fcntl(0, F_SETFL, O_SYNC);

  save_keywords((u8*)wordlist);

  write_report(output_dir, en_time - st_time, seed);

#ifdef LOG_STDERR
  SAY("\n== PIVOT DEBUG ==\n");
  dump_pivots(0, 0);
  SAY("\n== END OF DUMP ==\n\n");
#endif /* LOG_STDERR */

  SAY(cLGN "[+] " cBRI "This was a great day for science!" cRST "\n\n");

#ifdef DEBUG_ALLOCATOR
  if (!stop_soon) {
    destroy_database();
    destroy_signature_lists();
    destroy_http();
    destroy_signatures();
    __TRK_report();
  }
#endif /* DEBUG_ALLOCATOR */

  fflush(0);

  EVP_cleanup();
  CRYPTO_cleanup_all_ex_data();

  return 0;

}
Example #7
0
static void read_urls(u8* fn) {
  FILE* f = fopen((char*)fn, "r");
  u8    tmp[MAX_URL_LEN];
  u32   loaded = 0;

  if (!f) FATAL("Unable to open '%s'.", fn);

  while (fgets((char*)tmp, MAX_URL_LEN, f)) {
    struct http_request *req;
    u8* url = tmp;
    u8* ptr;
    u32 l;

    while (isspace(*url)) url++;

    /* Check if we're reading a pivots.txt file and grab the URL */
    if(!strncmp((char*)url,"GET ", 4) || !strncmp((char*)url,"POST ", 4)) {
      url += 4;

      /* If the server response code is a 404, than we'll skip the URL
      to avoid wasting time on things that are likely not to exist. */
      if(inl_findstr(url, (u8*)"code=404", MAX_URL_LEN))
        continue;

      ptr = url;
      /* Find the next space to terminate the URL */
      while(ptr && !isspace(*ptr)) ptr++;

      if(!ptr) FATAL("URL parsing failed at line: %s", tmp);

      *ptr = 0;
    /* Else we expect a simple flat file with URLs */
    } else {
      l = strlen((char*)url);
      while (l && isspace(url[l-1])) l--;
      url[l] = 0;
    }

    if (*url == '#' || !*url) continue;

    req = ck_alloc(sizeof(struct http_request));

    if (parse_url(url, req, NULL))
      FATAL("Scan target '%s' in file '%s' is not a valid absolute URL.", url, fn);

    if (!url_allowed_host(req))
      APPEND_FILTER(allow_domains, num_allow_domains,
                    __DFL_ck_strdup(req->host));

    if (!url_allowed(req))
      FATAL("URL '%s' in file '%s' explicitly excluded by -I / -X rules.",
            url, fn);

    maybe_add_pivot(req, NULL, 2);
    destroy_request(req);
    loaded++;

  }

  fclose(f);

  if (!loaded) FATAL("No valid URLs found in '%s'.", fn);

}
Example #8
0
static void edit_params(int argc, char** argv) {

  u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
  u32 i;

#ifdef __APPLE__

  u8 use_clang_as = 0;

  /* On MacOS X, the Xcode cctool 'as' driver is a bit stale and does not work
     with the code generated by newer versions of clang that are hand-built
     by the user. See the thread here: http://goo.gl/HBWDtn.

     To work around this, when using clang and running without AFL_AS
     specified, we will actually call 'clang -c' instead of 'as -q' to
     compile the assembly file.

     The tools aren't cmdline-compatible, but at least for now, we can
     seemingly get away with this by making only very minor tweaks. Thanks
     to Nico Weber for the idea. */

  if (clang_mode && !afl_as) {

    use_clang_as = 1;

    afl_as = getenv("AFL_CC");
    if (!afl_as) afl_as = getenv("AFL_CXX");
    if (!afl_as) afl_as = "clang";

  }

#endif /* __APPLE__ */

  if (!tmp_dir) tmp_dir = "/tmp";

  as_params = ck_alloc((argc + 32) * sizeof(u8*));

  as_params[0] = afl_as ? afl_as : (u8*)"as";

  as_params[argc] = 0;

  for (i = 1; i < argc - 1; i++) {

    if (!strcmp(argv[i], "--64")) use_64bit = 1;
    else if (!strcmp(argv[i], "--32")) use_64bit = 0;

#ifdef __APPLE__

    /* The Apple case is a bit different... */

    if (!strcmp(argv[i], "-arch") && i + 1 < argc) {

      if (!strcmp(argv[i + 1], "x86_64")) use_64bit = 1;
      else if (!strcmp(argv[i + 1], "i386"))
        FATAL("Sorry, 32-bit Apple platforms are not supported.");

    }

    /* Strip options that set the preference for a particular upstream
       assembler in Xcode. */

    if (clang_mode && (!strcmp(argv[i], "-q") || !strcmp(argv[i], "-Q")))
      continue;

#endif /* __APPLE__ */

    as_params[as_par_cnt++] = argv[i];

  }

#ifdef __APPLE__

  /* When calling clang as the upstream assembler, append -c -x assembler
     and hope for the best. */

  if (use_clang_as) {

    as_params[as_par_cnt++] = "-c";
    as_params[as_par_cnt++] = "-x";
    as_params[as_par_cnt++] = "assembler";

  }

#endif /* __APPLE__ */

  input_file = argv[argc - 1];

  if (input_file[0] == '-') {

    if (!strcmp(input_file + 1, "-version")) {
      just_version = 1;
      modified_file = input_file;
      goto wrap_things_up;
    }

    if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)");
      else input_file = NULL;

  } else {

    /* Check if this looks like a standard invocation as a part of an attempt
       to compile a program, rather than using gcc on an ad-hoc .s file in
       a format we may not understand. This works around an issue compiling
       NSS. */

    if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
        strncmp(input_file, "/var/tmp/", 9) &&
        strncmp(input_file, "/tmp/", 5)) pass_thru = 1;

  }

  modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(),
                               (u32)time(NULL));

wrap_things_up:

  as_params[as_par_cnt++] = modified_file;
  as_params[as_par_cnt]   = NULL;

}
Example #9
0
static void edit_params(u32 argc, char** argv) {

  u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1;
  u8 *name;

  cc_params = ck_alloc((argc + 64) * sizeof(u8*));

  name = strrchr(argv[0], '/');
  if (!name) name = argv[0]; else name++;

  if (!strcmp(name, "afl-clang-fast++")) {
    u8* alt_cxx = getenv("AFL_CXX");
    cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
  } else {
    u8* alt_cc = getenv("AFL_CC");
    cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
  }

  cc_params[cc_par_cnt++] = "-Xclang";
  cc_params[cc_par_cnt++] = "-load";
  cc_params[cc_par_cnt++] = "-Xclang";
  cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
  cc_params[cc_par_cnt++] = "-Qunused-arguments";

  while (--argc) {
    u8* cur = *(++argv);

#if defined(__x86_64__)
    if (!strcmp(cur, "-m32")) FATAL("-m32 is not supported");
#endif

    if (!strcmp(cur, "-x")) x_set = 1;

    if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E") ||
        !strcmp(cur, "-v")) maybe_linking = 0;

    if (!strcmp(cur, "-fsanitize=address") ||
        !strcmp(cur, "-fsanitize=memory")) asan_set = 1;

    if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;

    cc_params[cc_par_cnt++] = cur;

  }

  if (getenv("AFL_HARDEN")) {

    cc_params[cc_par_cnt++] = "-fstack-protector-all";

    if (!fortify_set)
      cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";

  }

  if (!asan_set) {

    if (getenv("AFL_USE_ASAN")) {

      cc_params[cc_par_cnt++] = "-fsanitize=address";

      if (getenv("AFL_USE_MSAN"))
        FATAL("ASAN and MSAN are mutually exclusive");

    } else if (getenv("AFL_USE_MSAN")) {

      cc_params[cc_par_cnt++] = "-fsanitize=memory";

      if (getenv("AFL_USE_ASAN"))
        FATAL("ASAN and MSAN are mutually exclusive");

    }

  }

  if (!getenv("AFL_DONT_OPTIMIZE")) {

    cc_params[cc_par_cnt++] = "-g";
    cc_params[cc_par_cnt++] = "-O3";
    cc_params[cc_par_cnt++] = "-funroll-loops";

  }

  cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";

  /* When the user tries to use persistent or deferred forkserver modes by
     appending a single line to the program, we want to reliably inject a
     signature into the binary (to be picked up by afl-fuzz) and we want
     to call a function from the runtime .o file. This is unnecessarily
     painful for three reasons:

     1) We need to convince the compiler not to optimize out the signature.
        This is done with __attribute__((used)).

     2) We need to convince the linker, when called with -Wl,--gc-sections,
        not to do the same. This is done by forcing an assignment to a
        'volatile' pointer.

     3) We need to declare __afl_persistent_loop() in the global namespace,
        but doing this within a method in a class is hard - :: and extern "C"
        are forbidden and __attribute__((alias(...))) doesn't work. Hence the
        __asm__ aliasing trick.

   */

  cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
    "({ static volatile char *_B __attribute__((used)); "
    " _B = (char*)\"" PERSIST_SIG "\"; "
#ifdef __APPLE__
    "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
    "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */
    "_L(_A); })";

  cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
    "do { static volatile char *_A __attribute__((used)); "
    " _A = (char*)\"" DEFER_SIG "\"; "
#ifdef __APPLE__
    "void _I(void) __asm__(\"___afl_manual_init\"); "
#else
    "void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
    "_I(); } while (0)";

  if (maybe_linking) {

    if (x_set) {
      cc_params[cc_par_cnt++] = "-x";
      cc_params[cc_par_cnt++] = "none";
    }

    cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);

  }

  cc_params[cc_par_cnt] = NULL;

}
Example #10
0
static void edit_params(u32 argc, char** argv) {

  u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0;
  u8 *name;

  cc_params = ck_alloc((argc + 128) * sizeof(u8*));

  name = strrchr(argv[0], '/');
  if (!name) name = argv[0]; else name++;

  if (!strcmp(name, "afl-clang-fast++")) {
    u8* alt_cxx = getenv("AFL_CXX");
    cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
  } else {
    u8* alt_cc = getenv("AFL_CC");
    cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
  }

  /* There are two ways to compile afl-clang-fast. In the traditional mode, we
     use afl-llvm-pass.so to inject instrumentation. In the experimental
     'trace-pc-guard' mode, we use native LLVM instrumentation callbacks
     instead. The latter is a very recent addition - see:

     http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards */

#ifdef USE_TRACE_PC
  cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
  cc_params[cc_par_cnt++] = "-mllvm";
  cc_params[cc_par_cnt++] = "-sanitizer-coverage-block-threshold=0";
#else
  cc_params[cc_par_cnt++] = "-Xclang";
  cc_params[cc_par_cnt++] = "-load";
  cc_params[cc_par_cnt++] = "-Xclang";
  cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
#endif /* ^USE_TRACE_PC */

  cc_params[cc_par_cnt++] = "-Qunused-arguments";

  /* Detect stray -v calls from ./configure scripts. */

  if (argc == 1 && !strcmp(argv[1], "-v")) maybe_linking = 0;

  while (--argc) {
    u8* cur = *(++argv);

    if (!strcmp(cur, "-m32")) bit_mode = 32;
    if (!strcmp(cur, "-m64")) bit_mode = 64;

    if (!strcmp(cur, "-x")) x_set = 1;

    if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E"))
      maybe_linking = 0;

    if (!strcmp(cur, "-fsanitize=address") ||
        !strcmp(cur, "-fsanitize=memory")) asan_set = 1;

    if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;

    if (!strcmp(cur, "-shared")) maybe_linking = 0;

    if (!strcmp(cur, "-Wl,-z,defs") ||
        !strcmp(cur, "-Wl,--no-undefined")) continue;

    cc_params[cc_par_cnt++] = cur;

  }

  if (getenv("AFL_HARDEN")) {

    cc_params[cc_par_cnt++] = "-fstack-protector-all";

    if (!fortify_set)
      cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";

  }

  if (!asan_set) {

    if (getenv("AFL_USE_ASAN")) {

      if (getenv("AFL_USE_MSAN"))
        FATAL("ASAN and MSAN are mutually exclusive");

      if (getenv("AFL_HARDEN"))
        FATAL("ASAN and AFL_HARDEN are mutually exclusive");

      cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
      cc_params[cc_par_cnt++] = "-fsanitize=address";

    } else if (getenv("AFL_USE_MSAN")) {

      if (getenv("AFL_USE_ASAN"))
        FATAL("ASAN and MSAN are mutually exclusive");

      if (getenv("AFL_HARDEN"))
        FATAL("MSAN and AFL_HARDEN are mutually exclusive");

      cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
      cc_params[cc_par_cnt++] = "-fsanitize=memory";

    }

  }

#ifdef USE_TRACE_PC

  if (getenv("AFL_INST_RATIO"))
    FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'.");

#endif /* USE_TRACE_PC */

  if (!getenv("AFL_DONT_OPTIMIZE")) {

    cc_params[cc_par_cnt++] = "-g";
    cc_params[cc_par_cnt++] = "-O3";
    cc_params[cc_par_cnt++] = "-funroll-loops";

  }

  if (getenv("AFL_NO_BUILTIN")) {

    cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
    cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
    cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
    cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
    cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";

  }

  cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
  cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
  cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";

  /* When the user tries to use persistent or deferred forkserver modes by
     appending a single line to the program, we want to reliably inject a
     signature into the binary (to be picked up by afl-fuzz) and we want
     to call a function from the runtime .o file. This is unnecessarily
     painful for three reasons:

     1) We need to convince the compiler not to optimize out the signature.
        This is done with __attribute__((used)).

     2) We need to convince the linker, when called with -Wl,--gc-sections,
        not to do the same. This is done by forcing an assignment to a
        'volatile' pointer.

     3) We need to declare __afl_persistent_loop() in the global namespace,
        but doing this within a method in a class is hard - :: and extern "C"
        are forbidden and __attribute__((alias(...))) doesn't work. Hence the
        __asm__ aliasing trick.

   */

  cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)="
    "({ static volatile char *_B __attribute__((used)); "
    " _B = (char*)\"" PERSIST_SIG "\"; "
#ifdef __APPLE__
    "__attribute__((visibility(\"default\"))) "
    "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
    "__attribute__((visibility(\"default\"))) "
    "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
#endif /* ^__APPLE__ */
    "_L(_A); })";

  cc_params[cc_par_cnt++] = "-D__AFL_INIT()="
    "do { static volatile char *_A __attribute__((used)); "
    " _A = (char*)\"" DEFER_SIG "\"; "
#ifdef __APPLE__
    "__attribute__((visibility(\"default\"))) "
    "void _I(void) __asm__(\"___afl_manual_init\"); "
#else
    "__attribute__((visibility(\"default\"))) "
    "void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
    "_I(); } while (0)";

  if (maybe_linking) {

    if (x_set) {
      cc_params[cc_par_cnt++] = "-x";
      cc_params[cc_par_cnt++] = "none";
    }

    switch (bit_mode) {

      case 0:
        cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path);
        break;

      case 32:
        cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path);

        if (access(cc_params[cc_par_cnt - 1], R_OK))
          FATAL("-m32 is not supported by your compiler");

        break;

      case 64:
        cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path);

        if (access(cc_params[cc_par_cnt - 1], R_OK))
          FATAL("-m64 is not supported by your compiler");

        break;

    }

  }

  cc_params[cc_par_cnt] = NULL;

}
Example #11
0
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);

}
Example #12
0
int read_config_file(const char *filename, int *_argc, char ***_argv) {

  FILE *fh;
  char line[MAX_LINE_LEN + 1];
  char *val, *ptr;
  u8 *tmp;
  u32 idx, i;

  APPEND_STRING(fargv, fargc, ck_strdup((u8*)*_argv[0]));

  fh = fopen(filename, "r");
  if (!fh) PFATAL("Unable to read config from: %s", filename);

  while (!feof(fh) && fargc < MAX_ARGS && fgets(line, MAX_LINE_LEN, fh)) {

    /* Skip comments and empty lines */
    if (line[0] == '\n' || line[0] == '\r' || line[0] == '#')
      continue;

    /* NULL terminate the key */
    idx = strcspn(line, " \t=");
    if (idx == strlen(line))
      FATAL("Config key error at line: %s", line);
    line[idx] = '\0';

    /* Find the beginning of the value. */
    val = line + (idx + 1);
    idx = strspn(val, " \t=");
    if (idx == strlen(val))
      FATAL("Config value error at line: %s", line);
    val = val + idx;

    /* Trim the unwanted characters from the value */
    ptr = val + (strlen(val) - 1);
    while(*ptr && *ptr < 0x21) {
      *ptr = 0;
      ptr--;
    }

    /* Done! Now we have a key/value pair. If the flag is set to 'false'
       we will disregard this line. If the value is 'true', we will set
       the flag without a value. In any other case, we will set the flag
       and value */

    if (val[0] == '\0')
      FATAL("Empty value in config line: %s", line);

    if (strcasecmp("false", val) == 0)
      continue;

    tmp = ck_alloc(strlen(line) + 3);
    sprintf((char*)tmp, "--%s", line);

    APPEND_STRING(fargv, fargc, tmp);
    if (strncasecmp("true", val, 3) != 0)
      APPEND_STRING(fargv, fargc, ck_strdup((u8*)val));

  }

  /* Copy arguments from command line into our array */
  for (i=1; i<*_argc && fargc < MAX_ARGS; ++i)
    APPEND_STRING(fargv, fargc, ck_strdup((u8*)(*_argv)[i]));

  /* Replace original flags */
  *_argc = fargc;
  *_argv = (char **)fargv;

  fclose(fh);
  return 0;
}
Example #13
0
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;

}
Example #14
0
static void edit_params(int argc, char** argv) {

  u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
  u32 i;

  if (!tmp_dir) tmp_dir = "/tmp";

  as_params = ck_alloc((argc + 1) * sizeof(u8*));

  memcpy(as_params, argv, argc * sizeof(u8*));

  as_params[0] = afl_as ? afl_as : (u8*)"as";

  as_params[argc] = 0;

  for (i = 1; i < argc; i++) {

    if (!strcmp(as_params[i], "--64")) use_64bit = 1;
    else if (!strcmp(as_params[i], "--32")) use_64bit = 0;

#ifdef __APPLE__

    /* The Apple case is a bit different... */

    if (!strcmp(as_params[i], "-arch") && i + 1 < argc) {

      if (!strcmp(as_params[i + 1], "x86_64")) use_64bit = 1;
      else if (!strcmp(as_params[i + 1], "i386"))
        FATAL("Sorry, 32-bit Apple platforms are not supported.");

    }

#endif /* __APPLE__ */

  }

  input_file = as_params[argc - 1];

  if (input_file[0] == '-') {

    if (input_file[1]) FATAL("Incorrect use (not called through afl-gcc?)");
      else input_file = NULL;

  } else {

    /* Check if this looks like a standard invocation as a part of an attempt
       to compile a program, rather than using gcc on an ad-hoc .s file in
       a format we may not understand. This works around an issue compiling
       NSS. */

    if (strncmp(input_file, tmp_dir, strlen(tmp_dir)) &&
        strncmp(input_file, "/var/tmp/", 9) &&
        strncmp(input_file, "/tmp/", 5)) pass_thru = 1;

  }

  modified_file = alloc_printf("%s/.afl-%u-%u.s", tmp_dir, getpid(),
                               (u32)time(NULL));

  as_params[argc - 1] = modified_file;

}