Introduction
On 2001-09-02, I posted on BugTraq a problem with the combination of using S/Key’s keyinit and the program sudo on a system. This article is a re-phrasing of that message, with some clarifications based upon mail I received in response.
Background
S/Key’s keyinit(1)
S/Key is a one-time password (OTP scheme that is available on many systems, and comes default in FreeBSD 4.x and earlier. It uses program called keyinit to allow a user to re-initialize a sequence. keyinit does not require any authentication from the user in order to reset the sequence.
sudo(1)
From the manpage:
sudo allows a permitted user to execute a command as the superuser or another user, as specified in the sudoers file. The real and effective uid and gid are set to match those of the target user as specified in the passwd file (the group vector is also initialized when the target user is not root). By default, sudo requires that users authenticate themselves with a password (NOTE: this is the user’s password, not the root password). Once a user has been authenticated, a timestamp is updated and the user may then use sudo without a password for a short period of time (five minutes by default).
sudo determines who is an authorized user by consulting the file /usr/local/etc/sudoers. By giving sudo the -v flag a user can update the time stamp without running a command. The password prompt itself will also time out if the user’s password is not entered with N minutes (again, this is defined at configure time and defaults to 5 minutes).
Impact
If S/Key is used for authentication by sudo (directly or indirectly) to authenticate users, a trivial root compromise if possible if users granted root by sudo allow their privileges to be compromised.
Demonstration
- Have S/Key installed with sudo
- Logon as a user who is authorized to use sudo as root
- Run keyinit to initialize an OTP sequence.
- Use S/Key’s key to get a sequence.
- Run sudo sh authenticate through an OTP.
- You now have a root shell, without needing to know any secrets; all that was needed was to get past the initial logon.
Analysis
Programs such as sudo which provide privileged-level services based on a user’s ability to authenticate through S/Key to normal-privilege levels will allow such privileged services to an attacker who is able to change the OTP sequence. In the case of sudo, assuming the victim has been given root privilege under sudo, an attacker is able to authenticate through PAM to gain root privileges, since PAM uses S/Key.
The key thing to note with sudo is that the attacker has had to do nothing besides run keyinit with a victim’s privileges to gain root privileges. No action needs to be taken by the user once the attacker is able to run keyinit as the victim. This is not a trojan attack.
In one respect this situation is similar to an attacker modifying ssh’s ~/.ssh/authorized_keys. However, ssh is used solely for obtaining user-level privileges. S/Key, on the other hand, is often used with PAM, and when programs such as sudo use PAM to allow users to gain privileged levels (in contrast to unprivileged user-levels), a root compromise can happen.
The use of sudo and S/Key individually are thought to increase the security of a system. However, however, this demonstration exhibits severe flaws in the combination of S/Key’s keyinit and sudo.
Comments, replies, and my responses
Not more important than a trojan?
Comment
Weitse Venema writes:
If an operator leaves his/her terminal unattended, then a miscreant can plant any number of trojan horses to gain future root access.
The possibilities for getting future root access are not limited to skeyinit + sudo. To begin with, any trojan horse will suffice that captures the operator’s plain-text password. Then there are cron and at, which give the equivalent of operator terminal access.
Therefore, adding a password challenge to skeyinit is not sufficient. The fix, at least for today’s versions of FreeBSD, is for operators not to leave their terminal unattended.
My Response
My response was:
Trojans can theoretically be avoided given the right user-environment setup. They also require action to be taken by the victim, which increases the time it takes to execute the attack. The attack I describe is not a trojan, and needs no victim action.
The importance of needing user action is important, because increasing the length of time from the start of the attack to the finish of it increases the possibility of the trojan being detected by some means.
I would like to emphasize that the acknowledgment of a different type of attack from a trojan is very important. There are ways to avoid being victim to a trojan, and the concept of being victim to a trojan is not a new one. Therefore, some thought may be given to avoiding being victim to a trojan. However, the attack I describe is a distinctly different type of attack, and little user thought is likely to be given to avoid being susceptible to it.
How about a backdoor instead?
Comment
Theo de Raadt writes:
This is horsepucky.
In that case, the cp(1) and chmod(1) commands are the same — a backdoor.
My Response
Hogwash. You of all people should realize the difference between a backdoor and something that allows raised privilege levels. The attack I describe allows an attacker to reach elevated privileges. Something like cp or chmod, and backdoors in general, only allows an attacker to sustain or re-acquire an already-achieved privilege level.
Users leaving terminals unattended, or having themselves be compromised via other means shows other flaws in the system
Comment
Derek Martin writes that if a system has sudo-privileged users being compromised, then this shows a lack of general security in the system. Hence, the attack really is small fries.
My Response
If a user is compromised, then it should be solely that, a user compromise. Because users are the weakest links in a system, we should contain breaks, especially those that users are vulnerable to create. This is the whole point of systems such as Security-Enhanced Linux, to contain problems in a system. Just because your Apache or Sendmail is compromised doesn’t meant that the system should suffer a complete downfall; rather, the compromise is contained and isolated. The keyinit+sudo combination shows a lack of containment; a user compromise leads directly to a system compromise.
Final Notes
It really amazes me that so few others realize the importance of this problem, even well-known figures, such as Theo de Raadt. True, this is a problem that only occurs when a user’s privileges are compromised, and many have said we should give up the game then, but that is a ridiculous notion. One should contain breaks in system wherever they may be.