⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ratproxy.c

📁 Google 推出一套免費的 Web 安全評估工具
💻 C
📖 第 1 页 / 共 4 页
字号:
      /* <tag><script>... */      if (htmlstate == 0 && !strncasecmp(cur+2,"<qg",3)) return 1;      /* <tag>+ADw-script+AD4-... */      if (htmlstate == 0 && (!not->charset || not->bad_cset) && !strncasecmp(cur+2,"+qg",3)) return 1;      /* <tag foo="bar"onload=...> */      if (htmlstate == (HS_IN_TAG|HS_IN_DBLQ) && !strncasecmp(cur+2,"\"qg",3)) return 1;      /* <tag foo='bar'onload=...> */      if (htmlstate == (HS_IN_TAG|HS_IN_SNGQ) && !strncasecmp(cur+2,"'qg",3)) return 1;    } else {      /* Handle CDATA blocks */      if (htmlstate == 0 && !strncasecmp(cur,"<![CDATA[",9)) { htmlstate = HS_IN_CDATA; cur += 9; continue; }      if (htmlstate == HS_IN_CDATA && !strncmp(cur,"]]>",3)) { htmlstate = 0; cur += 3; continue; }      /* Handle <!-- --> blocks (this depends on rendering mode, but hey). */      if (htmlstate == 0 && !strncmp(cur,"<!--",4)) { htmlstate = HS_IN_COMM; cur += 4; continue; }      if (htmlstate == HS_IN_COMM && !strncmp(cur,"-->",3)) { htmlstate = 0; cur += 3; continue; }      /* Detect what could pass for tag opening / closure... */      if (htmlstate == 0 && *cur == '<' && (isalpha(cur[1]) || cur[1] == '!' || cur[1] == '?')) { htmlstate = HS_IN_TAG; cur++; continue; }      if (htmlstate == HS_IN_TAG && *cur == '>') { htmlstate = 0; htmlurl = 0; cur++; continue; }       /* Handle double quotes around HTML parameters */      if (htmlstate == HS_IN_TAG && cur[-1] == '=' && *cur == '"') { htmlstate |= HS_IN_DBLQ; cur++; continue; }      if (htmlstate == (HS_IN_TAG|HS_IN_DBLQ) && *cur == '"') { htmlstate = HS_IN_TAG; cur++; continue; }      /* Handle single quotes around HTML parameters */      if (htmlstate == HS_IN_TAG && cur[-1] == '=' && *cur == '\'') { htmlstate |= HS_IN_SNGQ; cur++; continue; }      if (htmlstate == (HS_IN_TAG|HS_IN_SNGQ) && *cur == '\'') { htmlstate = HS_IN_TAG; cur++; continue; }      /* Special handling for SRC= and HREF= locations. */      if (htmlstate == HS_IN_TAG && isspace(cur[-1]) && !strncasecmp(cur,"href=",5)) {        htmlurl = 1; cur += 5; continue;      }      if (htmlstate == HS_IN_TAG && isspace(cur[-1]) && !strncasecmp(cur,"src=",4)) {        htmlurl = 1; cur += 4; continue;      }      /* Cancel mode if any character other than ", ', or qg: URL is encountered. */      if (htmlurl) htmlurl = 0;    }    cur++;  }  /* So, no XSS? Bummer. */  return 0;}/* Check for publicly cacheable documents. Returns 0 if not public,   1 if apparently meant to be public, 2 if partly protected. */static _u8 is_public(struct http_request* req, struct http_response* res) {  _u8 http10intent;  /* "Expires" and "Pragma" should say the same. */  if (res->pr10intent && res->ex10intent && res->pr10intent != res->ex10intent) return 2;  http10intent = res->ex10intent ? res->ex10intent : res->pr10intent;  /* HTTP/1.0 and HTTP/1.1 intents should say the same. */  if (http10intent && res->cc11intent && http10intent != res->cc11intent) return 2;  /* [Picky] HTTP/1.0 and HTTP/1.1 intents should not appear at all, or appear at once */  if (picky_cache && (http10intent ^ res->cc11intent)) {    if (strcmp(req->method,"GET")) return 0; /* Non-GET requests won't be cached. */    return 2;  }  if (res->cc11intent == INTENT_PRIV || http10intent == INTENT_PRIV) return 0;  /* No interest in making this document private was expressed... */  if (strcmp(req->method,"GET")) return 0; /* Non-GET requests won't be cached. */  return 1;}static _u8 dump_fn[1024];static _u8 dumped_already;/* Save trace data to file, if requested. */static _u8* save_trace(struct http_request* req, struct http_response* res) {  _s32 f;  _u32 i;  FILE* out;  if (!trace_dir) return "-";  /* Do not save the same request twice. */  if (dumped_already) return dump_fn;  dumped_already = 1;  sprintf(dump_fn,"%.512s/%08x-%04x.trace",trace_dir,(_u32)time(0),getpid());  f = open(dump_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);  if (f < 0) {        debug(">>> Unable to open trace file '%s'! <<<\n",dump_fn);    return "-";  }   out = fdopen(f,"w");  fprintf(out,"== REQUEST TO %s:%u (%u headers, %u byte payload) ==\n\n%s /%s%s%s HTTP/1.0\n",     req->host, req->port, req->h.c, req->payload_len,     req->method, req->path, req->query ? "?" : "", req->query ? req->query : (_u8*)"");  for (i=0;i<req->h.c;i++)    fprintf(out,"%s: %s\n", req->h.v1[i], req->h.v2[i]);  fprintf(out,"\n");  if (req->payload_len)    fwrite(req->payload,req->payload_len > MAXTRACEITEM ? MAXTRACEITEM : req->payload_len,1,out);  if (req->payload_len > MAXTRACEITEM)     fprintf(out,"\n*** DATA TRUNCATED DUE TO SIZE LIMITS ***");  fprintf(out,"\n\n== SERVER RESPONSE (%u headers, %u byte payload, detected MIME %s) ==\n\n"    "HTTP/1.0 %u \n",    res->h.c, res->payload_len, res->mime_type ? res->mime_type : (_u8*)"(none)",    res->code);  for (i=0;i<res->h.c;i++)    fprintf(out,"%s: %s\n", res->h.v1[i], res->h.v2[i]);  fprintf(out,"\n");  if (res->payload_len)    fwrite(res->payload,res->payload_len > MAXTRACEITEM ? MAXTRACEITEM : res->payload_len,1,out);  if (res->payload_len > MAXTRACEITEM)     fprintf(out,"\n*** DATA TRUNCATED DUE TO SIZE LIMITS ***");  fprintf(out,"\n\n== END OF TRANSACTION ==\n");  fclose(out);  close(f);  return dump_fn;}/* Use Flare to decode Flash file, if available. */static void decode_flash(struct http_response* res) {  _s32 f, pid;  _u8 tmp[1024];  struct stat st;  if (!dumped_already || !res->payload_len) return; /* ? */  sprintf(tmp,"%s.swf",dump_fn);  f = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600);  if (f < 0) return;  write(f, res->payload, res->payload_len);  close(f);  if (!(pid = fork())) {    /* Flare is way too noisy, let's close stderr. */    close(2);    execl("./flare","flare",tmp,NULL);    execlp("flare","flare",tmp,NULL);    exit(1);  }  if (pid > 0) waitpid(pid, (int*)&f, 0);  unlink(tmp);  sprintf(tmp,"%s.flr",dump_fn);  if (stat(tmp,&st) || !st.st_size) unlink(tmp);  /* So we should have a non-zero length .flr file next to a trace file     now; ratproxy-report.sh will detect this. */}/* A "fuzzy" comparator to avoid reporting "refresher" cookies where some minor parameters   were changed as new cookie arrivals; but to detect blanking or other major overwrites. */static _u8 unique_cookies(struct naive_list2* reqc, struct naive_list2* resc) {  _u32 i,j;  if (!resc->c) return 0; /* No cookies set at all. */  if (!reqc->c) return 1; /* All set cookies must be new. */  for (i=0;i<resc->c;i++) {    for (j=0;j<reqc->c;j++) {      if (!strcasecmp(resc->v1[i],reqc->v1[j]) &&       /* Same name   */          strlen(resc->v2[i]) == strlen(reqc->v2[j]))   /* Same length */            break; /* ...must be a refresher cookie. */    }    /* No refresher cookie matches for one cookie? Good enough. */    if (j == reqc->c) return 1;  }  /* All cookies were refreshers. */  return 0;}/* Cookie renderer, for reporting purposes. */static _u8* make_cookies(struct naive_list2* reqc, struct naive_list2* resc) {  _u8* ret = 0;  _u32 i,j;  _u8 had_some = 0;  if (!resc->c) return "-";#define ALLOC_STRCAT(dest,src) do { \    _u32 _sl = strlen(src); \    _u32 _dl = 0; \    if (dest) _dl = strlen(dest); \    dest = realloc(dest,_sl + _dl + 1); \    if (!dest) fatal("out of memory"); \    strcpy(dest + _dl, src); \  } while (0)  for (i=0;i<resc->c;i++) {    /* Render only newly set cookies! */    for (j=0;j<reqc->c;j++) {      if (!strcasecmp(resc->v1[i],reqc->v1[j]) &&       /* Same name   */          strlen(resc->v2[i]) == strlen(reqc->v2[j]))   /* Same length */            break; /* ...must be a refresher cookie. */    }    if (j == reqc->c) {      if (!had_some) had_some = 1; else ALLOC_STRCAT(ret,"; ");      ALLOC_STRCAT(ret,resc->v1[i]);      ALLOC_STRCAT(ret,"=");      ALLOC_STRCAT(ret,resc->v2[i]);    }  }  return ret ? ret : (_u8*)"-";}/* Check for safe JSON prologues. */static _u8 is_json_safe(_u8* str) {  _u32 i = 0;  while (json_safe[i]) {    if (!strncmp(str,json_safe[i],strlen(json_safe[i]))) return 1;    i++;  }  return 0;}/* Check for scripts that appear to be standalone or empty (as opposed to   JSON-like dynamically generated response snippets for on-page execution). */static _u8 standalone_script(_u8* str) {  if (!str) return 1; /* Empty */skip_more:  while (*str && isspace(*str)) str++;  if (!strncmp(str,"/*",2)) {    str = strstr(str+2, "*/");    if (!str) return 1; /* Empty */    goto skip_more;  }  if (!strncmp(str,"//",2)) {    str += 2;    while (*str && strchr("\r\n",*str)) str++;    goto skip_more;  }  if (*str == '(') { str++; goto skip_more; }  if (!*str) return 1; /* Empty */  /* This is not very scientific - in fact, there is no good way to     settle this - but should be a pretty good predictor in most cases. */  if (!strncasecmp(str,"var",3) && isspace(str[3])) return 1; /* Script */  if (!strncasecmp(str,"function",8) && isspace(str[8])) return 1; /* Script */  return 0; /* Probably JSON */}/* The main request handling and routing routine. */static void handle_client(FILE* client) {  FILE *server;  struct http_request* req;  struct http_response* res;  _u8 m;  _u32 i;  _u8 got_xss = 0;#define BEST_MIME (res->sniffed_mime ? res->sniffed_mime : \                   (res->mime_type ? res->mime_type : (_u8*)""))  /* TODO: Ideally, S() shouldn't do HTML escaping in machine     output (just filter | and control chars); but this requires     ratproxy-report.sh to be reworked. */// Request printer macros - since most of the data does not change.#define SHOW_REF_MSG(warn,mesg,mod) \    sayf("%u|%u|%s|-|%u|%u|%s|http%s://%s:%u/%s%s%s|-|%s|-|%s|-|-|-\n", \      warn, mod, mesg, res->code, res->payload_len, res->mime_type ? \      res->mime_type : (_u8*)"-", req->from_ssl ? "s" : "", S(req->host,0), req->port, \      S(req->path,0), req->query ? "?" : "", req->query ? \      S(req->query,0) : (_u8*)"", save_trace(req,res), S(req->referer,0))#define SHOW_MSG(warn,mesg,off_par,mod) \    sayf("%u|%u|%s|%s|%u|%u|%s|%s|%s|%s|%s|http%s://%s:%u/%s%s%s|%s|%s|%s\n", \      warn, mod ,mesg, off_par ? S(off_par,0) : (_u8*)"-", \      res->code, res->payload_len, \      res->mime_type ? S(res->mime_type,0) : (_u8*)"-", \      res->sniffed_mime ? S(res->sniffed_mime,0) : (_u8*)"-", \      res->charset ? S(res->charset,0) : (_u8*)"-", \      save_trace(req,res), \      S(req->method,0), req->from_ssl ? "s" : "", S(req->host,0), \      req->port, S(req->path,0), req->query ? "?" : "", \      req->query ? S(req->query,0) : (_u8*)"", \      S(make_cookies(&req->cookies,&res->cookies),0), \      req->payload_len ? S(stringify_payload(req),0) : (_u8*)"-", \      res->payload_len ? S(res->payload,0) : (_u8*)"-")   /* First, let's collect and complete the request */  req = collect_request(client,0,0);  server = open_server_complete(client, req);  if (req->is_connect) {    ssl_setup();    ssl_start(fileno(server),fileno(client));    fclose(client); fclose(server);    client = fdopen(ssl_cli_tap,"w+");    server = fdopen(ssl_srv_tap,"w+");    if (!client || !server) fatal("out of memory");    req = collect_request(client, req->host, req->port);  }  res = send_request(client, server, req, 0);  send_response(client,res);  if (req->from_ssl) ssl_shutdown();  /* Now, if the target is not within the set of tested domains,     there are several things we want to check if it originated     from within the tested locations. */  if (!host_ok(req->host)) {    _u8 *refq;    if (!req->ref_host) goto skip_tests;    /* Requests between non-analyzed sites do not concern us. */    if (!host_ok(req->ref_host)) goto skip_tests;    /* Referer token leakage test: contains_token() succeeds on "Referer" query */    if ((refq=strchr(req->referer,'?'))) {      struct naive_list_p p = { 0, 0, 0, 0, 0 };      _u32 i;      parse_urlencoded(&p,refq + 1);            for (i=0;i<p.c;i++)        if (contains_token(p.v1[i],p.v2[i])) break;      if (i != p.c)        SHOW_REF_MSG(3,"Referer may leak session tokens",1);    }    /* Cross-domain script inclusion check */    detect_mime(res);    if (rp_strcasestr(BEST_MIME,"script") ||         !strcasecmp(BEST_MIME,"application/json")|| !strcasecmp(BEST_MIME,"text/css"))       SHOW_REF_MSG(3,"External code inclusion",1);    /* POST requests between domains - outgoing. */    if (strcmp(req->method,"GET")) {      SHOW_REF_MSG(2,"Cross-domain POST requests",0);    } else if (log_active) {          i = 0;      while (active_mime[i]) {        if (!strcasecmp(BEST_MIME,active_mime[i])) {          SHOW_REF_MSG(1,"References to external active content",1);          break;        }        i++;      }    }    goto skip_tests;  }  /* All right, everything below pertains to checks on URLs within     the tested domain. Let's do some basic information gathering first. */  checksum_response(res);  detect_mime(res);  if (res->is_text)    detect_charset(res);  if (dump_urls) SHOW_MSG(0,"!All visited URLs",0,0);  /* If requested to do so, we need to log non-HTTPS traffic and     prioritize it depending on document type. */  if (log_mixed && !req->from_ssl) {    m = get_modifiers(req,res);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -