Subject: | Net::SSH::Perl ignores host key mismatch |
Date: | Sun, 31 Jan 2010 15:18:34 +0900 |
To: | bug-Net-SSH-Perl [...] rt.cpan.org |
From: | Nobuhiro Ban <ban.nobuhiro [...] gmail.com> |
Distribution name and version: Net-SSH-Perl-1.34
Perl version: v5.10.0 built for i486-linux-gnu-thread-multi
Operating System vendor and version: Debian GNU/Linux 5.0.3 (Linux 2.6.24)
* Description
Most SSH clients check the change of the host key for security reason.
These checks protect connections against the Man-in-the-middle attacks.
But, as for Net::SSH::Perl, this check doesn't work well.
This library silently accepts the changed key and connects to the host.
* Example
Alice, connects to bob.example.org by the code like:
Show quoted text
>use Net::SSH::Perl;
>my $ssh = Net::SSH::Perl->new("bob.example.org") or die;
>...
Bob, the owner of the SSH host bob.example.org.
Mallory, an attacker.
(1) Before the change of the host key.
Show quoted text>alice% cat ~/.ssh/known_hosts2
>bob.example.org ssh-dss AAAA...(The key of Bob)
(2) Someday the host key of bob.example.org changed (e.g. cracked by the
attacker Mallory).
Net::SSH::Perl ignores this change, and silently adds a new entry.
Show quoted text>alice% cat ~/.ssh/known_hosts2
>bob.example.org ssh-dss AAAA...(The key of Bob)
>bob.example.org ssh-dss AAAA...(The key of Mallory)
If Alice tries to connect to bbb.example.org with OpenSSH client 5.1p1
(instead of Net::SSH::Perl), she will be warned:
Show quoted text>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
>Someone could be eavesdropping on you right now (man-in-the-middle attack)!
* Code analysis
In Net::SSH::Perl::check_host_key ,
Show quoted text> my $status = _check_host_in_hostfile($host, $u_hostfile, $key);
> unless (defined $status && $status == HOST_OK) {
> $status = _check_host_in_hostfile($host, $s_hostfile, $key);
> }
The first call of _check_host_in_hostfile($host, $u_hostfile, $key)
returns HOST_CHANGED, but second call of _check_host_in_hostfile($host,
$s_hostfile, $key) overwrite it by HOST_NEW.
Show quoted text> if ($status == HOST_OK) {
> $ssh->debug("Host '$host' is known and matches the host key.");
> }
> elsif ($status == HOST_NEW) {
> if ($ssh->{config}->get('interactive')) {
(snip)
Show quoted text> }
> $ssh->debug("Permanently added '$host' to the list of known hosts.");
> _add_host_to_hostfile($host, $u_hostfile, $key);
> }
> else {
> croak "Host key for '$host' has changed!";
> }
So the second case is selected, silently added the changed key to
$u_hostfile if not "interactive" setting.
* Suggested fix
In Net::SSH::Perl::check_host_key ,
my $status = _check_host_in_hostfile($host, $u_hostfile, $key);
- unless (defined $status && $status == HOST_OK) {
+ unless (defined $status && ($status == HOST_OK || $status ==
HOST_CHANGED)) {
$status = _check_host_in_hostfile($host, $s_hostfile, $key);
}
* Additional comment
I think the default behavior for HOST_NEW (silently adding a new key)
is very insecure.