Ok I did some research and it turns it... there is no reason!
I believe how sudo
works is:
- It loads
libpam.so
. libpam.so
is just an ordinary library. No special permissions.
- It asks
libpam
, "is the password for the current user correct?".
- If
libpam
says "yes" then it runs the command as root (sudo
is SUID so it can do that).
The delay is inserted by libpam
. It's actually super super complicated how the delay is calculated - it's even randomised slightly. Some of the code is 25 years old so it's a bit hard to follow. I think the delay is triggered in pam_authenticate()
where there's this code:
_pam_await_timer(pamh, retval); /* if unsuccessful then wait now */
And the actual delay is somehow set by calls to pam_fail_delay()
. That page has some helpful information including rationale:
It is often possible to attack an authentication scheme by exploiting the time it takes the scheme to deny access to an applicant user. In cases of short timeouts, it may prove possible to attempt a brute force dictionary attack -- with an automated process, the attacker tries all possible passwords to gain access to the system. In other cases, where individual failures can take measurable amounts of time (indicating the nature of the failure), an attacker can obtain useful information about the authentication process. These latter attacks make use of procedural delays that constitute a covert channel of useful information.
On my RHEL 8 system the delay is set using the fail delay PAM plugin. If you edit /etc/pam.d/system-auth
then you see this line:
auth required pam_faildelay.so delay=2000000
Comment it out and the delays disappear! According to the docs this is a common config for local authentication and there's also password-auth
for remote auth, so it should be 100% safe to remove this delay.
Some stuck-in-the-muds are probably screaming BuT lOcAl DiCtIoNaRy AtTaCkS!!1! at me right now. Don't listen to their squeals.
Recall how I said libpam.so
is an ordinary library. It isn't SUID, so how does it actually check your password (since /etc/shadow
is a thing now it can't just see the hash). The answer is it calls a helper binary that IS SUID. That is called unix_chckpwd
, and it's probably on your PATH
. If you run it it checks if stdin is a TTY and does some silly security theatre:
❯ unix_chkpwd
This binary is not designed for running in this way
-- the system administrator has been informed
There's a 10 second wait at the end for literally no reason but to annoy you. I'm not joking:
sleep(10); /* this should discourage/annoy the user */
Anyway, a thought that might be niggling at you now is "so if PAM is responsible for the delay and it's just a normal non-SUID library, how does it securely store access attempt times, and e.g. do exponential delays?"
Well... it doesn't. Don't want to wait for sudo
's delay? You can just run a new instance of sudo
. But you don't even need that because unix_chkpwd
has this comment:
/*
* we establish that this program is running with non-tty stdin.
* this is to discourage casual use. It does *NOT* prevent an
* intruder from repeatedly running this program to determine the
* password of the current user (brute force attack, but one for
* which the attacker must already have gained access to the user's
* account).
*/
The delay is 100% security theatre. It does nothing to stop local dictionary attacks.
I mean even if it did, if you have access to a local user's account it's trivial to get their password without cracking it.
So what have we learned?
- There's no point to
sudo
's delay.
- The security architecture of PAM is crazy.
- PAM itself is stateless so it actually can't do exponential delays. I client of PAM (e.g.
sshd
) could though.
So finally, why does this delay exist if it is totally pointless? My guess is a) it make people feel secure (look at all the replies in this question saying it improves security), and b) it does make sense for remote password-based authentication, so I guess they added the feature for that and then nobody bothered to turn it off for sudo
?