mirror of
https://github.com/vanhauser-thc/thc-hydra.git
synced 2025-07-06 04:51:40 -07:00
Merge pull request #1001 from motypi/add-http-multipart-format
Add http multipart format
This commit is contained in:
commit
b19b39c575
1 changed files with 124 additions and 9 deletions
|
@ -67,6 +67,7 @@ int32_t getcookie = 1;
|
||||||
int32_t auth_flag = 0;
|
int32_t auth_flag = 0;
|
||||||
int32_t code_302_is_success = 0;
|
int32_t code_302_is_success = 0;
|
||||||
int32_t code_401_is_failure = 0;
|
int32_t code_401_is_failure = 0;
|
||||||
|
int32_t multipart_mode = 0;
|
||||||
|
|
||||||
char cookie[4096] = "", cmiscptr[1024];
|
char cookie[4096] = "", cmiscptr[1024];
|
||||||
|
|
||||||
|
@ -454,6 +455,15 @@ int32_t parse_options(char *miscptr, ptr_header_node *ptr_head) {
|
||||||
else
|
else
|
||||||
miscptr += strlen(miscptr);
|
miscptr += strlen(miscptr);
|
||||||
break;
|
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': // fall through
|
||||||
case 'G':
|
case 'G':
|
||||||
ptr = miscptr + 2;
|
ptr = miscptr + 2;
|
||||||
|
@ -532,6 +542,97 @@ int32_t parse_options(char *miscptr, ptr_header_node *ptr_head) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *build_multipart_body(char *multipart_boundary) {
|
||||||
|
if (!variables)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *body = NULL;
|
||||||
|
size_t body_size = 0;
|
||||||
|
|
||||||
|
// Duplicate "variables" for tokenizing
|
||||||
|
char *vars_dup = strdup(variables);
|
||||||
|
if (!vars_dup)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Tokenize the string using '&' as a delimiter
|
||||||
|
char *pair = strtok(vars_dup, "&");
|
||||||
|
while (pair != NULL) {
|
||||||
|
// Find the '=' separator in each pair
|
||||||
|
char *equal_sign = strchr(pair, '=');
|
||||||
|
if (!equal_sign) {
|
||||||
|
pair = strtok(NULL, "&");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*equal_sign = '\0';
|
||||||
|
char *key = pair;
|
||||||
|
char *value = equal_sign + 1;
|
||||||
|
|
||||||
|
// Build the multipart section for the field
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Reallocate the body buffer to add this section
|
||||||
|
size_t new_body_size = body_size + section_len;
|
||||||
|
char *new_body = realloc(body, new_body_size + 1); // +1 for null terminator
|
||||||
|
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);
|
||||||
|
|
||||||
|
pair = strtok(NULL, "&");
|
||||||
|
}
|
||||||
|
free(vars_dup);
|
||||||
|
|
||||||
|
// Append the closing boundary: --<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) {
|
char *prepare_http_request(char *type, char *path, char *params, char *headers) {
|
||||||
uint32_t reqlen = 0;
|
uint32_t reqlen = 0;
|
||||||
char *http_request = NULL;
|
char *http_request = NULL;
|
||||||
|
@ -740,7 +841,7 @@ int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options
|
||||||
char *http_request = NULL;
|
char *http_request = NULL;
|
||||||
int32_t found = !success_cond, i, j;
|
int32_t found = !success_cond, i, j;
|
||||||
char content_length[MAX_CONTENT_LENGTH], proxy_string[MAX_PROXY_LENGTH];
|
char content_length[MAX_CONTENT_LENGTH], proxy_string[MAX_PROXY_LENGTH];
|
||||||
|
char content_type[256];
|
||||||
memset(header, 0, sizeof(header));
|
memset(header, 0, sizeof(header));
|
||||||
cookie[0] = 0; // reset cookies from potential previous attempt
|
cookie[0] = 0; // reset cookies from potential previous attempt
|
||||||
|
|
||||||
|
@ -760,11 +861,24 @@ int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options
|
||||||
clogin[sizeof(clogin) - 1] = 0;
|
clogin[sizeof(clogin) - 1] = 0;
|
||||||
strncpy(cpass, html_encode(pass), sizeof(cpass) - 1);
|
strncpy(cpass, html_encode(pass), sizeof(cpass) - 1);
|
||||||
cpass[sizeof(cpass) - 1] = 0;
|
cpass[sizeof(cpass) - 1] = 0;
|
||||||
upd3variables = hydra_strrep(variables, "^USER^", clogin);
|
|
||||||
|
if (multipart_mode) {
|
||||||
|
snprintf(content_type, sizeof(content_type), "multipart/form-data; boundary=----THC-HydraBoundaryz2Z2z");
|
||||||
|
char *multipart_body = build_multipart_body("----THC-HydraBoundaryz2Z2z");
|
||||||
|
upd3variables = multipart_body;
|
||||||
|
|
||||||
|
}else{
|
||||||
|
snprintf(content_type, sizeof(content_type), "application/x-www-form-urlencoded");
|
||||||
|
upd3variables = variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
upd3variables = hydra_strrep(upd3variables, "^USER^", clogin);
|
||||||
upd3variables = hydra_strrep(upd3variables, "^PASS^", cpass);
|
upd3variables = hydra_strrep(upd3variables, "^PASS^", cpass);
|
||||||
upd3variables = hydra_strrep(upd3variables, "^USER64^", b64login);
|
upd3variables = hydra_strrep(upd3variables, "^USER64^", b64login);
|
||||||
upd3variables = hydra_strrep(upd3variables, "^PASS64^", b64pass);
|
upd3variables = hydra_strrep(upd3variables, "^PASS64^", b64pass);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Replace the user/pass placeholders in the user-supplied headers
|
// Replace the user/pass placeholders in the user-supplied headers
|
||||||
hdrrep(&ptr_head, "^USER^", clogin);
|
hdrrep(&ptr_head, "^USER^", clogin);
|
||||||
hdrrep(&ptr_head, "^PASS^", cpass);
|
hdrrep(&ptr_head, "^PASS^", cpass);
|
||||||
|
@ -796,7 +910,7 @@ int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options
|
||||||
else
|
else
|
||||||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||||||
if (!header_exists(&ptr_head, "Content-Type", 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);
|
add_header(&ptr_head, "Content-Type", content_type, HEADER_TYPE_DEFAULT);
|
||||||
if (cookie_header != NULL)
|
if (cookie_header != NULL)
|
||||||
free(cookie_header);
|
free(cookie_header);
|
||||||
cookie_header = stringify_cookies(ptr_cookie);
|
cookie_header = stringify_cookies(ptr_cookie);
|
||||||
|
@ -862,7 +976,7 @@ int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options
|
||||||
else
|
else
|
||||||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||||||
if (!header_exists(&ptr_head, "Content-Type", 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);
|
add_header(&ptr_head, "Content-Type", content_type, HEADER_TYPE_DEFAULT);
|
||||||
if (cookie_header != NULL)
|
if (cookie_header != NULL)
|
||||||
free(cookie_header);
|
free(cookie_header);
|
||||||
cookie_header = stringify_cookies(ptr_cookie);
|
cookie_header = stringify_cookies(ptr_cookie);
|
||||||
|
@ -929,7 +1043,7 @@ int32_t start_http_form(int32_t s, char *ip, int32_t port, unsigned char options
|
||||||
else
|
else
|
||||||
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
|
||||||
if (!header_exists(&ptr_head, "Content-Type", 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);
|
add_header(&ptr_head, "Content-Type", content_type, HEADER_TYPE_DEFAULT);
|
||||||
if (cookie_header != NULL)
|
if (cookie_header != NULL)
|
||||||
free(cookie_header);
|
free(cookie_header);
|
||||||
cookie_header = stringify_cookies(ptr_cookie);
|
cookie_header = stringify_cookies(ptr_cookie);
|
||||||
|
@ -1479,6 +1593,7 @@ void usage_http_form(const char *service) {
|
||||||
"and the condition string; seperate them too with colons:\n"
|
"and the condition string; seperate them too with colons:\n"
|
||||||
" 1= 401 error response is interpreted as user/pass wrong\n"
|
" 1= 401 error response is interpreted as user/pass wrong\n"
|
||||||
" 2= 302 page forward return codes identify a successful attempt\n"
|
" 2= 302 page forward return codes identify a successful attempt\n"
|
||||||
|
" M= attack forms that use multipart format\n"
|
||||||
" (c|C)=/page/uri to define a different page to gather initial "
|
" (c|C)=/page/uri to define a different page to gather initial "
|
||||||
"cookies from\n"
|
"cookies from\n"
|
||||||
" (g|G)= skip pre-requests - only use this when no pre-cookies are required\n"
|
" (g|G)= skip pre-requests - only use this when no pre-cookies are required\n"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue