📄 ratproxy.c
字号:
if (*x != '/') continue; /* "text/plain" */ if (strstr(res->payload,req->p.v2[i])) /* Text simply echoed back? */ continue; switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_AUTH: SHOW_MSG(2,"File path in query parameters",req->p.v2[i],m); break; case MOD_PRED: case MOD_PRED | MOD_AUTH: SHOW_MSG(3,"File path in query parameters",req->p.v2[i],m); break; } /* Report only once per URL. */ goto no_more_paths; } /* Non-echoed filenames are not necessarily evil, but worth examining. */ if (all_files) for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0] && strlen(req->p.v2[i]) < MAX_FPATH && strcmp(req->p.v1[i],"utmp") /* Analytics-specific again. */ ) { _u8* x = req->p.v2[i]; while (isalnum(*x) || *x == '_' || *x == '/') x++; if (*x == '.' && isalpha(x[1]) && isalpha(x[2]) && strlen(x+1) <= 5 && !strstr(res->payload,req->p.v2[i])) { m = get_modifiers(req,res); SHOW_MSG(1,"File name in query parameters",req->p.v2[i],m); break; } }no_more_paths: /* Java method names in a query are bad. */ for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0]) { _u8* x = strstr(req->p.v2[i],"com."); if (x && isalpha(x[4]) && strchr(x+4,'.') && !strstr(res->payload,req->p.v2[i]) && !strchr(x,'/')) { switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_AUTH: SHOW_MSG(2,"Java method call in query parameters",req->p.v2[i],m); break; case MOD_PRED: case MOD_PRED | MOD_AUTH: SHOW_MSG(3,"Java method call in query parameters",req->p.v2[i],m); break; } break; } } /* Javascript code in a query is bad; ignore alert(...) though, as this is almost always a sign of manual XSS testing, not a legitimate functionality. */ for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0]) { _u8* x = strchr(req->p.v2[i],'('); if (x && (x == req->p.v2[i] || isalpha(x[-1])) && strchr(x+1,')') && !rp_strcasestr(req->p.v2[i],"alert(") && strstr(res->payload,req->p.v2[i])) { switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_AUTH: SHOW_MSG(2,"Javascript code echoed back",req->p.v2[i],m); break; case MOD_PRED: case MOD_PRED | MOD_AUTH: SHOW_MSG(3,"Javascript code echoed back",req->p.v2[i],m); break; } break; } } /* SQL statement in a query is bad. */ for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0]) { _u8* x = rp_strcasestr(req->p.v2[i],"SELECT"); if (x && rp_strcasestr(x+1,"FROM") && !strstr(res->payload,req->p.v2[i])) { switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_AUTH: SHOW_MSG(2,"SQL code in query parameters",req->p.v2[i],m); break; case MOD_PRED: case MOD_PRED | MOD_AUTH: SHOW_MSG(3,"SQL code in query parameters",req->p.v2[i],m); break; } break; } } /* Check for OGNL-style parameter names. */ if (!req->non_param) for (i=0;i<req->p.c;i++) { if (!req->p.fn[i][0] && req->p.v1[i][0] && req->p.v2[i][0]) { _u8* x = strchr(req->p.v1[i] + 1, '.'); // 'user.lname' _u8* x1 = x ? strchr(x + 1, '.') : 0; // 'user.lname.foo' _u8* y = strchr(req->p.v1[i] + 1, '['); // 'users[0].lname' if (((x && x1) || y) && req->p.v1[i][0] != '[') { switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_AUTH: SHOW_MSG(1,"Suspicious parameter passing scheme",req->p.v1[i],m); break; case MOD_PRED: case MOD_PRED | MOD_AUTH: SHOW_MSG(2,"Suspicious parameter passing scheme",req->p.v1[i],m); break; } break; } } } /* Locate generic XSS candidates. */ if (try_attacks) if (try_replay_xss(req,res)) { m = get_modifiers(req,res); SHOW_MSG(3,"Confirmed XSS vectors",0,m); got_xss = 1; } if (all_xss && !got_xss && res->is_text) for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0] && xss_field(req->p.v2[i],0) && strstr(res->payload,req->p.v2[i])) { m = get_modifiers(req,res); if (!rp_strcasestr(BEST_MIME,"script") && strcasecmp(BEST_MIME,"application/json")) SHOW_MSG(0,"XSS candidates",req->p.v1[i],m); else SHOW_MSG(1,"XSS candidates (script)",req->p.v1[i],m); break; } for (i=0;i<req->p.c;i++) if (!req->p.fn[i][0] && xss_field(req->p.v2[i],1)) { _u32 j; for (j=0;j<res->h.c;j++) if (strstr(res->h.v2[j],req->p.v2[i])) { m = get_modifiers(req,res); SHOW_MSG(0,"Request splitting candidates",req->p.v1[i],m); goto xss_done; } }xss_done: /* Check for what looks like JSON with inline HTML (we skip standalone scripts, as they often contain static HTML to be rendered). We do some basic quote state tracking not to get confused by regular arithmetic. No comment tracking, but that shouldn't break easily. */ if ((rp_strcasestr(BEST_MIME,"script") || !strcasecmp(BEST_MIME,"application/json")) && !standalone_script(res->payload)) { _u8* p = res->payload, qstate = 0, got_html = 0, esc_next = 0, pv = ' '; do { if (esc_next) { esc_next = 0; continue; } /* TODO: This should be replaced with a proper Javascript analyzer. */ switch (*p) { case '\\': esc_next = 1; break; case '\'': case '"': if (qstate == *p) qstate = 0; else if (!qstate) qstate = *p; break; case '<': if (qstate) got_html = 1; break; case '>': if (qstate && got_html) got_html = 2; break; } } while (got_html < 2 && (pv=*(p++))); if (got_html == 2) { switch (NOECHO(m = get_modifiers(req,res))) { case 0: case MOD_PRED: case MOD_AUTH: SHOW_MSG(1,"Markup in dynamic Javascript",0,m); break; case MOD_AUTH | MOD_PRED: SHOW_MSG(ECHO(m) ? 2 : 1,"Markup in dynamic Javascript",0,m); break; } } } if (all_flash && !strcasecmp(BEST_MIME,"application/x-shockwave-flash")) { m = get_modifiers(req,res); SHOW_MSG(0,"All Flash applications",0,m); if (trace_dir) decode_flash(res); } /* TODO: Add more index checks and other troubling server responses. */ if (strstr(res->payload,">[To Parent Directory]<") || strstr(res->payload,"<title>Index of /")) { m = get_modifiers(req,res); SHOW_MSG(0,"Directory indexes",0,m); } /* TODO: This should be replaced with a proper Javascript analyzer. */ if (bad_js && res->is_text && ( rp_strcasestr(res->payload,".write(") || rp_strcasestr(res->payload,".writeln("))) { m = get_modifiers(req,res); SHOW_MSG(1,"Risky Javascript code","document.write",m); } if (bad_js && res->is_text && (rp_strcasestr(res->payload,".innerHtml") || rp_strcasestr(res->payload,".outerHtml"))) { m = get_modifiers(req,res); SHOW_MSG(1,"Risky Javascript code","innerHTML",m); } if (bad_js && res->is_text && rp_strcasestr(res->payload,"document.referrer")) { m = get_modifiers(req,res); SHOW_MSG(2,"Risky Javascript code","document.referrer",m); } if (bad_js && res->is_text && rp_strcasestr(res->payload,"document.domain")) { m = get_modifiers(req,res); SHOW_MSG(2,"Risky Javascript code","document.domain",m); }skip_tests: fflush(outfile); exit(0);}static void listen_loop(void) { _s32 lsock, csock, on = 1; _u32 x; static struct sockaddr_in saddr; lsock=socket(AF_INET, SOCK_STREAM, 0); if (lsock < 0) pfatal("cannot create socket"); if (setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(_s32)) == -1) pfatal("cannot setsockopt()"); saddr.sin_family = AF_INET; if (!use_any) { saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } else { saddr.sin_addr.s_addr = htonl(INADDR_ANY); } saddr.sin_port = htons(use_port); x = sizeof(saddr); if (bind(lsock, (struct sockaddr*)&saddr, x)) pfatal("cannot bind to port"); if (listen(lsock, 10)) pfatal("listen() failed"); debug("[*] Proxy configured successfully. Have fun, and please do not be evil.\n"); if (use_proxy) debug(" Upstream proxy is %s:%u\n",use_proxy,proxy_port); if (try_attacks) debug(" WARNING: Disruptive tests enabled. use with care.\n"); debug("[+] Accepting connections on port %u/tcp (%s)...\n", use_port, use_any ? "any source" : "local only"); while ((csock = accept(lsock, (struct sockaddr*)&saddr, &x)) >= 0) { /* Bury zombies */ while (waitpid(-1,&x,WNOHANG) > 0); if (!fork()) { FILE* client; close(lsock); client = fdopen(csock,"w+"); if (!client) fatal("fdopen() failed"); handle_client(client); /* Not reached */ exit(0); } close(csock); } pfatal("accept() failed");} int main(int argc, char** argv) { _s32 opt; _u8* x; signal(SIGPIPE, SIG_IGN); debug("ratproxy version " VERSION " by <lcamtuf@google.com>\n"); while ((opt = getopt(argc,argv,"+w:v:p:d:P:itxgjmafske2clXCr")) > 0) switch (opt) { case 'w': { _s32 f; if (outfile) fatal("multiple -w options make no sense"); unlink(optarg); /* Ignore errors */ f = open(optarg,O_WRONLY|O_CREAT|O_EXCL,0600); if (f < 0) pfatal("cannot open log file"); outfile = fdopen(f,"w"); if (!outfile) pfatal("fdopen failed"); } break; case 'v': { if (trace_dir) fatal("multiple -v options make no sense"); trace_dir = optarg; mkdir(trace_dir,0700); /* Ignore errors */ if (access(trace_dir,X_OK)) pfatal("cannot create -v directory"); } break; case 'p': use_port = atoi(optarg); if (!use_port || use_port > 65535) fatal("invalid -p value"); break; case 'P': use_proxy = optarg; x = strchr(optarg,':'); if (!x) break; *(x++) = 0; proxy_port = atoi(x); if (!proxy_port || proxy_port > 65535) fatal("invalid proxy port"); break; case '2': use_double = 1; break; case 'd': ADD(domains,optarg); break; case 'i': check_png = 1; break; case 'e': picky_cache = 1; break; case 't': all_files = 1; break; case 'f': all_flash = 1; break; case 'x': all_xss = 1; break; case 'g': get_xsrf = 1; break; case 'j': bad_js = 1; break; case 'l': use_len = 1; break; case 's': all_post = 1; break; case 'a': dump_urls = 1; break; case 'c': all_cookie = 1; break; case 'X': try_attacks = 1; break; case 'm': log_active = 1; break; case 'C': fix_attacks = 1; break; case 'k': log_mixed = 1; break; case 'r': use_any = 1; break; default: usage(argv[0]); } if (optind != argc) usage(argv[0]); if (optind == 1) debug("\n[!] WARNING: Running with no command-line config options specified. This is\n" " almost certainly not what you want, as most checks are disabled. Please\n" " consult the documentation or use --help for more information.\n\n"); else if (!domains.c) debug("\n[!] WARNING: Running with no 'friendly' domains specified. Many cross-domain\n" " checks will not work. Please consult the documentation for advice.\n\n"); if (!outfile) outfile = stdout; listen_loop(); /* Not reached */ return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -