Until now I generated all SSHFP resource records on the SSH destination server itself via ssh-keygen -r <name>. This is quite easy when you already have an SSH connection to a standard Linux system. But when connecting to third-party products such as routers, firewalls, whatever appliances, you don’t have this option. Hence I searched and found a way to generate SSHFP resource records remotely. Here we go:
Generating SSHFP Records
I found and forked a small bash script that scans the SSH public keys from the remote server and generates the appropriate resource records. Note that the output depends on the type of public keys the server uses, e.g., RSA, ECDSA or even Ed25519. (For an overview of different SSH key fingerprints have a look at this at-a-glance picture.) I am only using the SHA-256 hashes. You can ignore the SHA-1 output (shorter line with “1” in the 5th column). Download the script and make it executable:
1 2 |
wget https://gist.githubusercontent.com/webernetz/2ca7325555ce7f28f26daf5728386d82/raw/1c18dc43a05478771ac4693401a3c78205a4e710/grabsshfp.sh chmod u+x grabsshfp.sh |
And call it with the DNS name or IP address of the destination:
1 2 3 |
weberjoh@nb15-lx:~$ ./grabsshfp.sh pa-mgmt pa-mgmt IN SSHFP 1 1 4addde64e14a19e6a2286ca422ca0b9bd322c31d pa-mgmt IN SSHFP 1 2 ca0acaa29d0cb233b2a715be3217a91002efe87d7e28bd51314b1feef203c5a7 |
Verifying the Output!
This is really important:
Example 1: Palo Alto Networks Firewall
In the previous example, I generated the SSH fingerprints for a Palo Alto Networks firewall. Logging into their CLI I could verify both fingerprints (sha1 and sha256) for the single RSA public key:
1 2 3 4 5 6 7 8 9 10 11 |
weberjoh@pa> show ssh-fingerprints hash-type sha1 format hex SSH Fingerprints ---------------- 2048 4a:dd:de:64:e1:4a:19:e6:a2:28:6c:a4:22:ca:0b:9b:d3:22:c3:1d (RSA) weberjoh@pa> show ssh-fingerprints hash-type sha256 format hex SSH Fingerprints ---------------- 2048 ca:0a:ca:a2:9d:0c:b2:33:b2:a7:15:be:32:17:a9:10:02:ef:e8:7d:7e:28:bd:51:31:4b:1f:ee:f2:03:c5:a7 (RSA) |
Example 2: Fortinet FortiGate Firewall
Another example shows the generation of the SSHFP records for a FortiGate firewall:
1 2 3 4 5 |
weberjoh@nb15-lx:~$ ./grabsshfp.sh fg fg IN SSHFP 1 1 75ca5bfb168da9691e019abc52b6c5542bcb6fca fg IN SSHFP 1 2 936a61af4fbf2e65dd324b8d4549f6599f14b40e236874dc18ffb431bb5175b5 fg IN SSHFP 4 1 cb558c68ef65e0b307cb3bce8f1bf62859f00a7e fg IN SSHFP 4 2 3513c5a4be37ef1bab226dbb258767809e09df8b8438a311d2cc876a25b00197 |
As you can see, it offers two public keys (4th column). “1” for RSA and “4” for Ed25519 (refer to DNS SSHFP Resource Record Parameters), both hashed (5th column) with “1” for SHA-1 and “2” for SHA-256. Unfortunately, FortiGate is not really helping in displaying the required fingerprints:
1 2 3 4 5 6 7 8 |
fg # get system info admin ssh SSH v2 is enabled on port 22 SSH is enabled on the following 3 interfaces: fg-trust wan1 wan2 SSH hostkey DSA fingerprint = 3e:28:82:c1:46:59:0a:fb:45:d0:cd:9c:3a:2a:32:59 SSH hostkey RSA fingerprint = MD5:d0:c9:55:49:26:1c:55:c6:43:0a:00:40:d6:03:1b:b2 |
First, their output shows the fingerprints for RSA and DSA while SSH to the device used RSA and Ed25519. Hence, the Ed25519 fingerprint is missing.
Furthermore, it’s not trivial to compare the fingerprints from the FortiGate to the SSHFP records since the FortiGate outputs MD5 while SSHFP uses only SHA-1 and SHA-256 (and you still cannot “decrypt” a hash to its input). My workaround was to download the complete public key with nmap --script ssh-hostkey --script-args ssh_hostkey=full fg, save it to a file, show the fingerprint in MD5 ssh-keygen -l -E md5 -f fg-rsa.pub, compare it to the CLI output from FortiGate (was correct), and compare the fingerprint in SHA-256 to the SSHFP record. The latter also required transforming the base64 output from ssh-keygen to a hex output for SSHFP using this online converter. WTF. However, everything was correct and I now know as well that the RSA public from this FortiGate is correct.
Example 3: Cisco IOS Router
As a third example I generated the SSHFP records for a Cisco Router 2811 (Version 15.1(4)M12a):
1 2 3 |
weberjoh@nb15-lx:~$ ./grabsshfp.sh ccnp-r1a ccnp-r1a IN SSHFP 1 1 04bf6f524eab8c2be6294aef979e93b647c54663 ccnp-r1a IN SSHFP 1 2 d5953ce0e6de7e50ea0a10e8c1e5d48734285c1b608960e283c79533c06a6a40 |
You cannot display the fingerprints directly but you can display the complete SSH key with show ip sshĀ :
1 2 3 4 5 6 7 8 9 10 |
CCNP-LAB-R1a#show ip ssh SSH Enabled - version 2.0 Authentication timeout: 120 secs; Authentication retries: 3 Minimum expected Diffie Hellman key size : 1024 bits IOS Keys in SECSH format(ssh-rsa, base64 encoded): ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+Sujig8IGQy4LN8YJTu96sPQl1gX2VaZeTUip5sG3 W/TCgQG6MCpSwTLdieSWoGg8M/uXGRS9UPKFEIsVIxlhV7sHC8TJqkxcMjlVWBt/fYnHKqqKLraWd7yw 6+zXgVqSC66BOFusHak8NXQ3XkP/Rq9Q+5IBLTJI/GTpC2YI/U7sqliHYGCgKS7Ek2Hy048gb86pWaML f9WGyO2wggXEqYN37Lza9xXoTSwGaIAcqWREnauVnNIQdyUFrzy+qHJObothR2AJ2k44zHokYifRXwTn B5Hw69fX8NRVgSJFrBwWLtTuuCbRdvhfEGMeQ5zWS1lbbPsmAV+4uJ5bQ1/X |
I saved the key (the line that starts with ssh-rsa) into a file and used ssh-keygen again to generate the SSHFP records using this public key. Hence I was able to compare and verify the fingerprints:
1 2 3 |
weberjoh@nb15-lx:~$ ssh-keygen -r blubb -f ccnp-r1a.pub blubb IN SSHFP 1 1 04bf6f524eab8c2be6294aef979e93b647c54663 blubb IN SSHFP 1 2 d5953ce0e6de7e50ea0a10e8c1e5d48734285c1b608960e283c79533c06a6a40 |
Workaround for DSA Keys
Unfortunately, I did not succeed in scanning a DSA fingerprint with ssh-keyscan at all.
Example 4: Juniper ScreenOS Firewall
For example, when connecting to an old Juniper ScreenOS firewall only ssh-dss can be used. (OpenSSH 7.0 has disabled the support for DSA per default due to its weak security.) I tried it with ssh-keyscan but it did not output anything
1 2 |
weberjoh@nb15-lx:~$ ssh-keyscan -t dsa ssg-mgmt # ssg-mgmt:22 SSH-2.0-NetScreen |
while the Nmap script ssh-hostkey in fact was able to retrieve it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
weberjoh@nb15-lx:~$ nmap --script ssh-hostkey ssg-mgmt Starting Nmap 7.01 ( https://nmap.org ) at 2017-10-11 16:00 CEST Nmap scan report for ssg-mgmt (192.168.120.3) Host is up (0.0026s latency). rDNS record for 192.168.120.3: ssg-mgmt.webernetz.net Not shown: 998 filtered ports PORT STATE SERVICE 22/tcp open ssh | ssh-hostkey: |_ 1024 e7:5b:c9:a9:60:60:66:37:d6:90:bd:70:8f:76:e5:41 (DSA) 443/tcp open https Nmap done: 1 IP address (1 host up) scanned in 7.28 seconds |
For the sake of completeness here is the ssh-keyscan with -vvv. Maybe someone can tell me why it does not succeed? My question at Server Fault is here. I also tried to set the “KexAlgorithms +diffie-hellman-group1-sha1”, “HostKeyAlgorithms +ssh-dss” and “PubkeyAcceptedKeyTypes +ssh-dss” within the /etc/ssh/ssh_config file but this did not change anything for ssh-keyscan.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
weberjoh@nb15-lx:~$ ssh-keyscan -t dsa -vvv ssg-mgmt debug2: fd 3 setting O_NONBLOCK debug3: conalloc: oname ssg-mgmt kt 2 debug1: no match: NetScreen # ssg-mgmt:22 SSH-2.0-NetScreen debug1: Enabling compatibility mode for protocol 2.0 debug3: send packet: type 20 debug1: SSH2_MSG_KEXINIT sent debug3: receive packet: type 20 debug1: SSH2_MSG_KEXINIT received debug2: local client KEXINIT proposal debug2: KEX algorithms: curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1 debug2: host key algorithms: ssh-dss debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc,3des-cbc debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 debug2: compression ctos: none,zlib@openssh.com,zlib debug2: compression stoc: none,zlib@openssh.com,zlib debug2: languages ctos: debug2: languages stoc: debug2: first_kex_follows 0 debug2: reserved 0 debug2: peer server KEXINIT proposal debug2: KEX algorithms: diffie-hellman-group1-sha1 debug2: host key algorithms: ssh-dss debug2: ciphers ctos: 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc debug2: ciphers stoc: 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc debug2: MACs ctos: hmac-sha1 debug2: MACs stoc: hmac-sha1 debug2: compression ctos: none debug2: compression stoc: none debug2: languages ctos: debug2: languages stoc: debug2: first_kex_follows 0 debug2: reserved 0 debug1: kex: algorithm: (no match) |
As a workaround I used theĀ --script-args ssh_hostkey=full for the just mentioned Nmap script to retrieve the complete public key:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
weberjoh@nb15-lx:~$ nmap --script ssh-hostkey --script-args ssh_hostkey=full ssg-mgmt Starting Nmap 7.01 ( https://nmap.org ) at 2017-10-12 10:21 CEST Nmap scan report for ssg-mgmt (192.168.120.3) Host is up (0.0025s latency). rDNS record for 192.168.120.3: ssg-mgmt.webernetz.net Not shown: 998 filtered ports PORT STATE SERVICE 22/tcp open ssh | ssh-hostkey: |_ ssh-dss AAAAB3NzaC1kc3MAAACBAKAxiPI0dE9GwlnW0TXcL2xOX8t5PTZXas9YMFSBFYemjeN4cvomdKLZwDztY4PZMbPrVApSUlYM+sXQUKckIGanuoicaE7vY4gAvWdSkQ2MqQmRCWnorJVDg2LZU2Dfsxbb4I4g+pBOQwtQ5F1q5FXAuHW7VEh2YBOlS//GPv7ZAAAAFQCBFeZ+PAqZSyV6V49ovCIQLUL4QwAAAIBQ5h1Pb+RlnQ6VdD0RhaJnsaLfuSQYX2P37fsOkC+NQF2Sctq3nyV4plkW1b9gn4zaJMsikno+SSzgHUkJolFE3M24lXoQ71R+ExojdGtGU3ZfGc5I23dzDNuxPXhkoLf/4u0hWY62auDnhgOlXS6jiFOtCSmhP5mjaxCkwsW5swAAAIBMICC7XXLHog7K0xHTmZ3tdfR9InEe06gXJNGWHSdsT+stQHWqZAM4zL1PTFKaIliWXtTb7AgOKMsGFcm9yO1eDQvSw27HkhnldySQ/GB5ggnHc6zSuQJ5PHw69GJdCyeP60Fn8Ep2OWBUiD3q+8OFQO/9L5xkUGPZMx+qDczuqA== 443/tcp open https Nmap done: 1 IP address (1 host up) scanned in 6.64 seconds |
I then saved this pubkey (“ssh-dss AAAAB3Nza… … … DczuqA==”) into a file and used it to generate the SSHFP records:
1 2 3 |
weberjoh@nb15-lx:~$ ssh-keygen -r ssg-mgmt -f ssg-mgmt.pub ssg-mgmt IN SSHFP 2 1 5f755f8f7f2955793d8a584516803fa75eca9f50 ssg-mgmt IN SSHFP 2 2 7a2942d97dd6ac12e8fb56eea0e3916af00d89a91e5091c681f8ab905dc8c50a |
And again, do not forget to verify the public key / fingerprint with the device itself. In this example it was an old Juniper ScreenOS firewall which shows the same fingerprint (e7:5b:…) as captured with Nmap above:
1 2 3 |
ssg-> get ssh host-key DSA fingerprint: finger_print = e7:5b:c9:a9:60:60:66:37:d6:90:bd:70:8f:76:e5:41 |
Cheers! ;)
Featured image “Condor Business Class Inseat Entertainment” by Condor.com is licensed under CC BY-NC-ND 2.0.
There’s:
ssh-keyscan -D ${host}
Haha, that was easy…