Yubico / yubico-pam

Yubico Pluggable Authentication Module (PAM)
https://developers.yubico.com/yubico-pam
BSD 2-Clause "Simplified" License
687 stars 114 forks source link

[BUG] Locked screen fails unlock with YubiKey on Kubuntu (KDE-based Ubuntu) #113

Open conz27 opened 7 years ago

conz27 commented 7 years ago

The issue seems similar to #92 and #99 that were reported earlier, but for the KDE-based Linux distros.

The process that runs the lock-screen: kscreenlocker_greet runs as the session user as opposed to root. So when the CR occurs, it receives a "Permission Denied" when it tries to open /var/yubcio/user-123456 because chown is set as follows: root:user.

As soon as I changed the permission on /var/yubico/user-123456 to -rw-r-----, the lock screen worked just fine.

As far as I understand, the challenge response stored in /var/yubico/user-123456 is sensitive, hence should only be accessible by root?

Joeviocoe commented 7 years ago

Is there a workaround for this? Or am I expected to recompile with this commit 155b485?

Kubuntu has this issue when using the shared /var/yubico directory per the instructions. Linux Mint seems unaffected using the same configuration.

klali commented 7 years ago

@Joeviocoe this issue is not a duplicate of #92 and #99, please avoid posting the same comment to multiple issues.

@conz27 I would say that expected usage of ykpamcfg is to run it as the user if you expect things running in the users context to be able to use the configuration. Maybe ykpamcfg should grow something to support running it as root but setting permissions properly for a user.

conz27 commented 7 years ago

@klali: unfortunately, I can't run ykpamcfg as the user because my home directory is in encrypted. I have to use the /var/yubico shared directory because of that.

I think the real question is:

When using ykpamcfg in shared-mode (i.e. /var/yubico), if ykpamcfg creates the /var/yubico/user-123456 file with root:user ownership, should the file permissions be set to 0640 as opposed to 0600. I mean whats the point of setting the file ownership to root:user if you're going to set the permissions to 0600? Might as well have set the ownership to root:root in that case.

klali commented 7 years ago

Yes, this is a tricky situation. My thought would be to run it as the user with -p to write the file, but this gets thorny when you have multiple users. Currently ykpamcfg known nothing about what user it writes the file for, it only sets the umask to 077, leaving group and user up to the environment it runs in.

Maybe it should be possible to give it a username and have the file chowned to that user after it is written? A different alternative would be to set umask 007 instead (write for user and group) and hope that group is going to be correct, but in that case we might want to take the group in as a parameter as well..

crosser commented 7 years ago

Using group permission does not look right to me. Not all setups have a personal group for each user. I would say, the file ought to be owned by the user. In my own implementation of challenge-response PAM module, I rely on the file being created owned by the user initially, and when I create a new replacement file, I carry over the ownership from the old file to the new like this.

conz27 commented 7 years ago

If the file is chowned by the user, it will work with both root and user-based processes like @klali and @crosser suggested - without requiring group knowledge or permissions. However, if user accounts are compromised by attackers then they will be able to read and/or change the CR file to whatever they like with only user-level privileges - which is the part that feels wrong to me. You'd think sudo privileges should be required to make modifications to an existing CR file.

I'm guessing that with the CR file being static, the response from the YubiKey is the same every time and HMAC-SHA1 does not use non-static values or counters. This means that if an attacker is able to see the CR file, they can perform a MITM replay attack with the response - meaning the YubiKey requirement is short-circuited.

Edit: I'm guessing the CR file is static ... is it actually?

Unless there is some kind of authentication algorithm TLS-like handshake using Diffie-Hellman between yubico-pam and the YubiKey to establish a mutually-authenticated channel ... HMAC-SHA1 by itself is vulnerable.

The privilege-level of the attacked user determines the blast-radius of the compromise - (i.e. if I have sudo privileges, the attacker gains sudo privileges provided they know my password and the CR).

klali commented 7 years ago

