Both system()
and execve()
can be used to execute another command inside a program. Why in set-UID programs, system()
is dangerous, while execve()
is safe ?
system will call the shell (sh) to execute the command sent as an argument. The problem with system
because the shell behavior depends on the user who run the command. A small example:
Creating a file test.c
:
#include <stdio.h>
int main(void) {
if (system ("ls") != 0)
printf("Error!");
return 0;
}
Then:
$ gcc test.c -o test
$ sudo chown root:root test
$ sudo chmod +s test
$ ls -l test
-rwsr-sr-x 1 root root 6900 Dec 12 17:53 test
Creating a script called ls
in your current directory:
$ cat > ls
#!/bin/sh
/bin/sh
$ chmod +x ls
Now:
$ PATH=. ./test
# /usr/bin/id
uid=1000(cuonglm) gid=1000(cuonglm) euid=0(root) egid=0(root) groups=0(root),
24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),105(scanner),
110(bluetooth),111(netdev),999(docker),1000(cuonglm)
# /usr/bin/whoami
root
Oops, you got a shell with root privileges.
execve does not call a shell. It executes the program that passed to it as first argument. The program must be a binary executable or a script start with shebang line.
ls
can do fancy things with its environment, so even without system()
, you should probably sanitise the environment. When using setuids you want to minimise what is done as root (typically not execute commands). –
Beeswax /bin/ls
, the user can add /
to $IFS
, causing the shell split /bin/ls
to bin
and ls
. Now, an executable called bin
in current directory can do the same thing as ls
in my answer. –
Antwanantwerp system()
and execve()
work in different ways. system()
will always invoke the shell and this shell will execute the command as a separate process (this is why you can use wildcards and other shell facilities in the command line when using system()
).
execve()
(and the other functions in the exec()
family) replaces the current process with the one being spawned directly (the execve()
function doesn't return, except in case of failure). In fact system()
implementation is supposed to use a sequence of fork()
, execve()
and wait()
calls to perform its function.
Of course both are dangerous depending on what is being executed when the process has root privileges. system()
, though, brings some extra dangers due to the additional shell "layer" it uses that opens room security breaches as it invokes a root shell as in the case of your question (i.e., the process has the suid bit).
Apart from the metioned security issues with system()
, the spawned process inherits the main program's environment. This can be very problematic when using suid
, for example when the calling process sets LD_LIBRARY_PATH
-environment variable.
With the exec()
-family the calling program can set the environment to exactly what's needed (and safe) for the called program before calling exec()
.
And of course the shell called by system()
can have security issues itself.
© 2022 - 2024 — McMap. All rights reserved.
system()
is without problems but wouldn't the above be resolved by using absolute paths in the binary executable? – Microclimate