sudo-rs
sudo-rs copied to clipboard
Add support for `-A` (askpass) commandline switch
hi,
Cockpit uses sudo to gain root privileges for users performing actions via the web interface. We definitely need askpass support: we forward the prompt to the user, asking for the password, and passing it back. We can't do that with a pseudoterminal forwarded to the user because we also support caching the login password and using that.
See https://github.com/cockpit-project/cockpit/issues/22305 for the original report on our side.
Thanks!
Originally posted by @allisonkarlitskaya in #129
One initial question to help us in our discussion on this: since you are prepared to cache the password yourself, would an alternative approach using sudo --reset-timestamp --non-interactive --stdin be an alternative solution? E.g. providing the password to the standard input of sudo?
Does this mean that we'd use sudo --reset-timestamp followed by a normal sudo invocation, or does it mean that we'd run the command with --stdin?
If the first one: what if the admin has disabled credential caching? And how do we get the prompt? Is it printed to stdout? How do we know when the prompt is done? And what if there is more than one prompt (as is the case with 2FA, for example)?
If the second one: We definitely need stdin for our own purposes so that wouldn't be a good solution for us.
We're going to take this feature in consideration (e.g. first identify the difficulty of implementing this). The general idea seems pretty straightforward: spawn a process with ordinary user rights (and being sudo, we already have the code for that) and hook its standard output into our PAM process.
Hey, just wanted to chime in and say that other projects require the askpass functionality as well to work with sudo (I for example maintain https://github.com/xpipe-io/xpipe). Without the askpass functionality, it becomes very difficult to use sudo in an automated way.
Normal stdin with --stdin is quite limited as the calling application needs to make sure to supply the secret to the respective stdin. With an askpass process, the application just needs to print the secret to stdout, which is far easier to accomplish.
This was recently mentioned on the Ubuntu Discourse as something that would affect the Cockpit package on Ubuntu, too: https://discourse.ubuntu.com/t/adopting-sudo-rs-by-default-in-ubuntu-25-10/60583/27?u=jnsgruk
Here is another application needing sudo -A: https://github.com/elfmz/far2l/issues/2903
I think one thing to keep in mind is that implementing it could expose a user to password stealing through a supply chain attack. The specific attack I can think of is an attacker dropping:
export SUDO_ASKPASS=/tmp/password-stealer
alias sudo='sudo -A'
into a user's bashrc or similar through a malicious npm/pip install hook (or other compromised developer tooling). From the point this is added to the rc file, any invocation of sudo will transmit the user's password to the attacker.
I would oppose implementing this feature into sudo-rs without any additional safeguards, given its explicit goal towards removing less-used, security-vulnerable use cases. If we do implement this, at the very least, there should be some restrictions on where the program/binary comes from (maybe only from /usr/bin or only root-writable directories?).
Based on a few tests on 1.9.17p2, I don't think ogsudo has any restrictions on where the binary comes from, probably for legacy reasons? I wonder if we can ask the maintainer (cc @millert ) to also implement restrictions, given the prevalence of supply-chain attacks nowadays.
Thanks for this really insightful comment.
I do think we were convinced that the functionality, in the cases where it is needed, it is really really needed. E.g. providing a password on stdin if the program that sudo runs also processes stdin also obviously has some serious risks of password leakage.
A solution would be to take a cue from how editors are approved for visudo using the editors setting.
That would suggest to me:
- Introduce a
Defaults secure_askpass = ....setting that has a list of approved askpass programs/directories/Cmnd_Alias. UsingDefaults !secure_askpasswould give the current behaviour (and also clearly evokes the fact that a security feature is being turned off). A sane default for this can be given as well so sudo-rs would be 'secure out of the box'.
If a program wants to add a custom askpass program, they can surely also go through the minor installation step of dropping a file containing Defaults secure_askpass += their_program in /etc/sudoers.d, which is typically @includedir'd.
I'm not entirely convinced. If an attacker is able to control the user's environment, they would be able to control the path to sudo itself and cause the user to execute a trojan version (or just a wrapper) that steals the password. Would requiring a list of acceptable askpass programs actually fit the use cases of the people who rely on this feature?
In ogsudo the default path to the askpass helper is set in the sudo.conf file, not sudoers, since it is the sudo front-end that does the prompting.
For what it's worth, the idea for askpass came from ssh, which relies on environment variables for the askpass settings and does not use a command line flag or configuration options.
Would requiring a list of acceptable askpass programs actually fit the use cases of the people who rely on this feature?
Speaking as a developer of a tool who would depend on this feature, the answer is no as in context of remote servers, one would have to update the config on each system to support the sudo askpass there. For server management tools that don't want to modfiy/install anything on a remote system, that would make the workflow much more complicated.
For anyone concerned about the security implications of this, you can refer to OpenSSH with the SSH_ASKPASS environment variable, which basically does the same thing. If you want, you can reach out to the developers of OpenSSH as they surely have done a rigorous security analysis of this and decided that it was ok.
I'm not entirely convinced. If an attacker is able to control the user's environment, they would be able to control the path to
sudoitself and cause the user to execute a trojan version (or just a wrapper) that steals the password. Would requiring a list of acceptable askpass programs actually fit the use cases of the people who rely on this feature?
I don't disagree that both could happen, but in either case, the "fraud" would be more discoverable by the user, in the first case because the binary would not execute commands as sudo, and in the second case because creating a semi-feature-complete wrapper that also stole a person's password would be a bit of engineering effort to write cleanly. Using SUDO_ASKPASS is an easier command that steals a user's password; we are lowering the barrier of entry a fair bit here. (Not to mention that to any monitoring program, the program being run by the user is still the actual sudo binary, which is not true for the other cases)
For what it's worth, the idea for askpass came from ssh, which relies on environment variables for the askpass settings and does not use a command line flag or configuration options.
For anyone concerned about the security implications of this, you can refer to OpenSSH with the SSH_ASKPASS environment variable, which basically does the same thing. If you want, you can reach out to the developers of OpenSSH, as they surely have done a rigorous security analysis of this and decided that it was ok.
I don't necessarily agree here; SSH has a different threat model compared to sudo. For (og)sudo, local privilege escalation attacks are its main focus, since it allows root access. SSH is more concerned with fighting the fight at a network level, making sure that the connection between two servers is encrypted and cannot be eavesdropped/exploited in any way. Regardless, I went looking through the archives for portable-ssh and found the thread/bug where they discuss making ASKPASS configurable completely from the command line environment (through SSH_ASKPASS_REQUIRE). Reading through the discussion, they don't seem to have considered the possibility of supply chain attacks (also, it looks like it was implemented 5 years ago, while I'm sure folks were aware of supply chain attacks, I'm not sure if supply chain attacks through pip/npm were as mainstream then as they are now -- for context, the faker.js and color.js problem occured in 2022 and the more major XZUtils compromise occured in 2024).
I don't disagree that both could happen, but in either case, the "fraud" would be more discoverable by the user, in the first case because the binary would not execute commands as sudo, and in the second case because creating a semi-feature-complete wrapper that also stole a person's password would be a bit of engineering effort to write cleanly.
Engineering effort should be neglible in any case of such a password stealer attack, regardless of how you implement it. The password stealer attack you described can be implemented in a myriad of other ways that don't involve the askpass feature. You can just set any common command alias to any malicious program which fakes a sudo password prompt, you don't need the sudo -A itself for that.
In terms of discovering the fraud, the askpass executable is being run by sudo, but you can still obviously see which askpass program is called. If you implement monitoring for such things to tighten security, you can easily discover this as well. There is no way a fake askpass program can fly under the radar and not be detected.
So both of these arguments aren't really valid.
I don't necessarily agree here; SSH has a different threat model compared to sudo. For (og)sudo, local privilege escalation attacks are its main focus, since it allows root access. SSH is more concerned with fighting the fight at a network level, making sure that the connection between two servers is encrypted and cannot be eavesdropped/exploited in any way. Regardless, I went looking through the archives for portable-ssh and found the thread/bug where they discuss making ASKPASS configurable completely from the command line environment (through SSH_ASKPASS_REQUIRE). Reading through the discussion, they don't seem to have considered the possibility of supply chain attacks (also, it looks like it was implemented 5 years ago, while I'm sure folks were aware of supply chain attacks, I'm not sure if supply chain attacks through pip/npm were as mainstream then as they are now -- for context, the faker.js and color.js problem occured in 2022 and the more major XZUtils compromise occured in 2024).
The old sudo.xs also has an askpass feature, and that one is currently used everywhere. You mentioned supply chain attacks, but that is also very vague. Are you suggesting that sudo.xs and also ssh have an increased vulnerability to supply chain attacks because they provide an askpass feature and such a feature allows an easier attack than otherwise possible? Do you have any reference or concrete description to back this up?
What I like about the observation is that it purely looks at sudo security of the invoking user
Another mitigation that is simpler (e.g. not requiring a config setting) that comes to mind is to only allow askpass programs that are not owned/modifiable by the invoking user. Would that negatively impact use cases?
I do agree with other commenters that the precise attack scenario that this is aimed to thwart should become a bit more clear before we actually decide to implement a mitigation (The recent discussion around requiretty comes to mind, see #1245.)
Restricting askpass programs to those owned by the root user might be workable, with an option to allow unrestricted askpass programs.
When it comes to this feature being used by other tools, the whole point of it is that everything is handled by the user, so any solution of the askpass executable being owned by another user also wouldn't work. If you restrict a custom askpass executable to be required to be owned by root or something else, any tool would have to perform some root-based installation anyway and therefore could just install their own implementation of handling elevation, it wouldn't need the sudo askpass for that anymore. At least in our case, the askpass is a solution for user-level programs and installations still being able to elevate dynamically if needed.
I am no expert on sudo security, but I was under the impression that any user-level session where a user runs sudo (regardless whether an askpass is used or not) and enters their password, is vulnerable to a password stealing scenario. If your system is infected on the user-level where an attacker can tamper with your shell init files, and you type in your sudo password at the first sudo prompt without having additional verification in place and double-checking everything, then that can be used to steal the password, right? Or am I wrong here?
Cockpit sometimes requires that the askpass binary is owned by the calling user, depending on how Cockpit was (or was not) installed...
Thanks for all the input. We had a team discussion today and we think that the scenarios where an attacker has control over what askpass program is used would also allow other control over sudo invocations to give plenty of opportunity to obtain the password, as argued above.
I get folks' point of "hey we have the same exposure from everything else in a supply chain exec" and am okay with it. (even though I don't like the "other things are more insecure, so we are okay with it" argument).
When it comes to this feature being used by other tools, the whole point of it is that everything is handled by the user, so any solution of the askpass executable being owned by another user also wouldn't work. If you restrict a custom askpass executable to be required to be owned by root or something else, any tool would have to perform some root-based installation anyway and therefore could just install their own implementation of handling elevation, it wouldn't need the sudo askpass for that anymore. At least in our case, the askpass is a solution for user-level programs and installations still being able to elevate dynamically if needed.
Cockpit sometimes requires that the askpass binary is owned by the calling user, depending on how Cockpit was (or was not) installed...
One thing I'll say is that I feel like a situation where an unprivileged user downloads a random binary and wants it to assume root privileges without any user interaction feels like an antipattern we should prevent/not encourage, primarily because it is the exactly same pattern taken by basically every other trojan/malware/badware sample in other OS (Windows). I understand that y'all are here thinking about it from your very specific usecase, but I feel like in any other scenario "run this random unprivileged binary as sudo" is a thing I would actively discourage folks from doing purely from a "this might get you malware" POV.
Personally (a user who uses sudo in a non-server-side environment who has no interaction with xpipe and cockpit and installs programs through apt, npm etc), I would want a way to disable this completely if possible. (I guess that is a new feature request?)
Thanks for all the input. We had a team discussion today and we think that the scenarios where an attacker has control over what askpass program is used would also allow other control over sudo invocations to give plenty of opportunity to obtain the password, as argued above.
Could a potential compromise look like this where instead of using an environment variable for the askpass program, the -A option would require the program path to be passed instead? E.g. sudo -A <askpass program path>. That way, this would be a completely explicit option for the user without the possibility for an attacker to silently modify the environment.
Thanks for all the input. We had a team discussion today and we think that the scenarios where an attacker has control over what askpass program is used would also allow other control over sudo invocations to give plenty of opportunity to obtain the password, as argued above.
Could a potential compromise look like this where instead of using an environment variable for the askpass program, the
-Aoption would require the program path to be passed instead? E.g.sudo -A <askpass program path>. That way, this would be a completely explicit option for the user without the possibility for an attacker to silently modify the environment.
This wouldn't be a bad idea alongside the "allow folks to completely disable the option" tbh!
Cockpit sometimes requires that the askpass binary is owned by the calling user, depending on how Cockpit was (or was not) installed...
One thing I'll say is that I feel like a situation where an unprivileged user downloads a random binary and wants it to assume root privileges without any user interaction feels like an antipattern
I fully agree, but that's mostly the fault of the curl | sudo bash install instructions out there, and that's not at all related to askpass.
For the record: Cockpit does not download a random askpass binary from the internet of course. That would be crazy. The askpass helper originally comes from the distro rpm/deb, but is sometimes sent from there through ssh to a target host that you want to connect to.
Personally (a user who uses
sudoin a non-server-side environment who has no interaction with xpipe and cockpit and installs programs through apt, npm etc), I would want a way to disable this completely if possible. (I guess that is a new feature request?)
Yeah, disabling askpass helpers through a new config option seems reasonable.
would an alternative approach using
sudo --reset-timestamp --non-interactive --stdinbe an alternative solution? E.g. providing the password to the standard input of sudo?
Note that when using askpass with usual sudo - bad password retries and delays between them are controlled by sudo according to sysem configuration, will stdin-based solution work the same? This will require well-defined messages "protocol" on stdin/stdout and need to avoid clashing with printouts of application eventually launched by that sudo.
If I had a time machine...
It would actually be ideal if there was some sort of "pam conversation" protocol that we could speak via a file descriptor, but probably not stdin/stdout since we might confuse that with the program that we wanted to start (unless the protocol also includes a "we're done here" feature and takes great care to be race free regarding responses arriving unexpectedly at the end of the conversation)...
To be honest, though, we're kinda trying to move away from sudo anyway, so I doubt we would ever implement this on our side...
To be honest, though, we're kinda trying to move away from sudo anyway, so I doubt we would ever implement this on our side...
The reason we didn't originally conceive of askpass as necessary is related to this: when we started this project we considered "sudo" an interactive user-facing tool first and foremost (and we still do), and then the 'askpass' feature just seemed like it was only useful for people that wanted to use their super-duper password entry program for purely aesthetic reasons.
The reason we didn't originally conceive of askpass as necessary is related to this: when we started this project we considered "sudo" an interactive user-facing tool first and foremost (and we still do), and then the 'askpass' feature just seemed like it was only useful for people that wanted to use their super-duper password entry program for purely aesthetic reasons.
I hope that we could update your perception on the usage and requirements of a sudo askpass functionality. Once a project commits to using sudo askpass for elevation purposes and builds the implementation around it, it is very hard to completely change that many years later when a new sudo implementation comes around that does not support this. I also don't see any viable alternatives in some cases to the askpass functionality.
I fully understand the security concerns, that is why I proposed the compromise of removing the SUDO_ASKPASS environment variable and instead using an explicit approach with a command-line option with something like sudo -A <file> where there can be no silent password stealing. If you always want get the point across to any users what the askpass option is, the option could be called sudo --askpass-program <file>. What do you think of this approach?
Just want to note that in case of any alternate solution - need to have also clear way for caller to distinguish installed sudo "flavor" to select appropriate logic.
I hope that we could update your perception on the usage and requirements of a sudo askpass functionality. Once a project commits to using sudo askpass for elevation purposes and builds the implementation around it, it is very hard to completely change that many years later
That perception has already been updated succesfully! I should have stressed the word originally in the previous reply.
Generally this discussion has shown that it's a common & reasonable feature. So to be absolutely clear: we not only already decided that this is a reasonable request, but we've also actively planned to work on it in the very near future (for absolute clarity, I've updated #129 to make this clear).