#include "hydra-mod.h" #include "sasl.h" /* david: ref http://xmpp.org/rfcs/rfc3920.html */ extern char *HYDRA_EXIT; static char *domain = NULL; int32_t xmpp_auth_mechanism = AUTH_ERROR; char *JABBER_CLIENT_INIT_STR = ""; int32_t start_xmpp(int32_t s, char *ip, int32_t port, unsigned char options, char *miscptr, FILE * fp) { char *empty = "\"\""; char *login, *pass, buffer[500], buffer2[500]; char *AUTH_STR = ""; char *CHALLENGE_STR = ""; char *CHALLENGE_STR2 = ""; char *CHALLENGE_END_STR = ""; char *RESPONSE_STR = ""; char *RESPONSE_END_STR = ""; char *fooptr, *buf; if (strlen(login = hydra_get_next_login()) == 0) login = empty; if (strlen(pass = hydra_get_next_password()) == 0) pass = empty; switch (xmpp_auth_mechanism) { case AUTH_SCRAMSHA1: sprintf(buffer, "%s%s%s", AUTH_STR, "SCRAM-SHA-1", AUTH_STR_END); break; case AUTH_CRAMMD5: sprintf(buffer, "%s%s%s", AUTH_STR, "CRAM-MD5", AUTH_STR_END); break; case AUTH_DIGESTMD5: sprintf(buffer, "%s%s%s", AUTH_STR, "DIGEST-MD5", AUTH_STR_END); break; case AUTH_PLAIN: sprintf(buffer, "%s%s%s", AUTH_STR, "PLAIN", AUTH_STR_END); break; default: sprintf(buffer, "%s%s%s", AUTH_STR, "LOGIN", AUTH_STR_END); break; } hydra_send(s, buffer, strlen(buffer), 0); usleepn(300); if ((buf = hydra_receive_line(s)) == NULL) return 3; if (debug) hydra_report(stderr, "DEBUG S: %s\n", buf); if ((strstr(buf, CHALLENGE_STR) != NULL) || (strstr(buf, CHALLENGE_STR2) != NULL)) { /* the challenge string is sent depending of the auth chosen it's the case for login auth */ char *ptr = strstr(buf, CHALLENGE_STR); if (!ptr) ptr = strstr(buf, CHALLENGE_STR2); char *ptr_end = strstr(ptr, CHALLENGE_END_STR); int32_t chglen = ptr_end - ptr - strlen(CHALLENGE_STR); if ((chglen > 0) && (chglen < sizeof(buffer2))) { strncpy(buffer2, ptr + strlen(CHALLENGE_STR), chglen); buffer2[chglen] = '\0'; memset(buffer, 0, sizeof(buffer)); from64tobits((char *) buffer, buffer2); if (debug) hydra_report(stderr, "DEBUG S: %s\n", buffer); } switch (xmpp_auth_mechanism) { case AUTH_LOGIN:{ if (strstr(buffer, "sername") != NULL) { strncpy(buffer2, login, sizeof(buffer2) - 1); buffer2[sizeof(buffer2) - 1] = '\0'; hydra_tobase64((unsigned char *) buffer2, strlen(buffer2), sizeof(buffer2)); sprintf(buffer, "%s%.250s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); if (debug) hydra_report(stderr, "DEBUG C: %s\n", buffer); if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { free(buf); return 1; } buf = hydra_receive_line(s); if (buf == NULL) return 1; /* server now would ask for the password */ if ((strstr(buf, CHALLENGE_STR) != NULL) || (strstr(buf, CHALLENGE_STR2) != NULL)) { char *ptr = strstr(buf, CHALLENGE_STR); if (!ptr) ptr = strstr(buf, CHALLENGE_STR2); char *ptr_end = strstr(ptr, CHALLENGE_END_STR); int32_t chglen = ptr_end - ptr - strlen(CHALLENGE_STR); if ((chglen > 0) && (chglen < sizeof(buffer2))) { strncpy(buffer2, ptr + strlen(CHALLENGE_STR), chglen); buffer2[chglen] = '\0'; memset(buffer, 0, sizeof(buffer)); from64tobits((char *) buffer, buffer2); if (strstr(buffer, "assword") != NULL) { strncpy(buffer2, pass, sizeof(buffer2) - 1); buffer2[sizeof(buffer2) - 1] = '\0'; hydra_tobase64((unsigned char *) buffer2, strlen(buffer2), sizeof(buffer2)); sprintf(buffer, "%s%.250s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); } } else { hydra_report(stderr, "[ERROR] xmpp could not extract challenge from server\n"); free(buf); return 1; } } } } break; #ifdef LIBOPENSSL case AUTH_PLAIN:{ memset(buffer2, 0, sizeof(buffer)); sasl_plain(buffer2, login, pass); sprintf(buffer, "%s%.250s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); if (debug) hydra_report(stderr, "DEBUG C: %s\n", buffer); } break; case AUTH_CRAMMD5:{ int32_t rc = 0; char *preplogin; memset(buffer2, 0, sizeof(buffer2)); sasl_cram_md5(buffer2, pass, buffer); rc = sasl_saslprep(login, SASL_ALLOW_UNASSIGNED, &preplogin); if (rc) { free(buf); return 3; } sprintf(buffer, "%.200s %.250s", preplogin, buffer2); if (debug) hydra_report(stderr, "DEBUG C: %s\n", buffer); hydra_tobase64((unsigned char *) buffer, strlen(buffer), sizeof(buffer)); sprintf(buffer2, "%s%.250s%s", RESPONSE_STR, buffer, RESPONSE_END_STR); strncpy(buffer, buffer2, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = '\0'; free(preplogin); } break; case AUTH_DIGESTMD5:{ memset(buffer2, 0, sizeof(buffer2)); fooptr = buffer2; sasl_digest_md5(fooptr, login, pass, buffer, domain, "xmpp", NULL, 0, NULL); if (fooptr == NULL) { free(buf); return 3; } if (debug) hydra_report(stderr, "DEBUG C: %s\n", buffer2); hydra_tobase64((unsigned char *) buffer2, strlen(buffer2), sizeof(buffer2)); snprintf(buffer, sizeof(buffer), "%s%s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); } break; case AUTH_SCRAMSHA1:{ /*client-first-message */ char clientfirstmessagebare[200]; char *preplogin; int32_t rc = sasl_saslprep(login, SASL_ALLOW_UNASSIGNED, &preplogin); if (rc) { free(buf); return 3; } snprintf(clientfirstmessagebare, sizeof(clientfirstmessagebare), "n=%s,r=hydra", preplogin); free(preplogin); sprintf(buffer2, "n,,%.200s", clientfirstmessagebare); hydra_tobase64((unsigned char *) buffer2, strlen(buffer2), sizeof(buffer2)); snprintf(buffer, sizeof(buffer), "%s%s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); free(buf); if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { return 1; } buf = hydra_receive_line(s); if (buf == NULL) return 1; if ((strstr(buf, CHALLENGE_STR) != NULL) || (strstr(buf, CHALLENGE_STR2) != NULL)) { char serverfirstmessage[200]; char *ptr = strstr(buf, CHALLENGE_STR); if (!ptr) ptr = strstr(buf, CHALLENGE_STR2); char *ptr_end = strstr(ptr, CHALLENGE_END_STR); int32_t chglen = ptr_end - ptr - strlen(CHALLENGE_STR); if ((chglen > 0) && (chglen < sizeof(buffer2))) { strncpy(buffer2, ptr + strlen(CHALLENGE_STR), chglen); buffer2[chglen] = '\0'; } else { hydra_report(stderr, "[ERROR] xmpp could not extract challenge from server\n"); free(buf); return 1; } /*server-first-message */ memset(buffer, 0, sizeof(buffer)); from64tobits((char *) buffer, buffer2); strncpy(serverfirstmessage, buffer, sizeof(serverfirstmessage) - 1); serverfirstmessage[sizeof(serverfirstmessage) - 1] = '\0'; memset(buffer2, 0, sizeof(buffer2)); fooptr = buffer2; sasl_scram_sha1(fooptr, pass, clientfirstmessagebare, serverfirstmessage); if (fooptr == NULL) { hydra_report(stderr, "[ERROR] Can't compute client response\n"); free(buf); return 1; } hydra_tobase64((unsigned char *) buffer2, strlen(buffer2), sizeof(buffer2)); snprintf(buffer, sizeof(buffer), "%s%s%s", RESPONSE_STR, buffer2, RESPONSE_END_STR); } else { if (verbose || debug) hydra_report(stderr, "[ERROR] Not a valid server challenge\n"); free(buf); return 1; } } break; #endif ptr = 0; } free(buf); if (hydra_send(s, buffer, strlen(buffer), 0) < 0) { return 1; } usleepn(50); buf = hydra_receive_line(s); if (buf == NULL) return 1; //we test the challenge tag as digest-md5 when connected is sending "rspauth" value //so if we are receiving a second challenge we assume the auth is good if ((strstr(buf, "= 0) sock = hydra_disconnect(sock); if ((options & OPTION_SSL) == 0) { if (port != 0) myport = port; sock = hydra_connect_tcp(ip, myport); port = myport; } else { if (port != 0) mysslport = port; sock = hydra_connect_ssl(ip, mysslport, hostname); port = mysslport; } if (sock < 0) { if (verbose || debug) hydra_report(stderr, "[ERROR] Child with pid %d terminating, can not connect\n", (int32_t) getpid()); hydra_child_exit(1); } memset(buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%s%s%s", JABBER_CLIENT_INIT_STR, domain, JABBER_CLIENT_INIT_END_STR); if (hydra_send(sock, buffer, strlen(buffer), 0) < 0) { hydra_child_exit(1); } //some server is longer to answer usleepn(300); do { if ((buf = hydra_receive_line(sock)) == NULL) { /* no auth method identified */ hydra_report(stderr, "[ERROR] no authentication methods can be identified\n"); hydra_child_exit(1); } if (strstr(buf, "SCRAM-SHA-1") != NULL) { xmpp_auth_mechanism = AUTH_SCRAMSHA1; } if (strstr(buf, "CRAM-MD5") != NULL) { xmpp_auth_mechanism = AUTH_CRAMMD5; } if (strstr(buf, "DIGEST-MD5") != NULL) { xmpp_auth_mechanism = AUTH_DIGESTMD5; } if (strstr(buf, "PLAIN") != NULL) { xmpp_auth_mechanism = AUTH_PLAIN; } if (strstr(buf, "LOGIN") != NULL) { xmpp_auth_mechanism = AUTH_LOGIN; } } free(buf); } while (xmpp_auth_mechanism == AUTH_ERROR); if ((miscptr != NULL) && (strlen(miscptr) > 0)) { int32_t i; for (i = 0; i < strlen(miscptr); i++) miscptr[i] = (char) toupper((int32_t) miscptr[i]); if (strncmp(miscptr, "LOGIN", 5) == 0) xmpp_auth_mechanism = AUTH_LOGIN; if (strncmp(miscptr, "PLAIN", 5) == 0) xmpp_auth_mechanism = AUTH_PLAIN; #ifdef LIBOPENSSL if (strncmp(miscptr, "CRAM-MD5", 8) == 0) xmpp_auth_mechanism = AUTH_CRAMMD5; if (strncmp(miscptr, "SCRAM-SHA1", 10) == 0) xmpp_auth_mechanism = AUTH_SCRAMSHA1; if (strncmp(miscptr, "DIGEST-MD5", 10) == 0) xmpp_auth_mechanism = AUTH_DIGESTMD5; #endif } if (verbose) { switch (xmpp_auth_mechanism) { case AUTH_LOGIN: hydra_report(stderr, "[VERBOSE] using XMPP LOGIN AUTH mechanism\n"); break; case AUTH_PLAIN: hydra_report(stderr, "[VERBOSE] using XMPP PLAIN AUTH mechanism\n"); break; #ifdef LIBOPENSSL case AUTH_CRAMMD5: hydra_report(stderr, "[VERBOSE] using XMPP CRAM-MD5 AUTH mechanism\n"); break; case AUTH_SCRAMSHA1: hydra_report(stderr, "[VERBOSE] using XMPP SCRAM-SHA1 AUTH mechanism\n"); break; case AUTH_DIGESTMD5: hydra_report(stderr, "[VERBOSE] using XMPP DIGEST-MD5 AUTH mechanism\n"); break; #endif } } #ifdef LIBOPENSSL //check if tls is not wanted and if tls is available if (!disable_tls && tls) { char *STARTTLS = ""; hydra_send(sock, STARTTLS, strlen(STARTTLS), 0); usleepn(300); buf = hydra_receive_line(sock); if (buf == NULL || strstr(buf, "= 0) sock = hydra_disconnect(sock); hydra_child_exit(0); return; default: hydra_report(stderr, "[ERROR] Caught unknown return code, exiting!\n"); hydra_child_exit(2); } run = next_run; } } int32_t service_xmpp_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 return 0; } void usage_xmpp(const char* service) { printf("Module xmpp is optionally taking one authentication type of:\n" " LOGIN (default), PLAIN, CRAM-MD5, DIGEST-MD5, SCRAM-SHA1\n\n" "Note, the target passed should be a fdqn as the value is used in the Jabber init request, example: hermes.jabber.org\n\n"); }