mirror of
https://github.com/vanhauser-thc/thc-hydra.git
synced 2025-07-05 20:41:39 -07:00
1481 lines
51 KiB
C
1481 lines
51 KiB
C
/*
|
||
|
||
Hydra Form Module
|
||
-----------------
|
||
|
||
The hydra form can be used to carry out a brute-force attack on simple
|
||
web-based login forms that require username and password variables via
|
||
either a GET or POST request.
|
||
|
||
The module works similarly to the HTTP basic auth module and will honour
|
||
proxy mode (with authentication) as well as SSL. The module can be invoked
|
||
with the service names of "http-get-form", "http-post-form",
|
||
"https-get-form" and "https-post-form".
|
||
|
||
Here's a couple of examples: -
|
||
|
||
./hydra -l "<userID>" -P pass.txt 10.221.64.12 http-post-form
|
||
"/irmlab2/testsso-auth.do:ID=^USER^&Password=^PASS^:Invalid Password"
|
||
|
||
./hydra -S -s 443 -l "<username>" -P pass.txt 10.221.64.2 https-get-form
|
||
"/irmlab1/vulnapp.php:username=^USER^&pass=^PASS^:incorrect"
|
||
|
||
The option field (following the service field) takes ":" separated values:
|
||
The first is the page on the server to GET or POST to.
|
||
The second is the POST/GET variables (taken from either the browser, or a proxy
|
||
such as ZAP) with the varying usernames and passwords in the "^USER^" and
|
||
"^PASS^" placeholders.
|
||
The third + are optional parameters like C=, H= etc. (see below)
|
||
The final(!) parameter is the string that it checks for an *invalid* or *valid*
|
||
login
|
||
So please:
|
||
* invalid condition login should be preceded by "F="
|
||
* valid condition login should be preceded by "S=".
|
||
By default, if no header is found the condition is assume to be a fail (F=),
|
||
so checking for an *invalid* login string.
|
||
|
||
If you specify the debug flag (-d) it will show you the response from the
|
||
HTTP server which is useful for checking the result of a failed login to
|
||
find something to pattern match against. This should be done together with -t 1.
|
||
|
||
*/
|
||
|
||
#include "hydra-http.h"
|
||
#include "sasl.h"
|
||
|
||
extern char *HYDRA_EXIT;
|
||
char *buf;
|
||
char *cond;
|
||
extern int32_t http_auth_mechanism;
|
||
|
||
struct header_node {
|
||
char *header;
|
||
char *value;
|
||
char type;
|
||
struct header_node *next;
|
||
};
|
||
|
||
typedef struct cookie_node {
|
||
char *name;
|
||
char *value;
|
||
struct cookie_node *prev;
|
||
struct cookie_node *next;
|
||
} t_cookie_node, *ptr_cookie_node;
|
||
|
||
int32_t success_cond = 0;
|
||
int32_t getcookie = 1;
|
||
int32_t auth_flag = 0;
|
||
int32_t code_302_is_success = 0;
|
||
int32_t code_401_is_failure = 0;
|
||
int32_t multipart_mode = 0;
|
||
|
||
char cookie[4096] = "", cmiscptr[1024];
|
||
|
||
int32_t webport;
|
||
char bufferurl[6096 + 24], cookieurl[6096 + 24] = "", userheader[6096 + 24] = "", *url, *variables, *optional1;
|
||
|
||
#define MAX_REDIRECT 8
|
||
#define MAX_CONTENT_LENGTH 20
|
||
#define MAX_CONTENT_DISPOSITION 200
|
||
#define MAX_PROXY_LENGTH 2048 // sizeof(cookieurl) * 2
|
||
|
||
char redirected_url_buff[2048] = "";
|
||
int32_t redirected_flag = 0;
|
||
int32_t redirected_cpt = MAX_REDIRECT;
|
||
|
||
char *cookie_request = NULL, *normal_request = NULL; // Buffers for HTTP headers
|
||
|
||
/*
|
||
* Function to perform some initial setup.
|
||
*/
|
||
ptr_header_node initialize(char *ip, unsigned char options, char *miscptr);
|
||
|
||
/*
|
||
* Returns 1 if specified header exists, or 0 otherwise.
|
||
*/
|
||
ptr_header_node header_exists(ptr_header_node *ptr_head, char *header_name, char type) {
|
||
ptr_header_node cur_ptr = *ptr_head, found_header = NULL;
|
||
|
||
for (cur_ptr = *ptr_head; cur_ptr && !found_header; cur_ptr = cur_ptr->next)
|
||
if (cur_ptr->header && strcmp(cur_ptr->header, header_name) == 0 && cur_ptr->type == type)
|
||
found_header = cur_ptr;
|
||
|
||
return found_header;
|
||
}
|
||
|
||
#if defined(__sun)
|
||
|
||
/* Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu> */
|
||
char *strndup(const char *s, size_t n) {
|
||
char *result;
|
||
size_t len = strlen(s);
|
||
|
||
if (n < len)
|
||
len = n;
|
||
|
||
result = (char *)malloc(len + 1);
|
||
if (!result)
|
||
return 0;
|
||
|
||
memcpy(result, s, len);
|
||
result[len] = '\0';
|
||
return (result);
|
||
}
|
||
#endif
|
||
|
||
int32_t append_cookie(char *name, char *value, ptr_cookie_node *last_cookie) {
|
||
ptr_cookie_node new_ptr = (ptr_cookie_node)malloc(sizeof(t_cookie_node));
|
||
|
||
if (!new_ptr)
|
||
return 0;
|
||
new_ptr->name = name;
|
||
new_ptr->value = value;
|
||
new_ptr->next = NULL;
|
||
new_ptr->prev = NULL;
|
||
|
||
if (*last_cookie == NULL)
|
||
*last_cookie = new_ptr;
|
||
else
|
||
(*last_cookie)->next = new_ptr;
|
||
|
||
return 1;
|
||
}
|
||
|
||
char *stringify_cookies(ptr_cookie_node ptr_cookie) {
|
||
ptr_cookie_node cur_ptr = NULL;
|
||
uint32_t length = 1;
|
||
char *cookie_hdr = (char *)malloc(length);
|
||
|
||
if (cookie_hdr) {
|
||
memset(cookie_hdr, 0, length);
|
||
for (cur_ptr = ptr_cookie; cur_ptr; cur_ptr = cur_ptr->next) {
|
||
length += 2 + strlen(cur_ptr->name) + strlen(cur_ptr->value);
|
||
cookie_hdr = (char *)realloc(cookie_hdr, length);
|
||
if (cookie_hdr) {
|
||
strcat(cookie_hdr, cur_ptr->name);
|
||
strcat(cookie_hdr, "=");
|
||
strcat(cookie_hdr, cur_ptr->value);
|
||
if (cur_ptr->next)
|
||
strcat(cookie_hdr, ";");
|
||
} else
|
||
goto bail;
|
||
}
|
||
goto success;
|
||
}
|
||
|
||
bail:
|
||
if (cookie_hdr) {
|
||
free(cookie_hdr);
|
||
cookie_hdr = NULL;
|
||
}
|
||
|
||
success:
|
||
return cookie_hdr;
|
||
}
|
||
|
||
/*
|
||
* Cookie list layout:
|
||
* +----------+ +--------+ +------+
|
||
* | ptr_head | --> | next | --> | NULL |
|
||
* +----------+ | header | +------+
|
||
* | value |
|
||
* +--------+
|
||
* Returns 1 if success, or 0 otherwise.
|
||
*/
|
||
int32_t add_or_update_cookie(ptr_cookie_node *ptr_cookie, char *cookie_expr) {
|
||
ptr_cookie_node cur_ptr = NULL;
|
||
char *cookie_name = NULL, *cookie_value = strstr(cookie_expr, "=");
|
||
|
||
if (cookie_value) {
|
||
cookie_name = strndup(cookie_expr, cookie_value - cookie_expr);
|
||
cookie_value = strdup(cookie_value + 1);
|
||
|
||
// we've got the cookie's name and value, now it's time to insert or update
|
||
// the list
|
||
if (*ptr_cookie == NULL) {
|
||
// no cookies
|
||
append_cookie(cookie_name, cookie_value, ptr_cookie);
|
||
} else {
|
||
for (cur_ptr = *ptr_cookie; cur_ptr; cur_ptr = cur_ptr->next) {
|
||
if (strcmp(cur_ptr->name, cookie_name) == 0) {
|
||
free(cur_ptr->value); // free old value
|
||
free(cookie_name); // we already have it
|
||
cur_ptr->value = cookie_value;
|
||
break;
|
||
}
|
||
if (cur_ptr->next == NULL) {
|
||
append_cookie(cookie_name, cookie_value, &cur_ptr);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
int32_t process_cookies(ptr_cookie_node *ptr_cookie, char *cookie_expr) {
|
||
char *tok = NULL;
|
||
char *expr = strdup(cookie_expr);
|
||
int32_t res = 0;
|
||
|
||
if (strstr(cookie_expr, ";")) {
|
||
tok = strtok(expr, ";");
|
||
while (tok) {
|
||
res = add_or_update_cookie(ptr_cookie, tok);
|
||
if (!res) {
|
||
free(expr);
|
||
return res;
|
||
}
|
||
tok = strtok(NULL, ";");
|
||
}
|
||
free(expr);
|
||
return res;
|
||
} else {
|
||
add_or_update_cookie(ptr_cookie, expr);
|
||
free(expr);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* List layout:
|
||
* +----------+ +--------+ +--------+ +--------+
|
||
* | ptr_head | --> | next | --> | next | --> | NULL |
|
||
* | | | header | | header | | NULL |
|
||
* | | | value | | value | | NULL |
|
||
* +----------+ +--------+ +--------+ +--------+
|
||
*
|
||
* Returns 1 if success, or 0 otherwise (out of memory).
|
||
*/
|
||
int32_t add_header(ptr_header_node *ptr_head, char *header, char *value, char type) {
|
||
ptr_header_node cur_ptr = NULL;
|
||
ptr_header_node existing_hdr, new_ptr;
|
||
|
||
if (!header || !value || !strlen(header) || !strlen(value))
|
||
return 0;
|
||
|
||
// get to the last header
|
||
for (cur_ptr = *ptr_head; cur_ptr && cur_ptr->next; cur_ptr = cur_ptr->next)
|
||
;
|
||
|
||
char *new_header = strdup(header);
|
||
char *new_value = strdup(value);
|
||
|
||
if (new_header && new_value) {
|
||
if ((type == HEADER_TYPE_USERHEADER) || (type == HEADER_TYPE_DEFAULT && !header_exists(ptr_head, new_header, HEADER_TYPE_USERHEADER_REPL)) || (type == HEADER_TYPE_USERHEADER_REPL && !header_exists(ptr_head, new_header, HEADER_TYPE_DEFAULT)) || (type == HEADER_TYPE_DEFAULT_REPL && !header_exists(ptr_head, new_header, HEADER_TYPE_DEFAULT))) {
|
||
/*
|
||
* We are in one of the following scenarios:
|
||
* 1. A default header with no user-supplied headers that replace it.
|
||
* 2. A user-supplied header that must be appended (option 'h').
|
||
* 3. A user-supplied header that must replace a default header
|
||
* (option 'h'), but no default headers exist with that name.
|
||
*
|
||
* In either case we just add the header to the list.
|
||
*/
|
||
new_ptr = (ptr_header_node)malloc(sizeof(t_header_node));
|
||
if (!new_ptr) {
|
||
free(new_header);
|
||
free(new_value);
|
||
return 0;
|
||
}
|
||
new_ptr->header = new_header;
|
||
new_ptr->value = new_value;
|
||
new_ptr->type = type;
|
||
new_ptr->next = NULL;
|
||
|
||
if (cur_ptr)
|
||
cur_ptr->next = new_ptr;
|
||
else {
|
||
// head is NULL, so the list is empty
|
||
*ptr_head = new_ptr;
|
||
}
|
||
} else if ((type == HEADER_TYPE_DEFAULT_REPL || type == HEADER_TYPE_USERHEADER_REPL) && (existing_hdr = header_exists(ptr_head, new_header, HEADER_TYPE_DEFAULT)) != NULL) {
|
||
// It's a user-supplied header that must replace a default one
|
||
// Replace the default header's value with this new value
|
||
free(existing_hdr->value); // free old value
|
||
existing_hdr->value = new_value;
|
||
existing_hdr->type = type;
|
||
free(new_header); // we dont need this one anymore
|
||
}
|
||
} else {
|
||
// we're out of memory, so forcefully end
|
||
free(new_header);
|
||
free(new_value);
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
/*
|
||
* Replace in all headers' values every occurrence of oldvalue by newvalue.
|
||
* Only user-defined headers are considered.
|
||
*/
|
||
void hdrrep(ptr_header_node *ptr_head, char *oldvalue, char *newvalue) {
|
||
ptr_header_node cur_ptr = NULL;
|
||
|
||
for (cur_ptr = *ptr_head; cur_ptr; cur_ptr = cur_ptr->next) {
|
||
if ((cur_ptr->type == HEADER_TYPE_USERHEADER || cur_ptr->type == HEADER_TYPE_USERHEADER_REPL) && strstr(cur_ptr->value, oldvalue)) {
|
||
size_t oldlen = strlen(oldvalue);
|
||
size_t newlen = strlen(newvalue);
|
||
if (oldlen != newlen)
|
||
cur_ptr->value = (char *)realloc(cur_ptr->value, strlen(cur_ptr->value) - oldlen + newlen + 1);
|
||
if (cur_ptr->value) {
|
||
char *p = strstr(cur_ptr->value, oldvalue);
|
||
memmove(p + newlen, p + oldlen, strlen(p + oldlen) + 1);
|
||
memcpy(p, newvalue, newlen);
|
||
} else {
|
||
hydra_report(stderr, "[ERROR] Out of memory (hddrep).\n");
|
||
hydra_child_exit(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Replace the value of the default header named 'hdrname'.
|
||
*/
|
||
void hdrrepv(ptr_header_node *ptr_head, char *hdrname, char *new_value) {
|
||
ptr_header_node cur_ptr = NULL;
|
||
|
||
for (cur_ptr = *ptr_head; cur_ptr; cur_ptr = cur_ptr->next) {
|
||
if ((cur_ptr->type == HEADER_TYPE_DEFAULT) && strcmp(cur_ptr->header, hdrname) == 0) {
|
||
cur_ptr->value = (char *)realloc(cur_ptr->value, strlen(new_value) + 1);
|
||
if (cur_ptr->value)
|
||
strcpy(cur_ptr->value, new_value);
|
||
else {
|
||
hydra_report(stderr, "[ERROR] Out of memory (hdrrepv %lu)\n", strlen(new_value) + 1);
|
||
hydra_child_exit(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void cleanup(ptr_header_node *ptr_head) {
|
||
ptr_header_node cur_ptr = *ptr_head, next_ptr = cur_ptr;
|
||
|
||
while (next_ptr != NULL) {
|
||
free(cur_ptr->header);
|
||
free(cur_ptr->value);
|
||
next_ptr = cur_ptr->next;
|
||
}
|
||
|
||
*ptr_head = NULL;
|
||
}
|
||
|
||
/*
|
||
* Concat all the headers in the list in a single string.
|
||
* Leave the list itself intact: do not clean it here.
|
||
*/
|
||
char *stringify_headers(ptr_header_node *ptr_head) {
|
||
char *headers_str = NULL;
|
||
ptr_header_node cur_ptr = *ptr_head;
|
||
int32_t ttl_size = 0;
|
||
|
||
for (; cur_ptr; cur_ptr = cur_ptr->next)
|
||
ttl_size += strlen(cur_ptr->header) + strlen(cur_ptr->value) + 4;
|
||
|
||
headers_str = (char *)malloc(ttl_size + 1);
|
||
|
||
if (headers_str) {
|
||
memset(headers_str, 0, ttl_size + 1);
|
||
for (cur_ptr = *ptr_head; cur_ptr; cur_ptr = cur_ptr->next) {
|
||
strcat(headers_str, cur_ptr->header);
|
||
strcat(headers_str, ": ");
|
||
strcat(headers_str, cur_ptr->value);
|
||
strcat(headers_str, "\r\n");
|
||
}
|
||
}
|
||
|
||
return headers_str;
|
||
}
|
||
|
||
int32_t parse_options(char *miscptr, ptr_header_node *ptr_head) {
|
||
char *ptr, *ptr2, *tmp;
|
||
|
||
if (miscptr == NULL)
|
||
return 1;
|
||
|
||
/*
|
||
* Parse the user-supplied options.
|
||
* Beware of the backslashes (\)!
|
||
*/
|
||
while (*miscptr != 0) {
|
||
if (strlen(miscptr) < 2 || miscptr[1] != '=') {
|
||
hydra_report(stderr, "[ERROR] optional parameters must have the format X=value: %s\n", miscptr);
|
||
return 0;
|
||
}
|
||
switch (miscptr[0]) {
|
||
case 'a': // fall through
|
||
case 'A': // only for http, not http-form!
|
||
ptr = miscptr + 2;
|
||
|
||
if (strncasecmp(ptr, "NTLM", 4) == 0)
|
||
http_auth_mechanism = AUTH_NTLM;
|
||
else if (strncasecmp(ptr, "MD5", 3) == 0 || strncasecmp(ptr, "DIGEST", 6) == 0)
|
||
http_auth_mechanism = AUTH_DIGESTMD5;
|
||
else if (strncasecmp(ptr, "BASIC", 4) == 0)
|
||
http_auth_mechanism = AUTH_BASIC;
|
||
else
|
||
fprintf(stderr, "[WARNING] unknown http auth type: %s\n", ptr);
|
||
|
||
while (*ptr != 0 && *ptr != ':')
|
||
ptr++;
|
||
|
||
if (*ptr != 0) {
|
||
*ptr = 0;
|
||
ptr += 1;
|
||
}
|
||
|
||
miscptr = ptr;
|
||
break;
|
||
case 'c': // fall through
|
||
case 'C':
|
||
ptr = miscptr + 2;
|
||
while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\'))
|
||
ptr++;
|
||
if (*ptr != 0)
|
||
*ptr++ = 0;
|
||
sprintf(cookieurl, "%.1000s", hydra_strrep(miscptr + 2, "\\:", ":"));
|
||
miscptr = ptr;
|
||
break;
|
||
case '1':
|
||
code_401_is_failure = 1;
|
||
tmp = strchr(miscptr, ':');
|
||
if (tmp)
|
||
miscptr = tmp + 1;
|
||
else
|
||
miscptr += strlen(miscptr);
|
||
break;
|
||
case '2':
|
||
code_302_is_success = 1;
|
||
tmp = strchr(miscptr, ':');
|
||
if (tmp)
|
||
miscptr = tmp + 1;
|
||
else
|
||
miscptr += strlen(miscptr);
|
||
break;
|
||
case 'm': //fall through
|
||
case 'M':
|
||
multipart_mode = 1;
|
||
tmp = strchr(miscptr, ':');
|
||
if (tmp)
|
||
miscptr = tmp + 1;
|
||
else
|
||
miscptr += strlen(miscptr);
|
||
break;
|
||
case 'g': // fall through
|
||
case 'G':
|
||
ptr = miscptr + 2;
|
||
while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\'))
|
||
ptr++;
|
||
if (*ptr != 0)
|
||
*ptr++ = 0;
|
||
getcookie = 0;
|
||
miscptr = ptr;
|
||
break;
|
||
case 'h':
|
||
// add a new header at the end
|
||
ptr = miscptr + 2;
|
||
while (*ptr != 0 && *ptr != ':')
|
||
ptr++;
|
||
if (*(ptr - 1) == '\\')
|
||
*(ptr - 1) = 0;
|
||
if (*ptr != 0) {
|
||
*ptr = 0;
|
||
ptr += 1;
|
||
}
|
||
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
|
||
*/
|
||
if (add_header(ptr_head, miscptr + 2, hydra_strrep(ptr, "\\:", ":"), HEADER_TYPE_USERHEADER)) {
|
||
// Success: break the switch and go ahead
|
||
miscptr = ptr2;
|
||
break;
|
||
}
|
||
// Error: abort execution
|
||
hydra_report(stderr, "[ERROR] Out of memory for HTTP headers (h).\n");
|
||
return 0;
|
||
case 'H':
|
||
// add a new header, or replace an existing one's value
|
||
ptr = miscptr + 2;
|
||
while (*ptr != 0 && *ptr != ':')
|
||
ptr++;
|
||
|
||
if (*(ptr - 1) == '\\')
|
||
*(ptr - 1) = 0;
|
||
|
||
if (*ptr != 0) {
|
||
*ptr = 0;
|
||
ptr += 1;
|
||
}
|
||
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
|
||
*/
|
||
if (add_header(ptr_head, miscptr + 2, hydra_strrep(ptr, "\\:", ":"), HEADER_TYPE_USERHEADER_REPL)) {
|
||
// Success: break the switch and go ahead
|
||
miscptr = ptr2;
|
||
break;
|
||
}
|
||
// Error: abort execution
|
||
hydra_report(stderr, "[ERROR] Out of memory for HTTP headers (H).\n");
|
||
return 0;
|
||
default:
|
||
hydra_report(stderr, "[ERROR] no valid optional parameter type given: %c\n", miscptr[0]);
|
||
return 0;
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
char *build_multipart_body(char *multipart_boundary) {
|
||
if (!variables)
|
||
return NULL; // Pas de paramètres à traiter
|
||
|
||
char *body = NULL; // Chaîne résultat
|
||
size_t body_size = 0; // Taille actuelle du corps
|
||
|
||
// Dupliquer la chaîne "variables" afin de pouvoir la tokeniser
|
||
char *vars_dup = strdup(variables);
|
||
if (!vars_dup)
|
||
return NULL;
|
||
|
||
// Tokeniser la chaîne sur le caractère '&'
|
||
char *pair = strtok(vars_dup, "&");
|
||
while (pair != NULL) {
|
||
// Pour chaque paire, rechercher le séparateur '='
|
||
char *equal_sign = strchr(pair, '=');
|
||
if (!equal_sign) {
|
||
pair = strtok(NULL, "&");
|
||
continue;
|
||
}
|
||
*equal_sign = '\0'; // Terminer la clé
|
||
char *key = pair;
|
||
char *value = equal_sign + 1;
|
||
|
||
// Construire la section multipart pour ce champ.
|
||
// Format attendu :
|
||
// --<boundary>\r\n
|
||
// Content-Disposition: form-data; name="<key>"\r\n
|
||
// \r\n
|
||
// <value>\r\n
|
||
int section_len = snprintf(NULL, 0,
|
||
"--%s\r\n"
|
||
"Content-Disposition: form-data; name=\"%s\"\r\n"
|
||
"\r\n"
|
||
"%s\r\n",
|
||
multipart_boundary, key, value);
|
||
|
||
char *section = malloc(section_len + 1);
|
||
if (!section) {
|
||
free(body);
|
||
free(vars_dup);
|
||
return NULL;
|
||
}
|
||
snprintf(section, section_len + 1,
|
||
"--%s\r\n"
|
||
"Content-Disposition: form-data; name=\"%s\"\r\n"
|
||
"\r\n"
|
||
"%s\r\n",
|
||
multipart_boundary, key, value);
|
||
|
||
// Réallouer le buffer "body" pour y ajouter cette section
|
||
size_t new_body_size = body_size + section_len;
|
||
char *new_body = realloc(body, new_body_size + 1); // +1 pour le '\0'
|
||
if (!new_body) {
|
||
free(section);
|
||
free(body);
|
||
free(vars_dup);
|
||
return NULL;
|
||
}
|
||
body = new_body;
|
||
if (body_size == 0) {
|
||
strcpy(body, section);
|
||
} else {
|
||
strcat(body, section);
|
||
}
|
||
body_size = new_body_size;
|
||
free(section);
|
||
|
||
// Passage à la paire suivante
|
||
pair = strtok(NULL, "&");
|
||
}
|
||
free(vars_dup);
|
||
|
||
// Ajouter la fermeture du multipart :
|
||
// --<boundary>--\r\n
|
||
int closing_len = snprintf(NULL, 0, "--%s--\r\n", multipart_boundary);
|
||
char *closing = malloc(closing_len + 1);
|
||
if (!closing) {
|
||
free(body);
|
||
return NULL;
|
||
}
|
||
snprintf(closing, closing_len + 1, "--%s--\r\n", multipart_boundary);
|
||
|
||
size_t final_size = body_size + closing_len;
|
||
char *final_body = realloc(body, final_size + 1);
|
||
if (!final_body) {
|
||
free(closing);
|
||
free(body);
|
||
return NULL;
|
||
}
|
||
body = final_body;
|
||
strcat(body, closing);
|
||
free(closing);
|
||
|
||
return body;
|
||
}
|
||
|
||
char *prepare_http_request(char *type, char *path, char *params, char *headers) {
|
||
uint32_t reqlen = 0;
|
||
char *http_request = NULL;
|
||
|
||
if (type && path && headers) {
|
||
reqlen = strlen(path) + strlen(headers) + 20;
|
||
if (params)
|
||
reqlen += strlen(params);
|
||
|
||
http_request = (char *)malloc(reqlen);
|
||
if (http_request) {
|
||
memset(http_request, 0, reqlen);
|
||
|
||
// append the request verb (GET or POST)
|
||
if (strcmp(type, "GET") == 0)
|
||
strcat(http_request, "GET ");
|
||
else
|
||
strcat(http_request, "POST ");
|
||
|
||
// append the request path
|
||
strcat(http_request, path);
|
||
|
||
// if GET, append the params now
|
||
if (params && strcmp(type, "GET") == 0) {
|
||
strcat(http_request, "?");
|
||
strcat(http_request, params);
|
||
}
|
||
// append the headers
|
||
strcat(http_request, " HTTP/1.0\r\n");
|
||
strcat(http_request, headers);
|
||
strcat(http_request, "\r\n");
|
||
|
||
// if POST, append the params now
|
||
if (params && strcmp(type, "POST") == 0)
|
||
strcat(http_request, params);
|
||
}
|
||
}
|
||
|
||
return http_request;
|
||
}
|
||
|
||
int32_t strpos(char *str, char *target) {
|
||
char *res = strstr(str, target);
|
||
|
||
if (res == NULL)
|
||
return -1;
|
||
else
|
||
return res - str;
|
||
}
|
||
|
||
char *html_encode(char *string) {
|
||
char *ret = string;
|
||
|
||
if (ret == NULL)
|
||
return NULL;
|
||
|
||
if (strchr(ret, '%') != NULL)
|
||
ret = hydra_strrep(ret, "%", "%25");
|
||
if (strchr(ret, ' ') != NULL)
|
||
ret = hydra_strrep(ret, " ", "%20");
|
||
if (strchr(ret, '&') != NULL)
|
||
ret = hydra_strrep(ret, "&", "%26");
|
||
if (strchr(ret, '#') != NULL)
|
||
ret = hydra_strrep(ret, "#", "%23");
|
||
if (strchr(ret, '=') != NULL)
|
||
ret = hydra_strrep(ret, "=", "%3D");
|
||
if (strchr(ret, '+') != NULL)
|
||
ret = hydra_strrep(ret, "+", "%2B");
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
int32_t analyze_server_response(int32_t socket)
|
||
return 0 or 1 when the cond regex is matched
|
||
return -1 if no response from server
|
||
*/
|
||
int32_t analyze_server_response(int32_t s) {
|
||
int32_t runs = 0;
|
||
|
||
redirected_flag = 0;
|
||
auth_flag = 0;
|
||
while ((buf = hydra_receive_line(s)) != NULL) {
|
||
runs++;
|
||
// check for http redirection
|
||
if (strstr(buf, "HTTP/1.1 3") != NULL || strstr(buf, "HTTP/1.0 3") != NULL || strstr(buf, "Status: 3") != NULL) {
|
||
redirected_flag = 1;
|
||
} else if (strstr(buf, "HTTP/1.1 401") != NULL || strstr(buf, "HTTP/1.0 401") != NULL) {
|
||
auth_flag = 1;
|
||
} else if ((strstr(buf, "HTTP/1.1 403") != NULL) || (strstr(buf, "HTTP/1.1 404") != NULL) || (strstr(buf, "HTTP/1.0 403") != NULL) || (strstr(buf, "HTTP/1.0 404") != NULL)) {
|
||
return -1;
|
||
}
|
||
|
||
if (hydra_strcasestr(buf, "Location: ") != NULL) {
|
||
char *startloc, *endloc;
|
||
char str[2048];
|
||
|
||
startloc = hydra_strcasestr(buf, "Location: ") + strlen("Location: ");
|
||
strncpy(str, startloc, sizeof(str) - 1);
|
||
str[sizeof(str) - 1] = 0;
|
||
endloc = strchr(str, '\n');
|
||
if (endloc != NULL)
|
||
*endloc = 0;
|
||
endloc = strchr(str, '\r');
|
||
if (endloc != NULL)
|
||
*endloc = 0;
|
||
strcpy(redirected_url_buff, str);
|
||
}
|
||
// there can be multiple cookies
|
||
if (hydra_strcasestr(buf, "Set-Cookie: ") != NULL) {
|
||
char *cookiebuf = buf;
|
||
|
||
do {
|
||
char *startcookie, *endcookie1, *endcookie2;
|
||
char str[1024], tmpcookie[4096] = "", tmpname[128] = "", *ptr, *ptr2;
|
||
|
||
memset(str, 0, sizeof(str));
|
||
startcookie = hydra_strcasestr(cookiebuf, "Set-Cookie: ") + strlen("Set-Cookie: ");
|
||
strncpy(str, startcookie, sizeof(str) - 1);
|
||
str[sizeof(str) - 1] = 0;
|
||
endcookie1 = strchr(str, '\n');
|
||
endcookie2 = strchr(str, ';');
|
||
// terminate string after cookie data
|
||
if (endcookie1 != NULL && ((endcookie1 < endcookie2) || (endcookie2 == NULL))) {
|
||
if (*(endcookie1 - 1) == '\r')
|
||
endcookie1--;
|
||
*endcookie1 = 0;
|
||
} else if (endcookie2 != NULL)
|
||
*endcookie2 = 0;
|
||
// is the cookie already there? if yes, remove it!
|
||
if (strchr(startcookie, '=') != NULL && (ptr = strchr(startcookie, '=')) - startcookie + 1 <= sizeof(tmpname)) {
|
||
strncpy(tmpname, startcookie, sizeof(tmpname) - 2);
|
||
tmpname[sizeof(tmpname) - 2] = 0;
|
||
ptr = strchr(tmpname, '=');
|
||
*(++ptr) = 0;
|
||
// is the cookie already in the cookiejar? (so, does it have to be
|
||
// replaced?)
|
||
if ((ptr = hydra_strcasestr(cookie, tmpname)) != NULL) {
|
||
// yes it is.
|
||
// if the cookie is not in the beginning of the cookiejar, copy the
|
||
// ones before
|
||
if (ptr != cookie && *(ptr - 1) == ' ') {
|
||
strncpy(tmpcookie, cookie, ptr - cookie - 2);
|
||
tmpcookie[ptr - cookie - 2] = 0;
|
||
}
|
||
ptr += strlen(tmpname);
|
||
// if there are any cookies after this one in the cookiejar, copy
|
||
// them over
|
||
if ((ptr2 = strstr(ptr, "; ")) != NULL) {
|
||
ptr2 += 2;
|
||
strncat(tmpcookie, ptr2, sizeof(tmpcookie) - strlen(tmpcookie) - 1);
|
||
}
|
||
if (debug)
|
||
printf("[DEBUG] removing cookie %s in jar\n before: %s\n after: "
|
||
"%s\n",
|
||
tmpname, cookie, tmpcookie);
|
||
strcpy(cookie, tmpcookie);
|
||
}
|
||
}
|
||
ptr = strchr(str, '=');
|
||
// only copy the cookie if it has a value (otherwise the server wants to
|
||
// delete the cookie)
|
||
if (ptr != NULL && *(ptr + 1) != ';' && *(ptr + 1) != 0 && *(ptr + 1) != '\n' && *(ptr + 1) != '\r') {
|
||
if (strlen(cookie) > 0)
|
||
strncat(cookie, "; ", sizeof(cookie) - strlen(cookie) - 1);
|
||
strncat(cookie, str, sizeof(cookie) - strlen(cookie) - 1);
|
||
}
|
||
cookiebuf = startcookie;
|
||
} while (hydra_strcasestr(cookiebuf, "Set-Cookie: ") != NULL);
|
||
}
|
||
#ifdef HAVE_PCRE
|
||
if (hydra_string_match(buf, cond) == 1) {
|
||
#else
|
||
if (strstr(buf, cond) != NULL) {
|
||
#endif
|
||
free(buf);
|
||
// printf("DEBUG: STRING %s FOUND!!:\n%s\n", cond, buf);
|
||
return 1;
|
||
}
|
||
// else printf("DEBUG: STRING %s NOT FOUND:\n%s\n", cond, buf);
|
||
free(buf);
|
||
}
|
||
if (runs == 0) {
|
||
if (debug)
|
||
hydra_report(stderr, "DEBUG: no response from server\n");
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void hydra_reconnect(int32_t s, char *ip, int32_t port, unsigned char options, char *hostname) {
|
||
if (s >= 0)
|
||
s = hydra_disconnect(s);
|
||
if ((options & OPTION_SSL) == 0) {
|
||
s = hydra_connect_tcp(ip, port);
|
||
} else {
|
||
s = hydra_connect_ssl(ip, port, hostname);
|
||
}
|
||
}
|
||
|
||
int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options,
|
||
char *miscptr, FILE *fp, char *hostname, char *type,
|
||
ptr_header_node ptr_head, ptr_cookie_node ptr_cookie) {
|
||
char *empty = "";
|
||
char *login, *pass, clogin[256], cpass[256], b64login[345], b64pass[345];
|
||
char header[8096], *upd3variables;
|
||
char *cookie_header = NULL;
|
||
char *http_request = NULL;
|
||
int32_t found = !success_cond, i, j;
|
||
char content_length[MAX_CONTENT_LENGTH], proxy_string[MAX_PROXY_LENGTH];
|
||
|
||
memset(header, 0, sizeof(header));
|
||
cookie[0] = 0; // Réinitialiser les cookies d'une tentative antérieure
|
||
|
||
if (use_proxy > 0 && proxy_count > 0)
|
||
selected_proxy = random() % proxy_count;
|
||
|
||
/* Récupération du prochain login/mot de passe */
|
||
if (strlen(login = hydra_get_next_login()) == 0)
|
||
login = empty;
|
||
if (strlen(pass = hydra_get_next_password()) == 0)
|
||
pass = empty;
|
||
strcpy(b64login, login);
|
||
hydra_tobase64((unsigned char *)b64login, strlen(b64login), sizeof(b64login));
|
||
strcpy(b64pass, pass);
|
||
hydra_tobase64((unsigned char *)b64pass, strlen(b64pass), sizeof(b64pass));
|
||
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);
|
||
upd3variables = hydra_strrep(upd3variables, "^USER64^", b64login);
|
||
upd3variables = hydra_strrep(upd3variables, "^PASS64^", b64pass);
|
||
|
||
// Mise à jour des en‐têtes utilisateur (substitution dans les headers)
|
||
hdrrep(&ptr_head, "^USER^", clogin);
|
||
hdrrep(&ptr_head, "^PASS^", cpass);
|
||
hdrrep(&ptr_head, "^USER64^", b64login);
|
||
hdrrep(&ptr_head, "^PASS64^", b64pass);
|
||
|
||
/* Gestion du proxy (cas avec proxy authentifié ou non) */
|
||
if (use_proxy == 1 && proxy_authentication[selected_proxy] != NULL) {
|
||
/* --- Bloc pour proxy avec authentification --- */
|
||
if (getcookie) {
|
||
memset(proxy_string, 0, sizeof(proxy_string));
|
||
snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s%.600s", webtarget, cookieurl);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", proxy_string, NULL, cookie_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
|
||
return 1;
|
||
i = analyze_server_response(s);
|
||
if (strlen(cookie) > 0)
|
||
process_cookies(&ptr_cookie, cookie);
|
||
hydra_reconnect(s, ip, port, options, hostname);
|
||
}
|
||
if (strcmp(type, "POST") == 0) {
|
||
memset(proxy_string, 0, sizeof(proxy_string));
|
||
snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s%.600s", webtarget, url);
|
||
snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int32_t)strlen(upd3variables));
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", content_length);
|
||
else
|
||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||
if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("POST", proxy_string, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
return 1;
|
||
}
|
||
} else {
|
||
/* Cas GET avec proxy authentifié */
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", "0");
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", proxy_string, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
return 1;
|
||
}
|
||
}
|
||
} else if (use_proxy == 1) {
|
||
/* --- Bloc pour proxy sans authentification --- */
|
||
if (getcookie) {
|
||
memset(proxy_string, 0, sizeof(proxy_string));
|
||
snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s%.600s", webtarget, cookieurl);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", proxy_string, NULL, cookie_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
|
||
return 1;
|
||
i = analyze_server_response(s);
|
||
if (strlen(cookie) > 0)
|
||
process_cookies(&ptr_cookie, cookie);
|
||
hydra_reconnect(s, ip, port, options, hostname);
|
||
}
|
||
if (strcmp(type, "POST") == 0) {
|
||
memset(proxy_string, 0, sizeof(proxy_string));
|
||
snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s%.600s", webtarget, url);
|
||
snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int32_t)strlen(upd3variables));
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", content_length);
|
||
else
|
||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||
if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("POST", proxy_string, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
return 1;
|
||
}
|
||
} else {
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", "0");
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", proxy_string, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
return 1;
|
||
}
|
||
}
|
||
} else {
|
||
/* --- Bloc pour accès direct au serveur (sans proxy) --- */
|
||
normal_request = NULL;
|
||
if (getcookie) {
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", cookieurl, NULL, cookie_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
|
||
return 1;
|
||
i = analyze_server_response(s);
|
||
if (strlen(cookie) > 0) {
|
||
process_cookies(&ptr_cookie, cookie);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
}
|
||
hydra_reconnect(s, ip, port, options, hostname);
|
||
}
|
||
/* --- Traitement multipart --- */
|
||
if (multipart_mode) {
|
||
char *multipart_body = NULL;
|
||
/* Définir le boundary (ici, une valeur fixe, sans '\r\n') */
|
||
char multipart_boundary[64] = "----THC-HydraBoundaryz2Z2z";
|
||
multipart_body = build_multipart_body(multipart_boundary);
|
||
if (multipart_body == NULL) {
|
||
hydra_report(stderr, "[ERROR] Failed to build multipart body.\n");
|
||
return 0;
|
||
}
|
||
<<<<<<< Updated upstream
|
||
// now prepare for the "real" request
|
||
// first handle multipart/form-data, which is always POST
|
||
if (multipart_mode){
|
||
char *multipart_body = NULL;
|
||
char multipart_boundary[32] = "----THC-HydraBoundaryz2Z2z\r\n";
|
||
multipart_body = build_multipart_body(multipart_boundary);
|
||
if (multipart_body == NULL) {
|
||
hydra_report(stderr, "[ERROR] Failed to build multipart body. \n");
|
||
return 0;
|
||
}
|
||
snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int32_t)strlen(multipart_body));
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", content_length);
|
||
else
|
||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||
|
||
char content_type[256];
|
||
snprintf(content_type, sizeof(content_type) - 1, "multipart/for/data; boundary=%s", multipart_boundary);
|
||
if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Content-Type", content_type, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Content-type", content_type);
|
||
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
http_request = prepare_http_request("POST", url, multipart_body, normal_request);
|
||
free(multipart_body);
|
||
=======
|
||
/* Mettre à jour Content-Length pour le corps multipart */
|
||
snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int32_t)strlen(multipart_body));
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", content_length);
|
||
else
|
||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||
|
||
/* Mettre à jour Content-Type avec le boundary */
|
||
char content_type[256];
|
||
snprintf(content_type, sizeof(content_type) - 1, "multipart/form-data; boundary=%s", multipart_boundary);
|
||
if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Content-Type", content_type, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Content-Type", content_type);
|
||
|
||
/* Mettre à jour l'en-tête Cookie */
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
/* Préparer la requête POST avec le corps multipart */
|
||
http_request = prepare_http_request("POST", url, multipart_body, normal_request);
|
||
free(multipart_body);
|
||
return 1;
|
||
}
|
||
/* --- Traitement classique non-multipart --- */
|
||
if (strcmp(type, "POST") == 0) {
|
||
snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int32_t)strlen(upd3variables));
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", content_length);
|
||
else
|
||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||
if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("POST", url, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
>>>>>>> Stashed changes
|
||
return 1;
|
||
}
|
||
} else {
|
||
if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
|
||
hdrrepv(&ptr_head, "Content-Length", "0");
|
||
if (cookie_header != NULL)
|
||
free(cookie_header);
|
||
cookie_header = stringify_cookies(ptr_cookie);
|
||
if (!header_exists(&ptr_head, "Cookie", HEADER_TYPE_DEFAULT))
|
||
add_header(&ptr_head, "Cookie", cookie_header, HEADER_TYPE_DEFAULT);
|
||
else
|
||
hdrrepv(&ptr_head, "Cookie", cookie_header);
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
if (http_request != NULL)
|
||
free(http_request);
|
||
http_request = prepare_http_request("GET", url, upd3variables, normal_request);
|
||
if (hydra_send(s, http_request, strlen(http_request), 0) < 0) {
|
||
free(cookie_header);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (debug)
|
||
hydra_report_debug(stdout, "HTTP request sent:\n%s\n", http_request);
|
||
|
||
found = analyze_server_response(s);
|
||
|
||
if (redirected_flag && code_302_is_success)
|
||
found = success_cond;
|
||
|
||
if (auth_flag) { // 401 error
|
||
if (code_401_is_failure) {
|
||
hydra_completed_pair();
|
||
return 1;
|
||
} else {
|
||
hydra_report(stderr,
|
||
"[ERROR] received HTTP error code 401. The target may be using HTTP auth, "
|
||
"not a web form. Use module \"http%s-get\" instead, or set \"1=\".\n",
|
||
(options & OPTION_SSL) > 0 ? "s" : "");
|
||
return 2;
|
||
}
|
||
}
|
||
|
||
if (strlen(cookie) > 0)
|
||
process_cookies(&ptr_cookie, cookie);
|
||
|
||
// Gérer les redirections
|
||
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 && !code_302_is_success &&
|
||
(redirected_url_buff[0] != 0) && (redirected_cpt > 0)) {
|
||
// Traitement de la redirection (code non modifié ici)
|
||
// ...
|
||
}
|
||
|
||
if (found != -1 && found == success_cond &&
|
||
((redirected_flag && code_302_is_success) || redirected_flag == 0 || success_cond == 1) &&
|
||
redirected_cpt >= 0) {
|
||
hydra_report_found_host(port, ip, "www-form", fp);
|
||
hydra_completed_pair_found();
|
||
} else {
|
||
hydra_completed_pair();
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
void service_http_post_form(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE *fp, int32_t port, char *hostname) {
|
||
ptr_cookie_node ptr_cookie = NULL;
|
||
ptr_header_node ptr_head = initialize(ip, options, miscptr);
|
||
|
||
if (ptr_head)
|
||
service_http_form(ip, sp, options, miscptr, fp, port, hostname, "POST", &ptr_head, &ptr_cookie);
|
||
else {
|
||
hydra_report(stderr, "[ERROR] Could not launch head. Error while initializing.\n");
|
||
hydra_child_exit(2);
|
||
}
|
||
}
|
||
|
||
int32_t service_http_form_init(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE *fp, int32_t port, char *hostname) {
|
||
// called before the childrens are forked off, so this is the function
|
||
// which should be filled if initial connections and service setup has to be
|
||
// performed once only.
|
||
//
|
||
// fill if needed.
|
||
//
|
||
// return codes:
|
||
// 0 all OK
|
||
// -1 error, hydra will exit, so print a good error message here
|
||
|
||
if (initialize(ip, options, miscptr) == NULL)
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
ptr_header_node initialize(char *ip, unsigned char options, char *miscptr) {
|
||
ptr_header_node ptr_head = NULL;
|
||
char *ptr, *ptr2, *proxy_string;
|
||
#ifdef AF_INET6
|
||
unsigned char addr6[sizeof(struct in6_addr)];
|
||
#endif
|
||
|
||
if (use_proxy > 0 && proxy_count > 0)
|
||
selected_proxy = random() % proxy_count;
|
||
|
||
if (webtarget) {
|
||
free(webtarget);
|
||
webtarget = NULL;
|
||
}
|
||
|
||
if (cmdlinetarget != NULL)
|
||
webtarget = cmdlinetarget;
|
||
else
|
||
webtarget = hydra_address2string(ip);
|
||
if (port != 0)
|
||
webport = port;
|
||
else if ((options & OPTION_SSL) == 0)
|
||
webport = PORT_HTTP;
|
||
else
|
||
webport = PORT_HTTP_SSL;
|
||
|
||
/* normalise the webtarget for ipv6/port number */
|
||
ptr = malloc(strlen(webtarget) + 1 /* null */ + 6 /* :65535 */
|
||
#ifdef AF_INET6
|
||
+ 2 /* [] */
|
||
#endif
|
||
);
|
||
#ifdef AF_INET6
|
||
/* let libc decide if target is an ipv6 address */
|
||
if (inet_pton(AF_INET6, webtarget, addr6)) {
|
||
ptr2 = ptr + sprintf(ptr, "[%s]", webtarget);
|
||
} else {
|
||
#endif
|
||
ptr2 = ptr + sprintf(ptr, "%s", webtarget);
|
||
#ifdef AF_INET6
|
||
}
|
||
#endif
|
||
if (options & OPTION_SSL && webport != PORT_HTTP_SSL || !(options & OPTION_SSL) && webport != PORT_HTTP) {
|
||
sprintf(ptr2, ":%d", webport);
|
||
}
|
||
webtarget = ptr;
|
||
ptr = ptr2 = NULL;
|
||
|
||
sprintf(bufferurl, "%.6096s", miscptr);
|
||
ptr = url = bufferurl;
|
||
|
||
while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\'))
|
||
ptr++;
|
||
if (*ptr != 0)
|
||
*ptr++ = 0;
|
||
variables = ptr;
|
||
|
||
while (*ptr != 0 && (*ptr != ':' || *(ptr - 1) == '\\'))
|
||
ptr++;
|
||
if (*ptr != 0)
|
||
*ptr++ = 0;
|
||
|
||
optional1 = cond = ptr;
|
||
|
||
ptr2 = ptr + strlen(ptr);
|
||
|
||
while (ptr2 > ptr && (*ptr2 != ':' || *(ptr2 - 1) == '\\'))
|
||
ptr2--;
|
||
|
||
if (*ptr2 == ':') {
|
||
*ptr2++ = 0;
|
||
cond = ptr2;
|
||
}
|
||
|
||
if (optional1 == cond)
|
||
optional1 = NULL;
|
||
|
||
if (strstr(url, "\\:") != NULL) {
|
||
if ((ptr = malloc(strlen(url) + 1)) != NULL) {
|
||
strcpy(ptr, hydra_strrep(url, "\\:", ":"));
|
||
url = ptr;
|
||
}
|
||
}
|
||
if (strstr(variables, "\\:") != NULL) {
|
||
if ((ptr = malloc(strlen(variables) + 1)) != NULL) {
|
||
strcpy(ptr, hydra_strrep(variables, "\\:", ":"));
|
||
variables = ptr;
|
||
}
|
||
}
|
||
if (strstr(cond, "\\:") != NULL) {
|
||
if ((ptr = malloc(strlen(cond) + 1)) != NULL) {
|
||
strcpy(ptr, hydra_strrep(cond, "\\:", ":"));
|
||
cond = ptr;
|
||
}
|
||
}
|
||
|
||
// printf("ptr: %s ptr2: %s cond: %s url: %s variables: %s optional1: %s\n", ptr, ptr2, cond, url, variables, optional1 == NULL ? "null" : optional1);
|
||
|
||
if (url == NULL || variables == NULL || cond == NULL /*|| optional1 == NULL */)
|
||
hydra_child_exit(2);
|
||
|
||
if (*cond == 0) {
|
||
fprintf(stderr, "[ERROR] invalid number of parameters in module option\n");
|
||
return NULL;
|
||
}
|
||
|
||
sprintf(cookieurl, "%.1000s", url);
|
||
|
||
// conditions now have to contain F or S to set the fail or success condition
|
||
if (strpos(cond, "F=") == 0) {
|
||
success_cond = 0;
|
||
cond += 2;
|
||
} else if (*cond != 0 && (strpos(cond, "S=") == 0)) {
|
||
success_cond = 1;
|
||
cond += 2;
|
||
} else {
|
||
// by default condition is a fail
|
||
success_cond = 0;
|
||
}
|
||
|
||
// printf("miscptr: %s, url=%s, variables=%s, ptr=%s, optional1: %s, cond: %s (%d)\n", miscptr, url, variables, ptr, optional1, cond, success_cond);
|
||
|
||
/*
|
||
* Parse the user-supplied options.
|
||
* Beware of the backslashes (\)!
|
||
*/
|
||
if (!parse_options(optional1, &ptr_head))
|
||
return NULL;
|
||
|
||
/* again: no snprintf to be portable. don't worry, buffer can't overflow */
|
||
if (use_proxy == 1 && proxy_authentication[selected_proxy] != NULL) {
|
||
// proxy with authentication
|
||
add_header(&ptr_head, "Host", webtarget, HEADER_TYPE_DEFAULT);
|
||
add_header(&ptr_head, "User-Agent", "Mozilla 5.0 (Hydra Proxy Auth)", HEADER_TYPE_DEFAULT);
|
||
proxy_string = (char *)malloc(strlen(proxy_authentication[selected_proxy]) + 10);
|
||
if (proxy_string) {
|
||
strcpy(proxy_string, "Basic ");
|
||
strcat(proxy_string, proxy_authentication[selected_proxy]);
|
||
add_header(&ptr_head, "Proxy-Authorization", proxy_string, HEADER_TYPE_DEFAULT);
|
||
} else {
|
||
hydra_report(stderr, "Out of memory for \"Proxy-Authorization\" header.\n");
|
||
return NULL;
|
||
}
|
||
if (getcookie) {
|
||
// doing a GET to save cookies
|
||
if (cookie_request != NULL)
|
||
free(cookie_request);
|
||
cookie_request = stringify_headers(&ptr_head);
|
||
}
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
} else {
|
||
if (use_proxy == 1) {
|
||
// proxy without authentication
|
||
add_header(&ptr_head, "Host", webtarget, HEADER_TYPE_DEFAULT);
|
||
add_header(&ptr_head, "User-Agent", "Mozilla/5.0 (Hydra Proxy)", HEADER_TYPE_DEFAULT);
|
||
if (getcookie) {
|
||
// doing a GET to get cookies
|
||
if (cookie_request != NULL)
|
||
free(cookie_request);
|
||
cookie_request = stringify_headers(&ptr_head);
|
||
}
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
} else {
|
||
// direct web server, no proxy
|
||
add_header(&ptr_head, "Host", webtarget, HEADER_TYPE_DEFAULT);
|
||
add_header(&ptr_head, "User-Agent", "Mozilla/5.0 (Hydra)", HEADER_TYPE_DEFAULT);
|
||
|
||
if (getcookie) {
|
||
// doing a GET to save cookies
|
||
if (cookie_request != NULL)
|
||
free(cookie_request);
|
||
cookie_request = stringify_headers(&ptr_head);
|
||
}
|
||
|
||
if (normal_request != NULL)
|
||
free(normal_request);
|
||
normal_request = stringify_headers(&ptr_head);
|
||
}
|
||
}
|
||
|
||
return ptr_head;
|
||
}
|
||
|
||
void usage_http_form(const char *service) {
|
||
printf("Module %s requires the page and the parameters for the web form.\n\n"
|
||
"By default this module is configured to follow a maximum of 5 "
|
||
"redirections in\n"
|
||
"a row. It always gathers a new cookie from the same URL without "
|
||
"variables\n"
|
||
"The parameters requires at a minimum three \":\" separated values,\n"
|
||
"plus optional values.\n"
|
||
"(Note: if you need a colon in the option string as value, escape it "
|
||
"with \"\\:\", but do not escape a \"\\\" with \"\\\\\".)\n"
|
||
"\nSyntax: <url>:<form parameters>[:<optional>[:<optional>]:<condition string>\n"
|
||
"\nFirst is the page on the server to GET or POST to (URL), e.g. \"/login\".\n"
|
||
"Second is the POST/GET variables (taken from either the browser, proxy, etc.)\n"
|
||
" without the initial '?' character and the usernames and passwords being\n"
|
||
" replaced with \"^USER^\" (\"^USER64^\" for base64 encodings) and \"^PASS^\"\n"
|
||
" (\"^PASS64^\" for base64 encodings).\n"
|
||
"Third are optional parameters (see below)\n"
|
||
"Last is the string that it checks for an *invalid* login (by default).\n"
|
||
" Invalid condition login check can be preceded by \"F=\", successful condition\n"
|
||
" login check must be preceded by \"S=\".\n"
|
||
" This is where most people get it wrong! You have to check the webapp what a\n"
|
||
" failed string looks like and put it in this parameter! Add the -d switch to see\n"
|
||
" the sent/received data!\n"
|
||
" Note that using invalid login condition checks can result in false positives!\n"
|
||
"\nThe following parameters are optional and are put between the form parameters\n"
|
||
"and the condition string; seperate them too with colons:\n"
|
||
" 1= 401 error response is interpreted as user/pass wrong\n"
|
||
" 2= 302 page forward return codes identify a successful attempt\n"
|
||
" (c|C)=/page/uri to define a different page to gather initial "
|
||
"cookies from\n"
|
||
" (g|G)= skip pre-requests - only use this when no pre-cookies are required\n"
|
||
" (h|H)=My-Hdr\\: foo to send a user defined HTTP header with each "
|
||
"request\n"
|
||
" ^USER[64]^ and ^PASS[64]^ can also be put into these "
|
||
"headers!\n"
|
||
" Note: 'h' will add the user-defined header at the end\n"
|
||
" regardless it's already being sent by Hydra or not.\n"
|
||
" 'H' will replace the value of that header if it "
|
||
"exists, by the\n"
|
||
" one supplied by the user, or add the header at the "
|
||
"end\n"
|
||
"\nNote that if you are going to put colons (:) in your headers you should escape\n"
|
||
"them with a backslash (\\). All colons that are not option separators should be\n"
|
||
"escaped (see the examples above and below).\n"
|
||
"You can specify a header without escaping the colons, but that way you will not\n"
|
||
"be able to put colons in the header value itself, as they will be interpreted by\n"
|
||
"hydra as option separators.\n"
|
||
"\nExamples:\n"
|
||
" \"/login.php:user=^USER^&pass=^PASS^:incorrect\"\n"
|
||
" \"/"
|
||
"login.php:user=^USER64^&pass=^PASS64^&colon=colon\\:escape:S=result="
|
||
"success\"\n"
|
||
" \"/login.php:user=^USER^&pass=^PASS^&mid=123:authlog=.*failed\"\n"
|
||
" \"/:user=^USER&pass=^PASS^:H=Authorization\\: Basic "
|
||
"dT1w:H=Cookie\\: sessid=aaaa:h=X-User\\: ^USER^:H=User-Agent\\: wget\"\n"
|
||
" \"/exchweb/bin/auth/:F=failed"
|
||
"owaauth.dll:destination=http%%3A%%2F%%2F<target>%%2Fexchange&flags=0&"
|
||
"username=<domain>%%5C^USER^&password=^PASS^&SubmitCreds=x&trusted=0:"
|
||
"C=/exchweb\":reason=\n",
|
||
service);
|
||
}
|