google / google-authenticator-libpam

Apache License 2.0
1.8k stars 286 forks source link

GA on EL7 - potential to reveal usernames #140

Closed DPStokesNZ closed 5 years ago

DPStokesNZ commented 5 years ago

GA on EL7 (CentOS Linux release 7.6.1810 (Core) prompts valid GA users with verification even if account password is entered incorrectly. Example:

ssh test-user@some.remote.host
Password: <- incorrect password
Verification code: <- correct code
Password: <- correct password
Verification code: <- incorrect code
Password: <- correct password
Verification code: <- correct code
Last failed login: Wed Aug 28 09:23:38 NZST 2019 from x.x.x.x on ssh:notty
There were 2 failed login attempts since the last successful login.

The Verification code: prompt is only supplied for users with valid ~/.google_authenticator files, so there is the potential for brute force login attempts with random usernames to reveal valid usernames on the host.

Steps to reproduce:

  1. Install CentOS 7 minimal with all patches sudo yum -y update
  2. Install EPEL sudo yum -y install epel-release
  3. Install GA sudo yum -y install google-authenticator qrencode
  4. Modify /etc/ssh/sshd_config to allow ChallengeResponseAuthentication yes
  5. Modify /etc/pam.d/sshd to use GA, i.e.: echo "echo 'auth required pam_google_authenticator.so' >> /etc/pam.d/sshd" | sudo -s
  6. Restart SSH daemon sudo systemctl restart sshd
  7. Generate GA codes etc google-authenticator -t -f -d -r 3 -R 30 -w 3 -Q utf8
  8. Attempt to log in to host initially entering incorrect account password.

Expected behaviour:

Possible relevant packages:

Additional information:

Debug output from /var/log/secure:

Aug 27 18:04:11 localhost sshd[17006]: Postponed keyboard-interactive for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:14 localhost unix_chkpwd[17009]: password check failed for user (testuser)
Aug 27 18:04:14 localhost sshd[17008]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.200.44  user=testuser
Aug 27 18:04:14 localhost sshd(pam_google_authenticator)[17008]: debug: start of google_authenticator for "testuser"
Aug 27 18:04:14 localhost sshd(pam_google_authenticator)[17008]: debug: Secret file permissions are 0600. Allowed permissions are 0600
Aug 27 18:04:14 localhost sshd(pam_google_authenticator)[17008]: debug: "/home/testuser/.google_authenticator" read
Aug 27 18:04:14 localhost sshd(pam_google_authenticator)[17008]: debug: shared secret in "/home/testuser/.google_authenticator" processed
Aug 27 18:04:14 localhost sshd(pam_google_authenticator)[17008]: debug: google_authenticator for host "192.168.200.44"
Aug 27 18:04:14 localhost sshd[17006]: Postponed keyboard-interactive/pam for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:18 localhost sshd(pam_google_authenticator)[17008]: debug: scratch code 44449171 used and removed from "/home/testuser/.google_authenticator"
Aug 27 18:04:18 localhost sshd(pam_google_authenticator)[17008]: Accepted google_authenticator for testuser
Aug 27 18:04:18 localhost sshd(pam_google_authenticator)[17008]: debug: "/home/testuser/.google_authenticator" written
Aug 27 18:04:18 localhost sshd(pam_google_authenticator)[17008]: debug: end of google_authenticator for "testuser". Result: Success
Aug 27 18:04:20 localhost sshd[17006]: error: PAM: Authentication failure for testuser from 192.168.200.44
Aug 27 18:04:20 localhost sshd[17006]: Postponed keyboard-interactive for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:24 localhost sshd(pam_google_authenticator)[17010]: debug: start of google_authenticator for "testuser"
Aug 27 18:04:24 localhost sshd(pam_google_authenticator)[17010]: debug: Secret file permissions are 0400. Allowed permissions are 0600
Aug 27 18:04:24 localhost sshd(pam_google_authenticator)[17010]: debug: "/home/testuser/.google_authenticator" read
Aug 27 18:04:24 localhost sshd(pam_google_authenticator)[17010]: debug: shared secret in "/home/testuser/.google_authenticator" processed
Aug 27 18:04:24 localhost sshd(pam_google_authenticator)[17010]: debug: google_authenticator for host "192.168.200.44"
Aug 27 18:04:24 localhost sshd[17006]: Postponed keyboard-interactive/pam for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:26 localhost sshd(pam_google_authenticator)[17010]: Invalid verification code for testuser
Aug 27 18:04:26 localhost sshd(pam_google_authenticator)[17010]: debug: "/home/testuser/.google_authenticator" written
Aug 27 18:04:26 localhost sshd(pam_google_authenticator)[17010]: debug: end of google_authenticator for "testuser". Result: Authentication failure
Aug 27 18:04:28 localhost sshd[17006]: error: PAM: Authentication failure for testuser from 192.168.200.44
Aug 27 18:04:28 localhost sshd[17006]: Postponed keyboard-interactive for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:31 localhost sshd(pam_google_authenticator)[17012]: debug: start of google_authenticator for "testuser"
Aug 27 18:04:31 localhost sshd(pam_google_authenticator)[17012]: debug: Secret file permissions are 0400. Allowed permissions are 0600
Aug 27 18:04:31 localhost sshd(pam_google_authenticator)[17012]: debug: "/home/testuser/.google_authenticator" read
Aug 27 18:04:31 localhost sshd(pam_google_authenticator)[17012]: debug: shared secret in "/home/testuser/.google_authenticator" processed
Aug 27 18:04:31 localhost sshd(pam_google_authenticator)[17012]: debug: google_authenticator for host "192.168.200.44"
Aug 27 18:04:31 localhost sshd[17006]: Postponed keyboard-interactive/pam for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:35 localhost sshd(pam_google_authenticator)[17012]: debug: scratch code 92950412 used and removed from "/home/testuser/.google_authenticator"
Aug 27 18:04:35 localhost sshd(pam_google_authenticator)[17012]: Accepted google_authenticator for testuser
Aug 27 18:04:35 localhost sshd(pam_google_authenticator)[17012]: debug: "/home/testuser/.google_authenticator" written
Aug 27 18:04:35 localhost sshd(pam_google_authenticator)[17012]: debug: end of google_authenticator for "testuser". Result: Success
Aug 27 18:04:35 localhost sshd[17006]: Postponed keyboard-interactive/pam for testuser from 192.168.200.44 port 42540 ssh2 [preauth]
Aug 27 18:04:35 localhost sshd[17006]: Accepted keyboard-interactive/pam for testuser from 192.168.200.44 port 42540 ssh2
Aug 27 18:04:35 localhost sshd[17006]: pam_unix(sshd:session): session opened for user testuser by (uid=0)

NB: the default permissions for ~/.google_authenticator are 0400 upon creation, but having them as either 0400 or 0600 doesn't not change the behaviour.

Finally, I was unable to reproduce the issue with a Ubuntu 18.04 LTS host I have nor could an acquaintance produce the issue on a Debian host, so it appears to be specific to EL7.

Happy to provide a minimal EL7 host for testing if required.

Regards, Duncan.

ThomasHabets commented 5 years ago

Working as intended.

1) It's a trade-off. With code and password both prompted the attacker doesn't know if they got the password right. If you only ask for code when password is right, you are enabling finding the password, and then brute-forcing the OTP over a long time.

2) If you still want code to only be asked when password is correct then use requisite instead of required in your pam config:

required
           failure of such a PAM will ultimately lead to the PAM-API returning
           failure but only after the remaining stacked modules (for this
           service and type) have been invoked.
requisite
           like required, however, in the case that such a module returns a
           failure, control is directly returned to the application or to the
           superior PAM stack. The return value is that associated with the
           first required or requisite module to fail. Note, this flag can be
           used to protect against the possibility of a user getting the
           opportunity to enter a password over an unsafe medium. It is
           conceivable that such behavior might inform an attacker of valid
           accounts on a system. This possibility should be weighed against
           the not insignificant concerns of exposing a sensitive password in
           a hostile environment.
DPStokesNZ commented 5 years ago

OK, thanks. Was just curious why it behaved differently on other OS.

ThomasHabets commented 5 years ago

That's strange. It shouldn't behave differently. If it does that sounds like there's something wrong with PAM or the PAM configuration on those hosts. I pasted from the manpage of pam.d.

DPStokesNZ commented 5 years ago

Some variation in PAM between the OSes then - unlikely that two different hosts prepared by two different people would have the same configuration issue. I'd prefer to see the Debian/Ubuntu behaviour personally.