Relentless Coding

A Developer’s Blog

Authentication on Cisco IOS

Let’s have a look at how Cisco IOS handles authentication and how passwords are stored in the configuration file.

Disable Cleartext Passwords in the Configuration File

Let’s I set the “front-door password” for console access that would put the user in user EXEC mode:

ISR4321# conf t
ISR4321(config)# line console 0
ISR4321(config-line)# password foobarbaz
ISR4321(config-line)# login
ISR4321(config-line)# ^Z
ISR4321# sh run | b line
line con 0
!
line aux 0
!
line vty 0 4
 password foobarbaz
 login
line vty 5 15
 password foobarbaz
 login
!

To obfuscate passwords in the configuration file:

ISR4321(config)# service password-encryption

Passwords that are normally be stored in plaintext in the config file will now be obscured by “Type 7 encryption”.1 “Encryption” sounds like a big deal, but this type of encryption is merely meant to prevent casual shoulder surfing:

line con 0
 password 7 1047021200
 login

Type 7 “encryption” is seriously broken. So consider anyone with access to the config (or backups thereof) to know the password and be able to access user EXEC mode on your Cisco devices.

If we were to exit now, we would be prompted for this front-door password:

ISR4321# exit
ISR4321 con0 is now available

Press RETURN to get started.

User Access Verification

Password: 
ISR4321>

The router does not echo the password back to the screen to prevent shoulder surfing.

Protect Privileged EXEC Mode with a Password

Set the “enable” password (to get to enable/privileged EXEC mode):

ISR4321(config)# enable secret algorithm-type scrypt secret <pwd>

At least on my IOS, fortunately, scrypt is available as a PBKDF.2

When enable secret is set, IOS will ignore the enable password. That means that if both are set, you can only gain access with the enable secret password. enable password stores the password in plaintext in the config file, or merely obfuscates it when service password-encryption is set. So remove this insecure password with no enable password.

Username + Password Authentication

You can also use username + password authentication. Logins over console and Telnet can then request a username in addition to a password. SSH always requires both a username and a password.

Create users with usernames, password and privilege levels:

ISR4321(config)# username stefan privilige 15 secret stefanpwd
ISR4321(config)# username thomas privilige 1 secret stefanpwd

You can use algorithm-type to specify the PBKDF. On my IOS, by default, it uses the (weak) MD5. Use scrypt instead.

By changing line console 0 to use login local instead of login, the login prompt will request credentials from the local list configured with username <name> secret <secret>:

ISR4321# conf t
ISR4321(config)# line console 0
ISR4321(config-line)# login local
ISR4321(config-line)# end
ISR4321# exit
User Access Verification

Username: thomas
Password:
ISR4321>

If we authenticate with the privileged user stefan instead (which was configured with privilege 15), we are taken straight to enable/privileged EXEC mode after authentication.

Secure SSH and/or Telnet with ACLs

To secure logging in over IP, ACLs are needed. After all, you can have a strong password, but if Cisco’s SSH or Telnet daemon has a vulnerability, you would still want to prevent the baddies from knocking on those exposed ports.

First, create an standard numbered ACL:

ISR4321(config)#access-list 1 permit 172.16.0.0 0.15.255.255

This permits all hosts with a source IP address in the RFC 1918 private IP subnet 172.16/12. ACLs in Cisco land always end with default deny. So this reads: allow IP packets from source 172.16/12 and drop the packets otherwise. The wildcard mask (0.15.255.255) is a mask that defines which bits of the source address will be checked against the defined ACL base address.

Say, a packet with source IP 172.16.123.123 comes in:

base  = 1010 1100 0001 0000 0000 0000 0000 0000
mask  = 0000 0000 0000 1111 1111 1111 1111 1111
check = 1010 1100 0001 0000 0111 1011 0111 1011

If we compare base with check for every bit where the mask has a 0 bit, we see that base == check. And so the ACL matches and traffic is allowed to flow. Internally, Cisco probably just logically ORs the base and mask (base | mask) and mask and check (mask | check) and compares the results.

Currently, this ACL is not assigned to a port or a vty though, so it does not do anything.

ISR4321(config)#line vty 0 15
ISR4321(config-line)#access-class 1 in

Here, we assign the standard numbered ACL with identifier 1 to all the vty lines.

The in keyword specifies the direction of the traffic flow: in this case, we anticipate a remote client initiating a connection with the Cisco device. You could also specify out. The ACL would then filter outgoing connection made from the Cisco device by the user connected over a vty line. The single IP address in the standard ACLs is then interpreted as a destination rather than a source IP address. When using extended ACLs (100-199 and 2000-2699) for access-class, you should use the any keyword for either the source or destination address, depending on whether ingress or egress is filtered.


  1. Note that if you disable password-encryption again, IOS will not decrypt the obfuscated passwords. ↩︎

  2. By default, my IOS version (16.06.04) uses the (weak) MD5-based BSD password algorithm 1. If you encounter an enable secret:

    Router#sh run | i secret
    enable secret 5 $1$mERr$jegsBINbJe1/UUQKc.NUC1
    

    You can check the password on a Linux box with openssl-passwd(1):

    openssl passwd -1 -salt mERr foobarbaz
    $1$mERr$jegsBINbJe1/UUQKc.NUC1
    
     ↩︎