From 70c598ee3293bf97d532c10e5a7c610b3a42b224 Mon Sep 17 00:00:00 2001 From: ajuaristi Date: Sun, 29 Jun 2014 03:28:12 +0200 Subject: [PATCH] Added -h and -H options support for direct HTTP GET/POST requests. --- hydra-http-form.c | 476 ++++++++++++++++++++-------------------------- 1 file changed, 207 insertions(+), 269 deletions(-) diff --git a/hydra-http-form.c b/hydra-http-form.c index 2a5517a..7971752 100644 --- a/hydra-http-form.c +++ b/hydra-http-form.c @@ -52,10 +52,24 @@ Added fail or success condition, getting cookies, and allow 5 redirections by da #include "hydra-mod.h" +/* HTTP Request Options */ +#define OPT_PROXY_AUTH 1 +#define OPT_PROXY_NOAUTH 2 +#define OPT_NOPROXY 4 +#define OPT_GETCOOKIES 8 + +/* Default HTTP Headers */ +#define DEFAULT_HOST 1 +#define DEFAULT_USER_AGENT 2 +#define DEFAULT_CONTENT_TYPE 4 + +#define MAX_REQ_LEN 1030 + extern char *HYDRA_EXIT; char *buf; char *cond; +char http_request[MAX_REQ_LEN]; typedef struct header_node { char *header; char *value; @@ -76,10 +90,40 @@ char cookie[4096] = "", cmiscptr[1024]; extern char *webtarget; extern char *slash; int webport, freemischttpform = 0; +int http_opts; char bufferurl[1024], cookieurl[1024] = "", userheader[1024] = "", *url, *variables, *optional1; ptr_header_node ptr_head = NULL; +void prepare_httpreq(char * method, char * path){ + char tail[] = " HTTP/1.0"; + int req_len = (strlen(method) + strlen(path) + 1) <= MAX_REQ_LEN ? (strlen(method) + strlen(path) + 1) : MAX_REQ_LEN; + + memset(http_request, 0, MAX_REQ_LEN); + + if(strcmp(method, "GET") == 0) + strcat(http_request, "GET "); + else if(strcmp(method, "POST") == 0) + strcat(http_request, "POST "); + + strncat(http_request, path, MAX_REQ_LEN - sizeof(tail) - 5); + strcat(http_request, tail); +} + +/* + * Returns 1 if specified header exists, or 0 otherwise. + */ +int header_exists(char * header){ + ptr_header_node cur_ptr = NULL; + int header_exists = 0; + + for(cur_ptr = ptr_head; cur_ptr && !header_exists; cur_ptr = cur_ptr->next) + if(cur_ptr->header && strcmp(cur_ptr->header, header) == 0) + header_exists = 1; + + return header_exists; +} + /* * Returns 1 if success, or 0 otherwise (out of memory). */ @@ -107,9 +151,9 @@ int add_header(char *header, char *value){ ptr_head = new_ptr; // TODO Remove the debug messages - hydra_report_debug(stdout, "[add_header] Added header %s: %s", header, value); - hydra_report_debug(stdout, "[add_header] len(header) = %d", strlen(header)); - hydra_report_debug(stdout, "[add_header] len(value) = %d", strlen(value)); +// hydra_report(stdout, "[add_header] Added header %s: %s\n", header, value); +// hydra_report(stdout, "[add_header] len(header) = %d", strlen(header)); +// hydra_report(stdout, "[add_header] len(value) = %d", strlen(value)); return 1; } @@ -129,7 +173,7 @@ int add_or_replace_header(char *header, char *value){ for(cur_ptr = ptr_head; cur_ptr; cur_ptr = cur_ptr->next){ if(strcmp(cur_ptr->header, header) == 0){ - free(cur_ptr->value); + //free(cur_ptr->value); cur_ptr->value = value; break; } @@ -139,42 +183,101 @@ int add_or_replace_header(char *header, char *value){ return add_header(header, value); // TODO Remove the debug messages - hydra_report_debug(stdout, "[add_or_replace_header] Added header %s: %s", header, value); - hydra_report_debug(stdout, "[add_or_replace_header] len(header) = %d", strlen(header)); - hydra_report_debug(stdout, "[add_or_replace_header] len(value) = %d", strlen(value)); +// hydra_report(stdout, "[add_or_replace_header] Added header %s: %s\n", header, value); +// hydra_report(stdout, "[add_or_replace_header] len(header) = %d", strlen(header)); +// hydra_report(stdout, "[add_or_replace_header] len(value) = %d", strlen(value)); return 1; } +/* + * Replace in all headers' values every occurrence of oldvalue by newvalue. + */ +void hdrrep(char * oldvalue, char * newvalue){ + ptr_header_node cur_ptr = NULL; + + for(cur_ptr = ptr_head; cur_ptr; cur_ptr = cur_ptr->next){ + if(strstr(cur_ptr->value, oldvalue)){ + cur_ptr->value = (char *) realloc(cur_ptr->value, strlen(newvalue)); + if(cur_ptr->value) + strcpy(cur_ptr->value, newvalue); + else{ + hydra_report(stderr, "[ERROR] Out of memory."); + hydra_child_exit(1); + } + } + } +} + +int add_default_headers(int default_header_opts){ + int retval = 0; + + char * header = (char *) malloc(sizeof(char) * 80); + char * value = (char *) malloc(sizeof(char) * 80); + + if(header && value){ + if((default_header_opts & OPT_PROXY_AUTH) == OPT_PROXY_AUTH){ + memset(header, 0, 80); + memset(value, 0, 80); + strcpy(header, "Proxy-Authorization"); + strcpy(value, "Basic "); + strncat(value, proxy_authentication, 73); + retval &= add_header(header, value); + retval &= add_header("User-Agent", "Mozilla/5.0 (Hydra Proxy Auth)"); + } + + if((default_header_opts & OPT_PROXY_NOAUTH) == OPT_PROXY_NOAUTH){ + retval &= add_or_replace_header("User-Agent", "Mozilla/5.0 (Hydra Proxy)"); + } + + if((default_header_opts & OPT_NOPROXY) == OPT_NOPROXY){ + + } + + if((default_header_opts & OPT_GETCOOKIES) == OPT_GETCOOKIES){ + + } + } + + return retval; +} + /* * Concat all the headers in the list in a single string, and clean the whole list. */ char * stringify_headers_and_clean(){ char * headers_str = NULL; ptr_header_node cur_ptr = ptr_head, tmp_ptr = NULL; - int ttl_size = 0; + int ttl_size = strlen(http_request); while(cur_ptr){ if(cur_ptr->header && cur_ptr->value){ // Check for NULLs ttl_size += strlen(cur_ptr->header) + strlen(cur_ptr->value) + 1; - headers_str = (char *) realloc(headers_str, sizeof(char) * ttl_size); + if(headers_str) + headers_str = (char *) realloc(headers_str, sizeof(char) * ttl_size); + else{ + // Garbage appears when strcat()-ing, if we don't blank newly allocated memory + headers_str = (char *) malloc(sizeof(char) * ttl_size); + if(headers_str) + memset(headers_str, 0, sizeof(char) * ttl_size); + } if(headers_str){ // Check for errors - strcat(headers_str, cur_ptr->header); - strcat(headers_str, ": "); - strcat(headers_str, cur_ptr->value); - strcat(headers_str, "\r\n"); + strcat(headers_str, cur_ptr->header); + strcat(headers_str, ": "); + strcat(headers_str, cur_ptr->value); + strcat(headers_str, "\r\n"); }else{ - // Error: out of memory - hydra_report(stderr, "Out of memory for HTTP headers"); - hydra_child_exit(1); + // Error: out of memory + hydra_report(stderr, "Out of memory for HTTP headers"); + hydra_child_exit(1); } } // Clean it up and get to the next header tmp_ptr = cur_ptr; cur_ptr = cur_ptr->next; - free(tmp_ptr->header); - free(tmp_ptr->value); - free(tmp_ptr); + //free(tmp_ptr->header); + //free(tmp_ptr->value); + //free(tmp_ptr); } return headers_str; @@ -328,250 +431,38 @@ void hydra_reconnect(int s, char *ip, int port, unsigned char options) { int start_http_form(int s, char *ip, int port, unsigned char options, char *miscptr, FILE * fp, char *type) { char *empty = ""; - char *login, *pass, buffer[9000], clogin[256], cpass[256]; + char *login, *pass, clogin[256], cpass[256]; + char *buffer; // Buffer for HTTP headers char header[8096], *upd3variables, cuserheader[1024]; int found = !success_cond, i, j; memset(header, 0, sizeof(header)); cookie[0] = 0; // reset cookies from potential previous attempt + // Take the next login/pass pair if (strlen(login = hydra_get_next_login()) == 0) - login = empty; - if (strlen(pass = hydra_get_next_password()) == 0) - pass = empty; - strncpy(clogin, html_encode(login), sizeof(clogin) - 1); - clogin[sizeof(clogin) - 1] = 0; - strncpy(cpass, html_encode(pass), sizeof(cpass) - 1); - cpass[sizeof(cpass) - 1] = 0; - upd3variables = hydra_strrep(variables, "^USER^", clogin); - upd3variables = hydra_strrep(upd3variables, "^PASS^", cpass); - if (strstr(userheader, "^USER^") == NULL && strstr(userheader, "^PASS^") == NULL) { - strcpy(cuserheader, userheader); - } else { // we use the encoded version - strncpy(cuserheader, hydra_strrep(userheader, "^USER^", clogin), sizeof(cuserheader) - 1); - cuserheader[sizeof(cuserheader) - 1] = 0; - strncpy(cuserheader, hydra_strrep(cuserheader, "^PASS^", cpass), sizeof(cuserheader) - 1); - cuserheader[sizeof(cuserheader) - 1] = 0; - } + login = empty; + if (strlen(pass = hydra_get_next_password()) == 0) + pass = empty; + strncpy(clogin, html_encode(login), sizeof(clogin) - 1); + clogin[sizeof(clogin) - 1] = 0; + strncpy(cpass, html_encode(pass), sizeof(cpass) - 1); + cpass[sizeof(cpass) - 1] = 0; - /* again: no snprintf to be portable. dont worry, buffer cant overflow */ - if (use_proxy == 1 && proxy_authentication != NULL) { - // proxy with authentication - if (getcookie) { - //doing a GET to save cookies - sprintf(buffer, "GET http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nProxy-Authorization: Basic %s\r\nUser-Agent: Mozilla 5.0 (Hydra Proxy Auth)\r\n%s%s\r\n", - webtarget, webport, cookieurl, webtarget, proxy_authentication, header, cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - i = analyze_server_response(s); // return value ignored - if (strlen(cookie) > 0) { - sprintf(header, "Cookie: %s\r\n", cookie); - } - hydra_reconnect(s, ip, port, options); - } + // Replace the user/pass placeholders in the command line options + upd3variables = hydra_strrep(variables, "^USER^", clogin); + upd3variables = hydra_strrep(upd3variables, "^PASS^", cpass); - if (strcmp(type, "POST") == 0) { - sprintf(buffer, - "POST http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nProxy-Authorization: Basic %s\r\nUser-Agent: Mozilla/5.0 (Hydra Proxy Auth)\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s%s\r\n%s", - webtarget, webport, url, webtarget, proxy_authentication, (int) strlen(upd3variables), header, cuserheader, upd3variables); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } else { - sprintf(buffer, - "GET http://%s:%d%.600s?%s HTTP/1.0\r\nHost: %s\r\nProxy-Authorization: Basic %s\r\nUser-Agent: Mozilla/5.0 (Hydra Proxy Auth)\r\n%s%s\r\n", - webtarget, webport, url, upd3variables, webtarget, proxy_authentication, header, cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } - } else { - if (use_proxy == 1) { - // proxy without authentication - if (getcookie) { - //doing a GET to get cookies - sprintf(buffer, "GET http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra Proxy)\r\n%s%s\r\n", webtarget, webport, cookieurl, webtarget, header, - cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - i = analyze_server_response(s); // ignore result - if (strlen(cookie) > 0) { - sprintf(header, "Cookie: %s\r\n", cookie); - } - hydra_reconnect(s, ip, port, options); - } + // Replace the user/pass placeholders in the user-supplied headers + hdrrep("^USER^", clogin); + hdrrep("^PASS^", cpass); - if (strcmp(type, "POST") == 0) { - sprintf(buffer, - "POST http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s%s\r\n%s", - webtarget, webport, url, webtarget, (int) strlen(upd3variables), header, cuserheader, upd3variables); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } else { - sprintf(buffer, "GET http://%s:%d%.600s?%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\n%s%s\r\n", webtarget, webport, url, upd3variables, webtarget, - header, cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } - } else { - // direct web server, no proxy - if (getcookie) { - //doing a GET to save cookies - sprintf(buffer, "GET %.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\n%s\r\n", cookieurl, webtarget, cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - i = analyze_server_response(s); // ignore result - if (strlen(cookie) > 0) { - sprintf(header, "Cookie: %s\r\n", cookie); - } - hydra_reconnect(s, ip, port, options); - } +////////////////////////////////////////////////////////////////////////////////////////////////////////// - if (strcmp(type, "POST") == 0) { - sprintf(buffer, - "POST %.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s%s\r\n%s", - url, webtarget, (int) strlen(upd3variables), header, cuserheader, upd3variables); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } else { - sprintf(buffer, "GET %.600s?%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Hydra)\r\n%s%s\r\n", url, upd3variables, webtarget, header, cuserheader); - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - } - } - } + buffer = stringify_headers_and_clean(); + hydra_report(stdout, "HTTP headers:\n%s\r\n%s", http_request, buffer); - found = analyze_server_response(s); - if (auth_flag) { // we received a 401 error - user using wrong module - hydra_report(stderr, "[ERROR] the target is using HTTP auth, not a web form, received HTTP error code 401. Use module \"http%s-get\" instead.\n", - (options & OPTION_SSL) > 0 ? "s" : ""); - return 4; - } - if (strlen(cookie) > 0) { - sprintf(header, "Cookie: %.1000s\r\n", cookie); - } - //if page was redirected, follow the location header - redirected_cpt = MAX_REDIRECT; - if (debug) - printf("[DEBUG] attempt result: found %d, redirect %d, location: %s\n", found, redirected_flag, redirected_url_buff); - while (found == 0 && redirected_flag && (redirected_url_buff[0] != 0) && (redirected_cpt > 0)) { - //we have to split the location - char *startloc, *endloc; - char str[2048]; - char str2[2048]; - char str3[2048]; - - redirected_cpt--; - redirected_flag = 0; - //check if the redirect page contains the fail/success condition -#ifdef HAVE_PCRE - if (hydra_string_match(redirected_url_buff, cond) == 1) { -#else - if (strstr(redirected_url_buff, cond) != NULL) { -#endif - found = success_cond; - } else { - //location could be either absolute http(s):// or / something - //or relative - startloc = strstr(redirected_url_buff, "://"); - if (startloc != NULL) { - startloc += strlen("://"); - - if ((endloc = strchr(startloc, '\r')) != NULL) { - startloc[endloc - startloc] = 0; - } - if ((endloc = strchr(startloc, '\n')) != NULL) { - startloc[endloc - startloc] = 0; - } - strcpy(str, startloc); - - endloc = strchr(str, '/'); - if (endloc != NULL) { - strncpy(str2, str, endloc - str); - str2[endloc - str] = 0; - } else - strncpy(str2, str, sizeof(str)); - - if (strlen(str) - strlen(str2) == 0) { - strcpy(str3, "/"); - } else { - strncpy(str3, str + strlen(str2), strlen(str) - strlen(str2) - 1); - str3[strlen(str) - strlen(str2) - 1] = 0; - } - } else { - strncpy(str2, webtarget, sizeof(str2)); - if (redirected_url_buff[0] != '/') { - //it's a relative path, so we have to concatenate it - //with the path from the first url given - char *urlpath; - char urlpath_extracted[2048]; - - memset(urlpath_extracted, 0, sizeof(urlpath_extracted)); - - urlpath = strrchr(url, '/'); - if (urlpath != NULL) { - strncpy(urlpath_extracted, url, urlpath - url); - sprintf(str3, "%.1000s/%.1000s", urlpath_extracted, redirected_url_buff); - } else { - sprintf(str3, "%.1000s/%.1000s", url, redirected_url_buff); - } - } else - strncpy(str3, redirected_url_buff, sizeof(str3)); - if (debug) - hydra_report(stderr, "[DEBUG] host=%s redirect=%s origin=%s\n", str2, str3, url); - } - if (str3[0] != '/') { - j = strlen(str3); - str3[j + 1] = 0; - for (i = j; i > 0; i--) - str3[i] = str3[i - 1]; - str3[0] = '/'; - } - - if (verbose) - hydra_report(stderr, "[VERBOSE] Page redirected to http://%s%s\n", str2, str3); - - //re-use the code above to check for proxy use - if (use_proxy == 1 && proxy_authentication != NULL) { - // proxy with authentication - sprintf(buffer, "GET http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nProxy-Authorization: Basic %s\r\nUser-Agent: Mozilla/4.0 (Hydra)\r\n%s\r\n", - webtarget, webport, str3, str2, proxy_authentication, header); - } else { - if (use_proxy == 1) { - // proxy without authentication - sprintf(buffer, "GET http://%s:%d%.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/4.0 (Hydra)\r\n%s\r\n", webtarget, webport, str3, str2, header); - } else { - //direct web server, no proxy - sprintf(buffer, "GET %.600s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Mozilla/4.0 (Hydra)\r\n%s\r\n", str3, str2, header); - } - } - - hydra_reconnect(s, ip, port, options); - - if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - return 1; - } - found = analyze_server_response(s); - if (strlen(cookie) > 0) { - sprintf(header, "Cookie: %s\r\n", cookie); - } - } - } - - //if the last status is still 3xx, set it as a false - if (found != -1 && found == success_cond && redirected_flag == 0 && redirected_cpt >= 0) { - hydra_report_found_host(port, ip, "www-form", fp); - hydra_completed_pair_found(); - } else { - hydra_completed_pair(); - } + hydra_child_exit(1); return 1; } @@ -673,6 +564,34 @@ void service_http_form(char *ip, int sp, unsigned char options, char *miscptr, F success_cond = 0; } + // Prepare the HTTP requests that will follow + http_opts = 0; + if(use_proxy == 1 && proxy_authentication != NULL){ + // proxy with authentication + http_opts = OPT_PROXY_AUTH; + if(getcookie) + http_opts |= OPT_GETCOOKIES; + }else if(use_proxy == 1){ + // proxy without authentication + http_opts = OPT_PROXY_NOAUTH; + if(getcookie) + http_opts |= OPT_GETCOOKIES; + }else{ + // direct web server, no proxy +// char * header = (char *) malloc(255); +// char * value = (char *) malloc(255); +// strcpy(header, "User-Agent"); +// strcpy(value, "Mozilla/5.0 (Hydra)"); +// add_header(header, value); + add_header("Host", webtarget); + add_header("User-Agent", "Mozilla/5.0 (Hydra)"); + http_opts = OPT_NOPROXY; + if(getcookie) + http_opts |=OPT_GETCOOKIES; + } + + prepare_httpreq(type, url); + char *header = NULL, *value = NULL; while ( /*(optional1 = strtok(NULL, ":")) != NULL */ *optional1 != 0) { switch (optional1[0]) { @@ -690,14 +609,14 @@ void service_http_form(char *ip, int sp, unsigned char options, char *miscptr, F // add a new header at the end ptr = optional1 + 2; while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\')) - ptr++; + ptr++; if (*ptr != 0) - *ptr++ = 0; + *ptr++ = 0; ptr2 = ptr; while (*ptr2 != 0 && (*ptr2 != ':' || *(ptr2 - 1) == '\\')) - ptr2++; + ptr2++; if (*ptr2 != 0) - *ptr2++ = 0; + *ptr2++ = 0; /* * At this point: * - (optional1 + 2) contains the header's name @@ -706,13 +625,15 @@ void service_http_form(char *ip, int sp, unsigned char options, char *miscptr, F header = (char *) malloc(strlen(optional1 + 2)); value = (char *) malloc(strlen(ptr)); if(header && value){ - strcpy(header, optional1 + 2); - strcpy(value, hydra_strrep(ptr, "\\:", ":")); - if(add_header(hydra_trim(header), hydra_trim(value))){ - // Success: break the switch and go ahead - optional1 = ptr2; - break; - } + strcpy(header, optional1 + 2); + strcpy(value, hydra_strrep(ptr, "\\:", ":")); + hydra_report(stdout, "Header: %s\n", header); + hydra_report(stdout, "Value: %s\n", value); + if(add_header(header, value)){ + // Success: break the switch and go ahead + optional1 = ptr2; + break; + } } // Error: abort execution hydra_report(stderr, "[ERROR] Out of memory for HTTP headers."); @@ -720,16 +641,33 @@ void service_http_form(char *ip, int sp, unsigned char options, char *miscptr, F break; case 'H': // add a new header, or replace an existing one's value + ptr = optional1 + 2; + while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\')) + ptr++; + if (*ptr != 0) + *ptr++ = 0; + ptr2 = ptr; + while (*ptr2 != 0 && (*ptr2 != ':' || *(ptr2 - 1) == '\\')) + ptr2++; + if (*ptr2 != 0) + *ptr2++ = 0; + /* + * At this point: + * - (optional1 + 2) contains the header's name + * - ptr contains the header's value + */ header = (char *) malloc(strlen(optional1 + 2)); value = (char *) malloc(strlen(ptr)); if(header && value){ - strcpy(header, optional1 + 2); - strcpy(value, hydra_strrep(ptr, "\\:", ":")); - if(add_or_replace_header(hydra_trim(header), hydra_trim(value))){ - // Success: break the switch and go ahead - optional1 = ptr2; - break; - } + strcpy(header, optional1 + 2); + strcpy(value, hydra_strrep(ptr, "\\:", ":")); + hydra_report(stdout, "Header: %s\n", header); + hydra_report(stdout, "Value: %s\n", value); + if(add_or_replace_header(header, value)){ + // Success: break the switch and go ahead + optional1 = ptr2; + break; + } } // Error: abort execution hydra_report(stderr, "[ERROR] Out of memory for HTTP headers.");