#include "hydra-mod.h" #ifdef LIBOPENSSL #include #include #include #include #include #endif extern int32_t hydra_data_ready_timed(int32_t socket, long sec, long usec); extern char *HYDRA_EXIT; extern int32_t child_head_no; char snmpv3buf[1024], *snmpv3info = NULL; int32_t snmpv3infolen = 0, snmpversion = 1, snmpread = 1, hashtype = 1, enctype = 0; unsigned char snmpv3_init[] = {0x30, 0x3e, 0x02, 0x01, 0x03, 0x30, 0x11, 0x02, 0x04, 0x08, 0x86, 0xdd, 0xf0, 0x02, 0x03, 0x00, 0xff, 0xe3, 0x04, 0x01, 0x04, 0x02, 0x01, 0x03, 0x04, 0x10, 0x30, 0x0e, 0x04, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x30, 0x14, 0x04, 0x00, 0x04, 0x00, 0xa0, 0x0e, 0x02, 0x04, 0x3f, 0x44, 0x5c, 0xbc, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x00}; unsigned char snmpv3_get1[] = {0x30, 0x77, 0x02, 0x01, 0x03, 0x30, 0x11, 0x02, 0x04, 0x08, 0x86, 0xdd, 0xef, 0x02, 0x03, 0x00, 0xff, 0xe3, 0x04, 0x01, 0x05, 0x02, 0x01, 0x03}; unsigned char snmpv3_get2[] = {0x30, 0x2e, 0x04, 0x0c, 0x80, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, 0x1f, 0xca, 0x8d, 0x82, 0x1b, 0x04, 0x00, 0xa0, 0x1c, 0x02, 0x04, 0x3f, 0x44, 0x5c, 0xbb, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x05, 0x00}; unsigned char snmpv3_nouser[] = {0x04, 0x00, 0x04, 0x00, 0x04, 0x00}; struct SNMPV1_A { char ID; char len; char ver[3]; char comid; char comlen; }; struct SNMPV1_A snmpv1_a = {.ID = '\x30', .len = '\x00', .ver = "\x02\x01\x00", /* \x02\x01\x01 for snmpv2c, \x02\x01\x03 for snmpv3 */ .comid = '\x04', .comlen = '\x00'}; struct SNMPV1_R { unsigned char type[2]; unsigned char identid[2]; unsigned char ident[4]; unsigned char errstat[3]; unsigned char errind[3]; unsigned char objectid[2]; unsigned char object[11]; unsigned char value[3]; } snmpv1_r = { .type = "\xa0\x1b", /* GET */ .identid = "\x02\x04", .ident = "\x1a\x5e\x97\x00", /* random crap :) */ .errstat = "\x02\x01\x00", /* no error */ .errind = "\x02\x01\x00", /* error index 0 */ .objectid = "\x30\x0d", .object = "\x30\x0b\x06\x07\x2b\x06\x01\x02\x01\x01\x01", /* sysDescr */ .value = "\x05\x00" /* we just read, so value = 0 */ }; struct SNMPV1_W { unsigned char type[2]; unsigned char identid[2]; unsigned char ident[4]; unsigned char errstat[3]; unsigned char errind[3]; unsigned char objectid[2]; unsigned char object[12]; unsigned char value[8]; } snmpv1_w = { .type = "\xa3\x21", /* SET */ .identid = "\x02\x04", .ident = "\x1a\x5e\x97\x22", /* random crap :) */ .errstat = "\x02\x01\x00", /* no error */ .errind = "\x02\x01\x00", /* error index 0 */ .objectid = "\x30\x13", /* string */ .object = "\x30\x11\x06\x08\x2b\x06\x01\x02\x01\x01\x05\x00", .value = "\x04\x05Hydra" /* writing hydra :-) */ }; #ifdef LIBOPENSSL void password_to_key_md5(u_char *password, /* IN */ u_int passwordlen, /* IN */ u_char *engineID, /* IN - pointer to snmpEngineID */ u_int engineLength, /* IN - length of snmpEngineID */ u_char *key) { /* OUT - pointer to caller 16-octet buffer */ MD5_CTX MD; u_char *cp, password_buf[80], *mypass = password, bpass[17]; u_long password_index = 0, count = 0, i, mylen, myelen = engineLength; if (strlen(password) > passwordlen) passwordlen = strlen(password); if (passwordlen > sizeof(bpass) - 1) passwordlen = sizeof(bpass) - 1; mylen = passwordlen; if (mylen < 8) { memset(bpass, 0, sizeof(bpass)); strncpy(bpass, password, sizeof(bpass) - 1); while (mylen < 8) { strcat(bpass, password); mylen += passwordlen; } mypass = bpass; } if (myelen > 32) myelen = 32; MD5_Init(&MD); /* initialize MD5 */ /* Use while loop until we've done 1 Megabyte */ while (count < 1048576) { cp = password_buf; for (i = 0; i < 64; i++) { /* Take the next octet of the password, wrapping */ /* to the beginning of the password as necessary. */ *cp++ = mypass[password_index++ % mylen]; } MD5_Update(&MD, password_buf, 64); count += 64; } MD5_Final(key, &MD); /* tell MD5 we're done */ /* Now localize the key with the engineID and pass */ /* through MD5 to produce final key */ /* May want to ensure that engineLength <= 32, */ /* otherwise need to use a buffer larger than 64 */ memcpy(password_buf, key, 16); memcpy(password_buf + 16, engineID, myelen); memcpy(password_buf + 16 + myelen, key, 16); MD5_Init(&MD); MD5_Update(&MD, password_buf, 32 + myelen); MD5_Final(key, &MD); return; } void password_to_key_sha(u_char *password, /* IN */ u_int passwordlen, /* IN */ u_char *engineID, /* IN - pointer to snmpEngineID */ u_int engineLength, /* IN - length of snmpEngineID */ u_char *key) { /* OUT - pointer to caller 20-octet buffer */ SHA_CTX SH; u_char *cp, password_buf[80], *mypass = password, bpass[17]; u_long password_index = 0, count = 0, i, mylen = passwordlen, myelen = engineLength; if (mylen < 8) { memset(bpass, 0, sizeof(bpass)); strcpy(bpass, password); while (mylen < 8) { strcat(bpass, password); mylen += passwordlen; } mypass = bpass; } if (myelen > 32) myelen = 32; SHA1_Init(&SH); /* initialize SHA */ /* Use while loop until we've done 1 Megabyte */ while (count < 1048576) { cp = password_buf; for (i = 0; i < 64; i++) { /* Take the next octet of the password, wrapping */ /* to the beginning of the password as necessary. */ *cp++ = mypass[password_index++ % mylen]; } SHA1_Update(&SH, password_buf, 64); count += 64; } SHA1_Final(key, &SH); /* tell SHA we're done */ /* Now localize the key with the engineID and pass */ /* through SHA to produce final key */ /* May want to ensure that engineLength <= 32, */ /* otherwise need to use a buffer larger than 72 */ memcpy(password_buf, key, 20); memcpy(password_buf + 20, engineID, myelen); memcpy(password_buf + 20 + myelen, key, 20); SHA1_Init(&SH); SHA1_Update(&SH, password_buf, 40 + myelen); SHA1_Final(key, &SH); return; } #endif int32_t start_snmp(int32_t s, char *ip, int32_t port, unsigned char options, char *miscptr, FILE *fp) { char *empty = "\"\"", *ptr, *login, *pass, buffer[1024], buf[1024], hash[64], key[256] = "", salt[8] = ""; int32_t i, j, k, size, off = 0, off2 = 0; unsigned char initVect[8], privacy_params[8]; int32_t engine_boots = 0; #ifdef LIBOPENSSL DES_key_schedule symcbc; #endif if (strlen(login = hydra_get_next_login()) == 0) login = empty; if (strlen(pass = hydra_get_next_password()) == 0) pass = empty; if (snmpversion < 3) { /* do we attack snmp v1 or v2c? */ if (snmpversion == 2) { snmpv1_a.ver[2] = '\x01'; } if (snmpread) { size = sizeof(snmpv1_r); } else { size = sizeof(snmpv1_w); } snmpv1_a.comlen = (char)strlen(pass); snmpv1_a.len = snmpv1_a.comlen + size + sizeof(snmpv1_a) - 3; i = sizeof(snmpv1_a); memcpy(buffer, &snmpv1_a, i); strcpy(buffer + i, pass); i += strlen(pass); if (snmpread) { memcpy(buffer + i, &snmpv1_r, size); i += sizeof(snmpv1_r); } else { memcpy(buffer + i, &snmpv1_w, size); i += sizeof(snmpv1_w); } } else { // snmpv3 if (enctype == 0) { memcpy(buffer, snmpv3_get1, sizeof(snmpv3_get1)); i = sizeof(snmpv3_get1); } else { memcpy(buffer + 1, snmpv3_get1, sizeof(snmpv3_get1)); buffer[0] = buffer[1]; memset(buffer + 1, 0x81, 2); i = sizeof(snmpv3_get1) + 1; off2 = 1; } memcpy(buffer + i, snmpv3info, snmpv3infolen); if (hashtype > 0) { off = 12; #ifdef LIBOPENSSL if (hashtype == 1) { password_to_key_md5(pass, strlen(pass), snmpv3info + 6, snmpv3info[5], key); } else { password_to_key_sha(pass, strlen(pass), snmpv3info + 6, snmpv3info[5], key); } #endif if (enctype > 0) { off += 8; buffer[20 + off2] = 7; } } else { ptr = login; login = pass; pass = ptr; buffer[20] = 4; } buffer[i + 1] = 4 + snmpv3infolen + off + strlen(login); buffer[i + 3] = 2 + snmpv3infolen + off + strlen(login); if (enctype == 0) buffer[1] = 48 + sizeof(snmpv3_get1) + buffer[i + 1]; i += snmpv3infolen; // printf("2 + %d + %d + %d = 0x%02x\n", off, snmpv3infolen, strlen(login), // buffer[1]); buffer[i] = 0x04; buffer[i + 1] = strlen(login); memcpy(buffer + i + 2, login, strlen(login)); i += 2 + strlen(login); buffer[i] = 0x04; if (hashtype > 0) { buffer[i + 1] = 12; memset(buffer + i + 2, 0, 12); off = i + 2; i += 2 + 12; } else { buffer[i + 1] = 0; i += 2; } buffer[i] = 0x04; if (enctype == 0) { buffer[i + 1] = 0x00; i += 2; } else { buffer[i + 1] = 8; memcpy(buffer + i + 2, salt, 8); // uninitialized and we don't care i += 10; } if (enctype == 0) { memcpy(buffer + i, snmpv3_get2, sizeof(snmpv3_get2)); i += sizeof(snmpv3_get2); } else { buffer[i] = 4; buffer[i + 1] = 0x30; #ifdef LIBOPENSSL /* //PrivDES::encrypt(const unsigned char *key, // const uint32_t key_len, // const unsigned char *buffer, // const uint32_t buffer_len, // unsigned char *out_buffer, // uint32_t *out_buffer_len, // unsigned char *privacy_params, // uint32_t *privacy_params_len, // const unsigned long engine_boots, // const unsigned long engine_time) // last 8 bytes of key are used as base for initialization vector */ k = 0; memcpy((char *)initVect, key + 8, 8); // put salt in privacy_params j = htonl(engine_boots); memcpy(privacy_params, (char *)&j, 4); memcpy(privacy_params + 4, salt, 4); // ??? correct? // xor initVect with salt for (i = 0; i < 8; i++) initVect[i] ^= privacy_params[i]; DES_key_sched((const_DES_cblock *)key, &symcbc); DES_ncbc_encrypt(snmpv3_get2 + 2, buf, sizeof(snmpv3_get2) - 2, &symcbc, (const_DES_cblock *)(initVect), DES_ENCRYPT); #endif /* for (i = 0; i <= sizeof(snmpv3_get2) - 8; i += 8) { DES_ncbc_encrypt(snmpv3_get2 + i, buf + i, 8, (const_DES_cblock*)(initVect), DES_ENCRYPT); } // last part of buffer if (buffer_len % 8) { unsigned char tmp_buf[8]; unsigned char *tmp_buf_ptr = tmp_buf; int32_t start = buffer_len - (buffer_len % 8); memset(tmp_buf, 0, 8); for (uint32_t l = start; l < buffer_len; l++) *tmp_buf_ptr++ = buffer[l]; DES_ncbc_encrypt(tmp_buf, buf + start, 1, &symcbc, (const_DES_cblock*)(initVect), DES_ENCRYPT); *out_buffer_len = buffer_len + 8 - (buffer_len % 8); } else *out_buffer_len = buffer_len; */ // dummy k = ((sizeof(snmpv3_get2) - 2) / 8); if ((sizeof(snmpv3_get2) - 2) % 8 != 0) k++; memcpy(buffer + i + 2, buf, k * 8); i += k * 8 + 2; } i++; // just to conform with the snmpv1/2 code #ifdef LIBOPENSSL if (hashtype == 1) { HMAC((EVP_MD *)EVP_md5(), key, 16, buffer, i - 1, hash, NULL); memcpy(buffer + off, hash, 12); } else if (hashtype == 2) { HMAC((EVP_MD *)EVP_sha1(), key, 20, buffer, i - 1, hash, NULL); memcpy(buffer + off, hash, 12); } #endif } j = 0; do { if (hydra_send(s, buffer, i - 1, 0) < 0) return 3; j++; } while (hydra_data_ready_timed(s, 1, 0) <= 0 && j < 3); if (hydra_data_ready_timed(s, 5, 0) > 0) { i = hydra_recv(s, (char *)buf, sizeof(buf)); if (snmpversion < 3) { /* stolen from ADMsnmp... :P */ for (j = 0; j < i; j++) { if (buf[j] == '\x04') { /* community name */ for (j = j + buf[j + 1]; j + 2 < i; j++) { if (buf[j] == '\xa2') { /* PDU Response */ for (; j + 2 < i; j++) { if (buf[j] == '\x02') { /* ID */ for (j = j + (buf[j + 1]); j + 2 < i; j++) { if (buf[j] == '\x02') { if (buf[j + 1] == '\x01') { /* good ! */ hydra_report_found_host(port, ip, "snmp", fp); hydra_completed_pair_found(); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 3; return 1; } } } } } } } } } } else { // snmpv3 reply off = 0; if (buf[0] == 0x30) { if (buf[4] == 0x03 && buf[5] == 0x30) off = 4; if (buf[5] == 0x03 && buf[6] == 0x30) off = 6; if (buf[6] == 0x03 && buf[7] == 0x30) off = 6; } if (off == 0) return 3; if (debug) printf("[DEBUG] buf[%d + 15] %d\n", off, buf[off + 15]); k = 3 + off + buf[2 + off]; if ((j = hydra_memsearch(buf + k, buf[k + 3], snmpv3_nouser, sizeof(snmpv3_nouser))) < 0) if ((j = hydra_memsearch(buf + k, buf[k + 3], login, strlen(login))) >= 0) { if (snmpv3info[j - 2] == 0x04) j -= 2; else j = -1; } if (j >= 0) { i = buf[k + 3] + 4; if (i > sizeof(snmpv3info)) i = sizeof(snmpv3info); memcpy(snmpv3info, buf + k, i); snmpv3infolen = j; if (debug) hydra_dump_asciihex(snmpv3info, snmpv3infolen); } if ((buf[off + 15] & 1) == 1) { if (hashtype == 0) hydra_report_found_host(port, ip, "snmp3", fp); else hydra_report_found_host(port, ip, "snmp", fp); hydra_completed_pair_found(); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 3; return 1; } else if ((buf[off + 15] & 5) == 4 && hydra_memsearch(buf, i, snmpv3_nouser, sizeof(snmpv3_nouser)) >= 0) { // user does not exist if (verbose) printf("[INFO] user %s does not exist, skipping\n", login); hydra_completed_pair_skip(); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 3; return 1; } } } hydra_completed_pair(); if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) return 3; return 1; } void service_snmp(char *ip, int32_t sp, unsigned char options, char *miscptr, FILE *fp, int32_t port, char *hostname) { int32_t run = 1, next_run = 1, sock = -1, i = 0; int32_t myport = PORT_SNMP; char *lptr; if (miscptr != NULL) { lptr = strtok(miscptr, ":"); while (lptr != NULL) { if (strcasecmp(lptr, "1") == 0) snmpversion = 1; else if (strcasecmp(lptr, "2") == 0) snmpversion = 2; else if (strcasecmp(lptr, "3") == 0) snmpversion = 3; else if (strcasecmp(lptr, "PLAIN") == 0) hashtype = 0; else if (strcasecmp(lptr, "MD5") == 0) hashtype = 1; else if (strncasecmp(lptr, "R", 1) == 0) snmpread = 1; else if (strncasecmp(lptr, "W", 1) == 0) snmpread = 0; else if (strncasecmp(lptr, "SHA", 3) == 0) hashtype = 2; else if (strcasecmp(lptr, "DES") == 0) enctype = 1; else if (strcasecmp(lptr, "AES") == 0) enctype = 2; else { fprintf(stderr, "[ERROR] unknown optional parameter: %s\n", lptr); hydra_child_exit(2); } lptr = strtok(NULL, ":"); } } if (hashtype == 0) enctype = 0; if (port != 0) myport = port; sock = hydra_connect_udp(ip, myport); port = myport; if (debug) printf("[DEBUG] snmpv%d, isread %d, hashtype %d, enctype %d\n", snmpversion, snmpread, hashtype, enctype); hydra_register_socket(sp); if (sock < 0) { hydra_report(stderr, "[ERROR] Child with pid %d terminating, no socket available\n", (int32_t)getpid()); hydra_child_exit(1); } if (snmpversion == 3) { next_run = 0; while (snmpv3info == NULL && next_run < 3) { hydra_send(sock, snmpv3_init, sizeof(snmpv3_init), 0); if (hydra_data_ready_timed(sock, 5, 0) > 0) { if ((i = hydra_recv(sock, (char *)snmpv3buf, sizeof(snmpv3buf))) > 30) { if (snmpv3buf[4] == 3 && snmpv3buf[5] == 0x30) { snmpv3info = snmpv3buf + 7 + snmpv3buf[6]; snmpv3infolen = snmpv3info[3] + 4; if (snmpv3info + snmpv3infolen <= snmpv3buf + sizeof(snmpv3buf)) { while (snmpv3info[snmpv3infolen - 2] == 4 && snmpv3info[snmpv3infolen - 1] == 0 && snmpv3infolen > 1) snmpv3infolen -= 2; if (debug) hydra_dump_asciihex(snmpv3info, snmpv3infolen); if (snmpv3info[10] == 3 && child_head_no == 0) printf("[INFO] Remote device MAC address is " "%02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned char)snmpv3info[12], (unsigned char)snmpv3info[13], (unsigned char)snmpv3info[14], (unsigned char)snmpv3info[15], (unsigned char)snmpv3info[16], (unsigned char)snmpv3info[12]); } } } } next_run++; } if (snmpv3info == NULL || i < snmpv3info + snmpv3infolen - snmpv3buf) { hydra_report(stderr, "No valid reply from snmp server, exiting!\n"); hydra_child_exit(2); } } if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) run = 3; while (1) { switch (run) { case 1: /* connect and service init function */ next_run = start_snmp(sock, ip, port, options, miscptr, fp); break; case 3: /* clean exit */ if (sock >= 0) sock = hydra_disconnect(sock); hydra_child_exit(2); return; default: hydra_report(stderr, "[ERROR] Caught unknown return code, exiting!\n"); hydra_child_exit(2); } run = next_run; } } int32_t service_snmp_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_snmp(const char *service) { printf("Module snmp is optionally taking the following parameters:\n" " READ perform read requests (default)\n" " WRITE perform write requests\n" " 1 use SNMP version 1 (default)\n" " 2 use SNMP version 2\n" " 3 use SNMP version 3\n" " Note that SNMP version 3 usually uses both login and " "passwords!\n" " SNMP version 3 has the following optional sub parameters:\n" " MD5 use MD5 authentication (default)\n" " SHA use SHA authentication\n" " DES use DES encryption\n" " AES use AES encryption\n" " if no -p/-P parameter is given, SNMPv3 noauth is performed, " "which\n" " only requires a password (or username) not both.\n" "To combine the options, use colons (\":\"), e.g.:\n" " hydra -L user.txt -P pass.txt -m 3:SHA:AES:READ target.com snmp\n" " hydra -P pass.txt -m 2 target.com snmp\n"); }