I'm hardening a Linux system and wanted to test (setuid
-based) shell escapes using common binaries, like awk
, vim
, etc., supporting command executing.
However, all binaries I've tested except sh
and bash
don't respect their setuid
bit.
In particular, awk
continues to execute as a normal user:
$ ls -lL /usr/bin/awk
-rwsr-xr-x 1 root root 121976 Mar 23 2012 /usr/bin/awk
$ id
uid=1000(bob) gid=1000(bob) groups=1000(bob)
$ awk 'BEGIN{system("id")}'
uid=1000(bob) gid=1000(bob) groups=1000(bob)
In contrast, bash
executes as root
when given the -p
option:
$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1168776 Apr 18 2019 /bin/bash
$ /bin/bash -p
# id
uid=1000(bob) gid=1000(bob) euid=0(root) groups=1000(bob)
Is there any way to make awk
, vim
, less
, etc. respect the setuid
bit and execute the command as root
?
OS:
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
Update:
parallels@debian-gnu-linux-vm:~$ ls -la /proc/self/fd/0 /dev/fd/0 /dev/stdin
lrwx------ 1 parallels parallels 64 Mar 26 08:15 /dev/fd/0 -> /dev/pts/1
lrwxrwxrwx 1 root root 15 Mar 20 19:56 /dev/stdin -> /proc/self/fd/0
lrwx------ 1 parallels parallels 64 Mar 26 08:15 /proc/self/fd/0 -> /dev/pts/1
Best Answer
In your example, it's not
awk
which is dropping privileges or not "respecting its setuid bit", but the/bin/sh
command that awk uses to implement itssystem()
function.Just like its C counterpart, awk's
system()
does not parse and run the command directly, but by passing it as an argument to/bin/sh -c
. If/bin/sh
is bash (or the Debian version of dash, or a couple of other shells which copied this misfeature from bash), it will reset its effective uid back to the real one.The same thing applies to
print | "cmd"
or"cmd" | getline
in awk -- they're implemented withpopen(3)
which calls/bin/sh -c
. Notice that it's always/bin/sh
(or the system's shell, eg./system/bin/sh
on Android), not the user's login shell or that from the$SHELL
environment variable. [1]This is different in perl: perl's
system
,exec
,open "|-"
,open2
,open3
, etc will run the command directly if they're called with multiple arguments or if the command does not contain shell metacharacters:This example is on Debian 10. On other systems like FreeBSD or older Debian, both commands will print the same thing, because their
/bin/sh
does not drop privileges. [2]Notes:
[1] Other programs like
vim
andless
do use the$SHELL
environment variable, so they're easily "fixable" by pointing it to some wrapper. Invim
you could also use:set shcf=-pc
to pass the-p
option to the shell used for the:!
and similar commands.[2] The perl example will also work on OpenBSD just like on FreeBSD, provided that you replace the
env - /tmp/perl 'script'
with the more obtuseecho 'script' | /tmp/perl /dev/fd/0
.OpenBSD's perl will reject the
-e
argument and refuse to read its script from the stdin when running in setuid mode (see this which is ending here -- OpenBSD supposedly has secure setuid scripts).But that does not apply to
/dev/fd/N
, which perl is handling itself when given as a script name (only the/dev/fd/N
form, not/dev/stdin
or/proc/self/fd/N
).