diff --git a/.gitignore b/.gitignore index 4cf0c32..d325b29 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ pw-inspector pw-inspector.exe hydra.restore *~ +.vscode/ +build/ diff --git a/hydra-http-form.c b/hydra-http-form.c index f675beb..d6c0b0f 100644 --- a/hydra-http-form.c +++ b/hydra-http-form.c @@ -386,6 +386,7 @@ char *stringify_headers(ptr_header_node *ptr_head) { } } + return headers_str; } diff --git a/hydra-http.c b/hydra-http.c index a0769b9..3b3fe78 100644 --- a/hydra-http.c +++ b/hydra-http.c @@ -10,9 +10,23 @@ char *http_buf = NULL; static char end_condition[END_CONDITION_MAX_LEN]; int end_condition_type = -1; +#define MAX_STATUS_CODE_SIZE 10 +int *match_status_code; + int32_t webport; int32_t http_auth_mechanism = AUTH_UNASSIGNED; +char *save_miscptr; + +void freeMemory(void **ptr) { + if (ptr != NULL && *ptr != NULL) { + free(*ptr); + *ptr = NULL; + } +} + +#define freeM(p) freeMemory((void **)(&(p))) + int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, char *miscptr, FILE *fp, char *type, ptr_header_node ptr_head) { char *empty = ""; char *login, *pass, *buffer, buffer2[500]; @@ -21,6 +35,10 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha int32_t complete_line = 0, buffer_size; char tmpreplybuf[1024] = "", *tmpreplybufptr; + if (save_miscptr != miscptr) { + miscptr = save_miscptr; + } + if (strlen(login = hydra_get_next_login()) == 0) login = empty; if (strlen(pass = hydra_get_next_password()) == 0) @@ -32,8 +50,8 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha header = stringify_headers(&ptr_head); buffer_size = strlen(header) + 500; - if (!(buffer = malloc(buffer_size))) { - free(header); + if (!(buffer = (char *)malloc(buffer_size))) { + freeM(header); return 3; } @@ -85,8 +103,8 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha fooptr = buffer2; result = sasl_digest_md5(fooptr, login, pass, buffer, miscptr, type, webtarget, webport, header); if (result == NULL) { - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 3; } @@ -128,21 +146,21 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha } if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 1; } // receive challenge if (http_buf != NULL) - free(http_buf); + freeM(http_buf); http_buf = hydra_receive_line(s); if (http_buf == NULL) { if (verbose) hydra_report(stderr, "[ERROR] Server did not answer\n"); - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 3; } @@ -164,8 +182,7 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha // recover challenge from64tobits((char *)buf1, pos); - free(http_buf); - http_buf = NULL; + freeM(http_buf); // Send response buildAuthResponse((tSmbNtlmAuthChallenge *)buf1, (tSmbNtlmAuthResponse *)buf2, 0, login, pass, NULL, NULL); @@ -197,13 +214,13 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha } if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 1; } if (http_buf != NULL) - free(http_buf); + freeM(http_buf); http_buf = hydra_receive_line(s); complete_line = 0; tmpreplybuf[0] = 0; @@ -214,20 +231,20 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha if (tmpreplybuf[0] == 0 && strstr(http_buf, "HTTP/1.") != NULL) { strncpy(tmpreplybuf, http_buf, sizeof(tmpreplybuf) - 1); tmpreplybuf[sizeof(tmpreplybuf) - 1] = 0; - free(http_buf); + freeM(http_buf); http_buf = hydra_receive_line(s); } else if (tmpreplybuf[0] != 0) { complete_line = 1; - if ((tmpreplybufptr = malloc(strlen(tmpreplybuf) + strlen(http_buf) + 1)) != NULL) { + if ((tmpreplybufptr = (char *) malloc(strlen(tmpreplybuf) + strlen(http_buf) + 1)) != NULL) { strcpy(tmpreplybufptr, tmpreplybuf); strcat(tmpreplybufptr, http_buf); - free(http_buf); + freeM(http_buf); http_buf = tmpreplybufptr; if (debug) printf("http_buf now: %s\n", http_buf); } } else { - free(http_buf); + freeM(http_buf); http_buf = hydra_receive_line(s); } } @@ -237,8 +254,8 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha if (http_buf == NULL) { if (verbose) hydra_report(stderr, "[ERROR] Server did not answer\n"); - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 3; } @@ -248,6 +265,36 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha ptr = ((char *)strchr(http_buf, ' ')); if (ptr != NULL) ptr++; + + // check status + if (match_status_code != NULL) { + for (int i = 0; i < sizeof(*match_status_code) / sizeof(int); i++) { + if (match_status_code[i] == atoi(ptr)) { + if (end_condition_type == -1) { + if (debug) + hydra_report(stderr, "Status code condition %d match.\n", match_status_code[i]); + hydra_report_found_host(port, ip, "www", fp); + hydra_completed_pair_found(); + + if (http_buf != NULL) { + freeM(http_buf); + } + + goto finish; + } + } + } + + if (end_condition_type == -1) { + // Skip when status codes do not match + hydra_completed_pair(); + if (http_buf != NULL) { + freeM(http_buf); + } + goto finish; + } + } + if (ptr != NULL && (*ptr == '2' || *ptr == '3' || strncmp(ptr, "403", 3) == 0 || strncmp(ptr, "404", 3) == 0)) { #ifdef HAVE_PCRE if (end_condition_type >= 0 && hydra_string_match(http_buf, end_condition) != end_condition_type) { @@ -264,8 +311,7 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha hydra_completed_pair_found(); } if (http_buf != NULL) { - free(http_buf); - http_buf = NULL; + freeM(http_buf); } } else { if (ptr != NULL && *ptr != '4') @@ -290,8 +336,8 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha if (find_auth) { // free(http_buf); // http_buf = NULL; - free(buffer); - free(header); + freeM(buffer); + freeM(header); return 1; } } @@ -299,9 +345,9 @@ int32_t start_http(int32_t s, char *ip, int32_t port, unsigned char options, cha } // free(http_buf); // http_buf = NULL; - - free(buffer); - free(header); +finish: + freeM(buffer); + freeM(header); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 3; @@ -317,6 +363,10 @@ void service_http(char *ip, int32_t sp, unsigned char options, char *miscptr, FI unsigned char addr6[sizeof(struct in6_addr)]; #endif +if (save_miscptr != miscptr) { + miscptr = save_miscptr; +} + hydra_register_socket(sp); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return; @@ -331,7 +381,7 @@ void service_http(char *ip, int32_t sp, unsigned char options, char *miscptr, FI webport = mysslport; /* normalise the webtarget for ipv6/port number */ - webtarget = malloc(strlen(hostname) + 1 /* null */ + 6 /* :65535 */ + webtarget = (char *) malloc(strlen(hostname) + 1 /* null */ + 6 /* :65535 */ #ifdef AF_INET6 + 2 /* [] */ #endif @@ -426,54 +476,151 @@ int32_t service_http_init(char *ip, int32_t sp, unsigned char options, char *mis // -1 error, hydra will exit, so print a good error message here /*POU CODE */ - char *start = strstr(miscptr, "F="); - if (start == NULL) - start = strstr(miscptr, "S="); - if (start != NULL) { - if (start[0] == 'F') - end_condition_type = 0; - else - end_condition_type = 1; - int condition_len = strlen(start); - memset(end_condition, 0, END_CONDITION_MAX_LEN); - if (condition_len >= END_CONDITION_MAX_LEN) { - hydra_report(stderr, "Condition string cannot be bigger than %u.", END_CONDITION_MAX_LEN); - return -1; + + char *misc = (char *)malloc(strlen(miscptr) + 1); + char *cp = misc; + memset(misc, '\0', strlen(miscptr)); + strcpy(misc, miscptr); + + const char *delim = ":"; + char *p = NULL; + char *match_text_start = NULL; + int trun_flag = 0; + +#if defined __APPLE__ || __linux__ || __unix__ + while ((p = strtok_r(NULL, delim, &misc))) { +#endif + +#ifdef _WIN32 + while ((p = strtok_s(NULL, delim, &misc))) { +#endif + if (strstr(p, "r=") != NULL || strstr(p, "R=") != NULL) { + if (strlen(p) < 3) { + hydra_report(stderr, "Invalid status code, eg: 200 or 200|400."); + freeM(misc); + return -1; + } + + int *status_tmp = (int *) malloc(MAX_STATUS_CODE_SIZE * sizeof(int)); + + char tmp; + int value, n; + int pos = 0; + int plen = strlen(p); + + p += 2; + + while (p) { + n = sscanf(p, "%3d%c", &value, &tmp); + + if ((n != 1 && tmp != '|') || value > 1000) { + hydra_report(stderr, "Invalid status code, eg: 200 or 200|400."); + freeM(misc); + return -1; + } + + status_tmp[pos++] = value; + + if (pos > MAX_STATUS_CODE_SIZE) { + hydra_report(stderr, "Match up to %d status codes.", MAX_STATUS_CODE_SIZE); + freeM(misc); + return -1; + } + + if (n == 1) { + break; + } + + p = strchr(p, '|'); + + if (p) { + ++p; + } + } + + match_status_code = (int *) malloc(pos * sizeof(int)); + for(int i = 0; i < pos; i++) { + match_status_code[i] = status_tmp[i]; + } + freeM(status_tmp); + + char *misc_tmp = (char *)malloc(strlen(miscptr) - plen); + sprintf(misc_tmp, "%.*s%.*s", trun_flag - 1, miscptr, strlen(miscptr) - plen - trun_flag - 1, miscptr + trun_flag + plen + 1); + freeM(miscptr); + miscptr = misc_tmp; + } else if (strstr(p, "F=") != NULL || strstr(p, "S=") != NULL) { + int size = 0; + if (misc != NULL && strlen(misc) != 0) { + size += strlen(misc) + 1; + } + size += strlen(p); + if(size == strlen(p)) { + match_text_start = p; + } else { + match_text_start = (char *) realloc(p, size); + } + + if (misc != NULL && strlen(misc) != 0) { + strcat(match_text_start, ":"); + strcat(match_text_start, misc); + } + memset(miscptr + trun_flag + 1, '\0', size); + break; + } else { + trun_flag += strlen(p) + 1; + } } - // copy condition witout starting string (F= or S= 2char) - strncpy(end_condition, start + 2, condition_len - 2); - if (debug) - hydra_report(stderr, "End condition is %s, mod is %d\n", end_condition, end_condition_type); - if (*(start - 1) == ' ') - start--; - memset(start, '\0', condition_len); - if (debug) - hydra_report(stderr, "Modificated options:%s\n", miscptr); - } else { - if (debug) - hydra_report(stderr, "Condition not found\n"); + if (match_text_start != NULL) { + if (match_text_start[0] == 'F') + end_condition_type = 0; + else + end_condition_type = 1; + + int condition_len = strlen(match_text_start); + memset(end_condition, 0, END_CONDITION_MAX_LEN); + + if (condition_len >= END_CONDITION_MAX_LEN) { + hydra_report(stderr, "Condition string cannot be bigger than %u.", END_CONDITION_MAX_LEN); + freeM(misc); + return -1; + } + + // copy condition witout starting string (F= or S= 2char) + strncpy(end_condition, match_text_start + 2, condition_len - 2); + if (debug) + hydra_report(stderr, "End condition is %s, mod is %d\n", end_condition, end_condition_type); + + + if (debug) + hydra_report(stderr, "Modificated options:%s\n", miscptr); + } + + free(cp); + + save_miscptr = miscptr; + + return 0; } - return 0; -} - -void usage_http(const char *service) { - printf("Module %s requires the page to authenticate.\n" - "The following parameters are optional:\n" - " (a|A)=auth-type specify authentication mechanism to use: BASIC, " - "NTLM or MD5\n" - " (h|H)=My-Hdr\\: foo to send a user defined HTTP header with each " - "request\n" - " (F|S)=check for text in the HTTP reply. S= means if this text is " - "found, a\n" - " valid account has been found, F= means if this string is " - "present the\n" - " combination is invalid. Note: this must be the last option " - "supplied.\n" - "For example: \"/secret\" or \"http://bla.com/foo/bar:H=Cookie\\: " - "sessid=aaaa\" or \"https://test.com:8080/members:A=NTLM\"\n\n", - service); -} + void usage_http(const char *service) { + printf("Module %s requires the page to authenticate.\n" + "The following parameters are optional:\n" + " (a|A)=auth-type specify authentication mechanism to use: BASIC, " + "NTLM or MD5\n" + " (h|H)=My-Hdr\\: foo to send a user defined HTTP header with each " + "request\n" + " (r|R)=check for status code in the HTTP reply. If the reply status code\n" + " matches it, it is judged as successful \n" + " (F|S)=check for text in the HTTP reply. S= means if this text is " + "found, a\n" + " valid account has been found, F= means if this string is " + "present the\n" + " combination is invalid. Note: this must be the last option " + "supplied.\n" + "For example: \"/secret\" or \"http://bla.com/foo/bar:H=Cookie\\: " + "sessid=aaaa\" or \"https://test.com:8080/members:A=NTLM\"\n\n", + service); + } diff --git a/hydra-telnet.c b/hydra-telnet.c index 63fcb23..f30048d 100644 --- a/hydra-telnet.c +++ b/hydra-telnet.c @@ -37,12 +37,14 @@ int32_t start_telnet(int32_t s, char *ip, int32_t port, unsigned char options, c return 1; if (strchr(buf, '/') != NULL || strchr(buf, '>') != NULL || strchr(buf, '%') != NULL || strchr(buf, '$') != NULL || strchr(buf, '#') != NULL) { - hydra_report_found_host(port, ip, "telnet", fp); - hydra_completed_pair_found(); - free(buf); - if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) - return 3; - return 1; + if (strstr(buf, "ailed") == NULL) { + hydra_report_found_host(port, ip, "telnet", fp); + hydra_completed_pair_found(); + free(buf); + if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) + return 3; + return 1; + } } (void)make_to_lower(buf);