So the file is not static, for the process to work properly it has to be writable by the pam module. The reason for this is that two responses are calculated, one being for authentication of this session and one for authentication of the next one to not have a static challenge & response.

I've pushed a branch (https://github.com/Yubico/yubico-pam/commits/ykpamcfg_user) adding a username switch to ykpamcfg (this should also help with having to rename the file when using a common path).

jeremyn commented 7 years ago

I'm also getting a permission error on the challenge file under /var/yubico when trying to unlock the screen, and this is with Ubuntu 16.10 with Unity, so this is not just a KDE problem.

ghost commented 7 years ago

Workaround for KDE plasma 5:

Locate kcheckpass binary file on your system. It's installed by kscreenlocker package. It could be /usr/lib/kcheckpass or /usr/lib/x86_64-linux-gnu/libexec/kcheckpass and so on.

Next, give it SUID permissions: chmod u+s /Path/to/kcheckpass

Now it should be able to read&write to any yubico directory. In this case SUID should be safe as it's supported by upstream in case PAM isn't avalaible.

Unfortunately SUID bit will bo gone in case kcheckpass file is overwritten i.e during update kscreenlocker package.

To undo above changes: chmod u-s /Path/to/kcheckpass

OOPMan commented 7 years ago

@fancytenseletters Thanks for the work-around! I was worried I'd have to sneak around using loginctl until this got fixed :-)

potiuk commented 7 years ago

