8 ms·
Ancient “su – hostile” vulnerability in Debian 8 and 9
- blauditore 8y agoI'm not a shell pro; what is happening on the sleep line?
- jayrhynas 8y agoAs far as I understand it: A background subshell is started that waits 10 seconds and then runs a program with the input "id". That program uses ioctl to send characters to the current TTY. Since the user exited back to the root shell before the program executed, the `id` command is typed and executed on the root shell.
- deleted 8y ago[deleted]
- ryanlol 8y agoIt runs the command in a (subshell), in the background&. This is to make the process survive the subsequent logout. Because this process inherited terminal fds from the parent, it can continue accessing the logged out terminal (now root).
- c0l0 8y ago$ (sleep 10; /tmp/a.out id) & $ -> the end of the prompt of a "normal" (i. e. non-root) user () -> run everything inside in a forked subshell of the current shell sleep 10 -> "block"/sleep for 10 seconds via the `sleep` executable in your $PATH ; -> after the left-hand side terminates, proceed with the next command on the right-hand side /tmp/a.out id -> fork and exec the program located at /tmp/a.out with the literal byte sequence "id" on its argument vector & -> run this command (the whole subshell that () requests) as a background job When the user exits the shell that spawned the subshell, the whole process group will receive SIGHUP. The backgrounded subshell will still continue running, and after its `sleep` child process terminates, go on to run `/tmp/a.out`.
- blauditore 8y agoAh thanks, I didn't understand the subshell forking part before.
- rkeene2 8y agoIt's waiting, the "tty" command which is invoked a "a.out" causes the tty to receive the sequence of characters specified -- in this case "id\n". The vulnerability here is that if, as one user, you switch user contexts and then later (10 seconds, in this case, hence "sleep 10") the command interacts with the tty over the file descriptor that had been given to the child process and not killed when you exited the shell that spawned it.
- peterwwillis 8y agoThis explains the problem a little clearer I think: https://bugzilla.redhat.com/show_bug.cgi?id=173008 https://bugzilla.redhat.com/show_bug.cgi?id=173008
- masklinn 8y agoSo if I understand correctly, the issue is that when su-ing to more restricted privileges a hostile program (immediately executed via -c) can use TIOCSTI to inject commands which will escape su and execute as the more privileged user? Is that also an issue using `su; ./hostile; exit`?
- tedunangst 8y agoYou mean su to root? The same mechanism still exists, though root already has other powers.
- masklinn 8y agoNo, I mean su to a new shell and execute a command there rather than su -c.
- jwilk 8y agoThat would be weird if "su -c" was vulnerable but interactive "su" was not. The former is much easier to fix. In fact, "su" in Debian (which the subject of the submitted article), calls setsid() when you use -c, which defeats TIOCSTI.
- masklinn 8y ago> That would be weird if "su -c" was vulnerable but interactive "su" was not. Not necessarily, if TIOCSTI just pushes stuff to the term input buffer, this is going to get popped on the next prompt of su, so on an interactive su it's not going to be executed under escalated privileges but is instead going to be executed as the same user that executed the hostile program, while with a non-interactive su it's going to get popped on the next prompt of the su caller and thus get escalated privileges. That's my understanding of it anyway, I could be completely off.
- tedunangst 8y agoFor those unaware, ioctl(TIOCSTI) allows injecting characters back into the tty, where they will be read by the next process to read from the terminal. In this case, that process is the root shell that execed su.
- _wmd 8y agoI guess you're the right person to ask - why hasn't this just been ripped out of the likes of OpenBSD? edit: seems it already has! https://marc.info/?l=openbsd-cvs&m=149870941319610 https://marc.info/?l=openbsd-cvs&m=149870941319610
- carroccio 8y agoTIOCSTI ioctl https://events.ccc.de/congress/2008/Fahrplan/events/2992.en.html https://events.ccc.de/congress/2008/Fahrplan/events/2992.en....
- _wmd 8y agoAnother variant of using TIOCSTI with poor permissions. FWIW this exact same bug impacted Docker and LXC at various points. In the case of lxc-attach, when stdio is connected to a TTY, it creates a new pty within the container and multiplexes between them to avoid the issue. I don't think there is a single legitimate use for that ioctl.. it should just die already tl;dr passing a TTY with stopped privileged jobs reading from it (like an interactive root shell) into an unprivileged location is deadly, as the unprivileged location can use TIOCSTI to load up the TTY's input buffer and then exit, causing the stopped jobs to read that input when they're resumed
- Dylan16807 8y ago"Terminal I/O Control - Simulate Terminal Input" ah okay
- cryptonector 8y agoYes, I think this is exactly right. su(1M) and sudo(1M) should create a pty to run the child in. And this ioctl should go.
- bjt2n3904 8y agoJust tested this out, can confirm it works on Debian 7 as well. Genius little trick! Not sure about practical exploitation, though.
- codedokode 8y agoAs I remember, `login` program (that asks for your login and password on terminal) does a "virtual hangup" to prevent such things.
- cryptonector 8y agoWell, on *BSD the way this works is that when the session leader exits the pty/tty will internally call vhangup(2), which in turn does all that revoke(2) does on the tty FD plus it sends SIGHUP to any processes with that tty as the controlling tty. Linux for a long time had nothing like this. It has a vhangup(2), but looking at its implementation it doesn't seem to do what the BSD vhangup(2) does by calling revoke(2): replace all open file descriptors pointing to the tty with one that returns EIO for read(2)/write(2)/etc. Linux does NOT have a revoke(2), or at least I can't find it. There was a patch for that back in 2006 and 2007. I don't know what happened to that. EDIT: Some trivia as well. On BSD SIGHUP is generated by the tty. On Linux and Solaris/Illumos it's only generated by the session leader process on exit, and only if it wants to. This is how bash's disown builtin works: it just doesn't HUP the disown background jobs. The C shell (csh) historically never generated SIGHUP because it's a BSD shell. Back in the early aughts there was some controversy where csh users wanted OpenSSH's sshd to close a session when the pty session leader exits, as otherwise the session would stay open indefinitely. The OpenSSH developers feared this would lose data, and they were right. The source of this problem was that csh wasn't generating SIGHUP on Solaris and Linux, so background jobs stayed alive and held an open file reference to the pty, which meant that they kept sshd from seeing EOF on the ptm, so sshd would not terminate the session as long as those bg jobs stayed alive. This is all still the case today.
- cat199 8y agoOooh so thats why my terminals would get hungup on linux machines when I logged out with a bg job.. and why I haven't seen it since switching to MacOS or OpenBSD for most logins to other systems :) thanks :D
- cryptonector 8y ago
- deleted 8y ago[deleted]
- sandworm101 8y agoLol. Thanks. Work machine. Must have ctrl-tabbed without realizing.
- JdeBP 8y agoThis is old news, that keeps being reported over and over. Part of the problem, I suspect, is that people keep pointing to the wrong locus of the problem. Even here, this is being characterized as a Debian problem. This is a kernel mechanism. * https://nvd.nist.gov/vuln/detail/CVE-2013-6409 https://nvd.nist.gov/vuln/detail/CVE-2013-6409 * https://nvd.nist.gov/vuln/detail/CVE-2015-6565 https://nvd.nist.gov/vuln/detail/CVE-2015-6565 * https://nvd.nist.gov/vuln/detail/CVE-2016-2779 https://nvd.nist.gov/vuln/detail/CVE-2016-2779 * https://nvd.nist.gov/vuln/detail/CVE-2016-7545 https://nvd.nist.gov/vuln/detail/CVE-2016-7545 * https://nvd.nist.gov/vuln/detail/CVE-2017-5226 https://nvd.nist.gov/vuln/detail/CVE-2017-5226 Some kernel people take the view that TIOCSTI is of no Earthly use, and there are other ways to implement line editing, and just make using it an error. * http://undeadly.org/cgi?action=article&sid=20170701132619 http://undeadly.org/cgi?action=article&sid=20170701132619 * https://github.com/openbsd/src/commit/baecf150995d4609cd147948779361c3152f355d https://github.com/openbsd/src/commit/baecf150995d4609cd1479... Others take a different view. * http://www.openwall.com/lists/oss-security/2017/06/03/9 http://www.openwall.com/lists/oss-security/2017/06/03/9 * http://www.openwall.com/lists/kernel-hardening/2017/05/15/8 http://www.openwall.com/lists/kernel-hardening/2017/05/15/8 * http://www.openwall.com/lists/kernel-hardening/2017/05/17/1 http://www.openwall.com/lists/kernel-hardening/2017/05/17/1 * http://www.openwall.com/lists/kernel-hardening/2017/05/29/16 http://www.openwall.com/lists/kernel-hardening/2017/05/29/16 * http://www.openwall.com/lists/kernel-hardening/2017/05/30/9 http://www.openwall.com/lists/kernel-hardening/2017/05/30/9 * http://www.openwall.com/lists/kernel-hardening/2017/05/30/26 http://www.openwall.com/lists/kernel-hardening/2017/05/30/26 * http://www.openwall.com/lists/kernel-hardening/2017/05/30/27 http://www.openwall.com/lists/kernel-hardening/2017/05/30/27 * http://www.openwall.com/lists/kernel-hardening/2017/05/30/32 http://www.openwall.com/lists/kernel-hardening/2017/05/30/32 * http://www.openwall.com/lists/kernel-hardening/2017/05/31/16 http://www.openwall.com/lists/kernel-hardening/2017/05/31/16
- AbacusAvenger 8y agoUsually when something is reported as being a distribution bug, it's because they have some patch specific to their packages that causes the issue. Is that not the case here? Are other distrbutions affected right now?
- im3w1l 8y agoI'm increasingly feeling that terminals and bash are just too complex and have too many edge cases and footguns and that we'd be better of just starting over with something were security was a focus from day zero.
- jackewiehose 8y agoBecause newer software has less bugs and is more secure? I doubt that.
- deepsun 8y agoActually, refactoring a somewhat larger internal project in Google to a different language+architecture served us as a pretty good code review + self security audit. Yes, there was some turbulence at the beginning, but in the end it turned out to be way better understood/tested project. I believe every project should be re-written every 4-5 years, it becomes less and less expensive to maintain it on the long run. Also keeps workers morale and promotion cycle healthy. Unfortunately, not all companies have resources AND structure to put that resources in refactoring something that already works.
- ThbTs4wbXC9Qjv 8y agoHas that project been subjected to the greater world of people who don't think like Google programmers? Internal projects always suffer from groupthink. Don't get me wrong, I love internal projects because once you're behind the gate, they are the first things I probe and attack. Usually very easy targets.
- lmm 8y agoYep. Unix has zillions of ways for processes to interact with each other, which makes for an enormous attack surface. The future is something like unikernels on the server and something like Qubes running them on the desktop, so that each "process" is properly isolated and can only communicate through channels that are deliberately designed for it. We're going to have to rediscover how we do things like pipelines in a safe way, but the current unix design of small processes interacting via unstructured interfaces that mingle commands and data is just untenable.
- pjkundert 8y agoWe used TIOCSTI to attack Unix terminal sessions left open to “write” — in 1985. I was wondering when/if this would show up again!
- wilun 8y agoPosix TTY and more precisely stdin/stdout/stderr inheritance and internals of FD have a completely insane design. There is the famous divide between file descriptors and file descriptions. Hilarity can and will ensue in tons of domains. I nearly shipped some code with bugs because of that mess (and could only avoid those bugs by using threads; you can NOT switch your std fd to non-blocking without absolutely unpredictable consequences), and obviously some bugs of a given class can create security issues. Especially, and in a way, obviously, when objects are shared across security boundaries. Far is the time when Unix people were making fun of the lack of security in consumer Windows. Today, there is no comprehensive model on the most used "Unix" side, while modern Windows certainly have problems in the default way they are configured, but at least the security model exist with well defined boundaries (even if we can be sad that some seemingly security related features are not considered officially as security boundaries, at least we are not deluding ourselves into thinking that a spaghetti of objects without security descriptors can be shared and the result can be a secure system...)
- caf 8y agoThere is a model, it's just not particularly well publicised: a file descriptor is a capability. That's it.
- wilun 8y agoIs it efficient and sufficient though? And can and do we build real security on top of it? This issue shows systems have been built for decades with blatant holes because it was not taken into account in even core os admin tools. There is the other problem corresponding to the myth that everything is a fd. Which has never been true, and is even less and less as time passes. Also, extensive extra security hooks and software using them are built, but not of top of this model. Finally, sharing posix fd across security boundaries often causes problems because of all the features available for both sides, for which the security impact are not studied. A model just stating that posix fd are capa is widely insufficient. So if this is the only one, even in the context in pure Posix we already know this is an extremely poor one.
- erlkonig 8y agoAh, this looks like the old ungetc() exploit, where (back in the 1980s at utexas.edu) we'd leave a process connected to a terminal, wait for another user to log in, then push characters to their shell from our program using ungetc(). Essentially, each character pushed ends up looking like a fresh input character to the other program. The basic issue is whether all open file handles that shouldn't be there (our hack program, for example) got closed out by the new login session. For something like login, the question is easy, ONLY itself should be connected early on. For su, it's much weirder, since the user may have created background jobs before running su, and su and sudo can't reasonably close all other handles on the original tty device. Further su and sudo can't close all file descriptors of the "sub-session" as it exits, because that the "sub-session" is created by forking, so su/sudo aren't around at the end. Creating a separate pseudo-terminal device to allow for draconian cleanup, and prevent even having both user IDs connected to the same tty device, seems like the best place to start. Hmm, now I want to go update the user-group-setter program I use (which also can set auth user IDs on Solaris, etc) and try having it do ptty allocation for the subjob. In the meantime, try this to get a session and run through the same demo steps: setsid -w su - <user> Won't for everything (no /dev/tty), but it does block the example. You can add a tty if you have one handy, too, by using redirection in the spawned process in this general form, but I don't currently have the cluon for how to create a /dev/pts/<num> from the shell level - if someone can construct the full command, I'd like to see it :-) setsid sh -c 'exec command <> /dev/tty2 >&0 2>&1'
- jwilk 8y ago> I don't currently have the cluon for how to create a /dev/pts/<num> from the shell level As I recommended in http://www.openwall.com/lists/oss-security/2018/06/14/2 http://www.openwall.com/lists/oss-security/2018/06/14/2 , use screen or tmux: screen su - <user> script(1) is more lightweight than screen/tmux, but it can't be easily persuaded to run arbitrary commands, such as "su". :-/
- yorwba 8y agoHow is persuading script to run su not easy? I just tried script -c su /dev/null and it worked as I expected. (/dev/null is there to prevent script from logging the interaction to a file)
- exikyut 8y agoNobody else has pointed this out (!): whatever platform is running at this URL doesn't sanitize input. Notice how the C #includes seem to be including emptiness. Well, <stdio.h> et al weren't stripped; they're still in the source code, un-converted < > (ie NOT converted to < >) and all.
- bcaa7f3a8bbc 8y agoPaX/grsecurity has mitigation to this issue, at least for 10 years. From grsecurity's config for GRKERNSEC_HARDEN_TTY. | There are very few legitimate uses for this functionality and it | has made vulnerabilities in several 'su'-like programs possible in | the past. Even without these vulnerabilities, it provides an | attacker with an easy mechanism to move laterally among other | processes within the same user's compromised session. Has one run a grsecurity kernel, the system would not be affected. Some independent developers and KSPP people are also trying to submit this mitigation to the mainline kernel for many years, but so far none of the patch went into the kernel. Since grsecurity is now a private product, you may want to check them out and apply this mitigation to the mainline kernel. [PATCH] drivers/tty: add protected_ttys sysctl * https://gist.github.com/thejh/e163071dfe4c96a9f9b589b7a2c24fc6 https://gist.github.com/thejh/e163071dfe4c96a9f9b589b7a2c24f... tiocsti-restrict : make TIOCSTI ioctl require CAP_SYS_ADMIN * https://lwn.net/Articles/720740/ https://lwn.net/Articles/720740/