Any workaround/suggestion for Ubuntu 16.04 with Gnome ? I have exactly the same problem :(

potiuk commented 7 years ago

Just looked a bit more closely - looks like in Ubuntu + Gnome it's the gnome-screensaver-dialog that calls the pam authentication method. Unfortunately setting the SUID bit does not help, and I checked the source code to see why - it seems that similarly to kcheckpass SUID is acceptable (for BSD style OS) but it's written in quite safe and sensible way - it drops the extra priviledges as one of the first things it does and switches back to the original user :( so the actual pam calls are executed as normal user .

For now the "workaround" is to use "Switch user" button rather than provide password when the screensaver dialog is displayed. Then you are thrown out to Lightdm (I use it instead of gdm). Lightdm of course runs as root, and have access to the file so it can login as usual. It kind of works, but is not the nicest way.

Any ideas how this can be solved are welcome!

OOPMan commented 7 years ago

@potiuk Have you tried pinging the Gnome guys about this? Otherwise, you can use loginctl in a text-mode session to unlock the DM session

potiuk commented 7 years ago

I think it's not the question of gnome guys, there is nothing wrong with gnome about it (it's the same for KDE, Unity and likely others). How I understand it - it is more of an architectural problem with the yubico pam module security itself.

Firstly - it's perfectly OK for pam authentication to be run as both user, and root (on behalf of another user). Both cases are valid, and general screensaver consensus is that screensaver does not require root access and runs as the logged in user. Which is good and safe. It is actually a potential security hole if screensaver is run with setuid (there are multiple references in source code of gnome-screensaver about not opening that hole).

Unfortunately yubico's pam module's architecture with challenge-repsonse (for safety reason) requires storing non-static challenge/response information in a place which is not accessible to all applications running as the logged in user. It's again a sensible solution, otherwise any application should be able to read the upcoming challenge and response and do MITM attack as described by @conz27. For now the solution is that pam authentication must be run as root.

To be honest - it's not a blocker as there are workarounds that work. Not nicest and user friendly, but they do work. For example using "switch user" in gnome-screensaver and logging in again as the same user is functionally working OK (it kills the screensaver and switches to the login screen which is run as root). The only drawback is that you won't be able to type in the password directly in screensaver. That's a User Experience issue rather than functional.

We simply need a solution where only pam-library-code can store and read stored challenge/response, regardless from the user it runs as. Seems simple but not really.

I looked at other options that might be better than linux discretionary access rights. Using AppArmor is not good because it restricts sensitive apps rather than protects files. SELinux would be better but there are many distros (including Ubuntu) which do not have it by default and yubico would have to define whitelist of apps that are allowed to read the file. Maybe another solution would be that challenge/response data could be kept encrypted by the pam module (and user accessible). But then probably there is no good way to generate and keep the encryption keys in the way that only pam library could access. I cannot think of better solution, unfortunately :(

ghost commented 7 years ago

You can try to set capabilities on gnome-screensaver like CAP_DAC_OVERRIDE, see https://www.insecure.ws/linux/getcap_setcap.html however there is possibility that it drops them too.

crosser commented 7 years ago

Unfortunately yubico's pam module's architecture with challenge-repsonse (for safety reason) requires storing non-static challenge/response information in a place which is not accessible to all applications running as the logged in user. It's again a sensible solution, otherwise any application should be able to read the upcoming challenge and response and do MITM attack as described by @conz27. For now the solution is that pam authentication must be run as root.

I would like to challenge the validity of this reasoning. In my view, if an adversary could read the pam state file with the userid of the attacked user, they are already in, and can read (and write) anything that belongs to the user. Preventing their subsequent login does not noticeably improve the situation, the user is already compromised.

For the above reason, I maintain that the right solution is to have the state file owned by the user. This is the approach that I take in my PAM module.

OOPMan commented 7 years ago

@potiuk I think you're missing something which is that the KDE screenlocker does not run with SUID, it's the kcheckpass utility which does and is explicitly stated to be safe for this usage. Perhaps if Gnome broke out their screenlocker from the process of password verification they could achieve something similar?

Your exposition didn't really convince me. While you state that PAM auth can be run as user or root there seem to be multiple use-cases where it is restricted to root (only Yubico, Shadow Passwords file, probably other potential ones as well) for genuinely good reasons.

It thus seems to me that you should talk to the Gnome guys about this because workaround suggested by @fancytenseletters may very well be considered the right way to approach this?

potiuk commented 7 years ago

@crosser - it'a much worse if you also use C/R for things like sudo access. In my case - I was using initially C/R for both - logging-in and sudo access. Remember we are talking about also write access to the file (write access is needed because the stored challenge/response is not static - it changes every time you exercise challenge/response so that next time it will be different challenge and different response). So you could write your own challenge/response to the file and login as sudo using your own key for example (thus leading to priviledge escalation).

crosser commented 7 years ago

@potiuk I agree that sudo changes the perspective. My answer is not to use (only) the C/R module for sudo.

potiuk commented 7 years ago

@OOPMan true. It does look like KDE approach is the only "good" I can imagine in fact. I looked at kcheckpass implementation and they do mention that it is as simple as only possible in order to have less worries about setuid. Also it would play very well with AppArmour - because you could specifically restrict kcheckpass to only access what's needed. If only convincing gnome team to do something like that was easy. But it's a good idea to contact them. I will try to do it now :).

potiuk commented 7 years ago

@OOPMan issue raised: https://bugzilla.gnome.org/show_bug.cgi?id=782134

EdRoxter commented 6 years ago

In addition to @fancytenseletters 's excellent workaround (https://github.com/Yubico/yubico-pam/issues/113#issuecomment-287210543), I want to add that I created a little systemd script which would just blindly run at boot time to set the +s bit on kcheckpass.

  1. Create (as root) a file /usr/local/bin/chmodkcheckpass.sh with the following content:
    
    #!/bin/bash

/bin/chmod u+s /usr/lib/x86_64-linux-gnu/libexec/kcheckpass exit 0

You may want to check if the path is correct.
2. Make it executable: `sudo chmod u+x /usr/local/bin/chmodkcheckpass.sh`
3. Create (as root) a minimal systemd service file, for example `/etc/systemd/system/chmodkcheckpass.service` with the following content:

[Unit] Description=Chmod kcheckpass so unlocking works with yubikey

[Service] ExecStart=/usr/local/bin/chmodkcheckpass.sh

[Install] WantedBy=default.target

4. Check that the +s bit is _not_ set on kcheckpass, then run `sudo systemctl start chmodkcheckpass.service`
5. Check if the +s bit is set now, additionally check `tail /var/log/syslog` if the service file ran without errors (i.e. there should be only one line saying `Dec 20 14:18:02 edbook systemd[1]: Started Chmod kcheckpass so unlocking works with yubikey.`)
6. Set up the service for default run:

nico@edbook:~$ sudo systemctl enable chmodkcheckpass.service Created symlink /etc/systemd/system/default.target.wants/chmodkcheckpass.service → /etc/systemd/system/chmodkcheckpass.service.



So as long as there is no definite fix for this, this solution should work and also be update-proof.
SecKatie commented 6 years ago

I am using mate and ran into the same problem. Would it be proper and secure to set a capability to the dialog using setcap? I was able to work around the issue in the mate desktop by using setcap cap_dac_read_search+ep /usr/lib/mate-screensaver/mate-screensaver-dialog This allows it to have read access to all files but not write access. I am currently in testing to see if it will drop the capability. It could also possibly be automated much in the same way that @EdRoxter automated the SUID permissions.

NotSpecial commented 5 years ago

I am using cinnamon on arch and experienced the same problem. In case it helps anyone, I have resorted to the following solution: Using two different challenge files, one with root, and one with user privileges.

Concretely, I use the root-accessible file for sudo, and the user accessible file for the cinnamon screensaver.

As far as I understand, the initial state of the challenge-response state file is random, and thus it should be impossible to use determine the current root state from the user state.

In practice, this is straightforward, as is requires only an additional pam rule. If there are any glaring security holes I am overlooking with this setup, please let me know. Otherwise it might be of use for someone.

axilleas commented 5 years ago

For anyone using Arch, you can use a pacman hook:

  1. Create the directory if it doesn't exist:

    sudo mkdir /etc/pacman.d/hooks
  2. Create /etc/pacman.d/hooks/kcheckpass.hook with the following contents:

    # Set SUID for kcheckpass so unlocking works with yubikey
    # https://github.com/Yubico/yubico-pam/issues/113#issuecomment-353061344
    # https://cgit.kde.org/kscreenlocker.git/tree/kcheckpass/README
    
    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = kscreenlocker
    [Action]
    Depends = kscreenlocker
    Depends = yubico-pam
    When = PostTransaction
    Exec = /bin/chmod u+s /usr/lib/kcheckpass
kmahyyg commented 4 years ago

Thanks to @axilleas , Only his solution is working. Arch + kde5

figboy9 commented 2 years ago

After updating kscreenlocker, kcheckpass is gone and I can no longer unlock it. Does anyone have another solution?

kscreenlocker: 5.25.0-1

davidshen84 commented 2 years ago

I got hit by this issue today after upgrading my kscreenlocker to 5.25.5.

+s to the /usr/lib64/libexec/kscreenlocker_greet file is simply not allowed by the Plasma framework because it is considered a security hole.

edward-p commented 1 year ago

I think the problem is at:

https://github.com/Yubico/yubico-pam/blob/5719a2f859144948de7b67b6d706d6ed403b219f/drop_privs.c#L85-L93

Since kscreenlocker is running as normal user, setegid(pw->pw_gid) seteuid(pw->pw_uid) will always fail. But in this case, there's no need to call setegid, seteuid, and authorization should contine.

Possible fix (Not tested):

 if (getegid() != pw->pw_gid && setegid(pw->pw_gid) < 0) { 
     D (privs->debug_file, "setegid: %s", strerror(errno)); 
     goto free_out; 
 } 

 if (geteuid() != pw->pw_uid && seteuid(pw->pw_uid) < 0) { 
     D (privs->debug_file, "seteuid: %s", strerror(errno)); 
     goto free_out; 
 } 
Maryse47 commented 1 year ago

Since kscreenlocker is running as normal user

The problem is challenge file isn't accessible for normal users. You need to either make it accessible or make kscreenlocker privileged.

surmish commented 1 week ago

is there a user-friendly workaround for this?