Let’s see an example of command injection. We’re given an executable file acat
that reads the contents of restricted documents.
$ cat secret cat: secret: Permission denied $ ./acat secret my_secret_password
This happens because secret
is owned by root
and only it has read access permission to this file.
$ ls -al secret -r-------- 1 root user 19 sep 08 18:22 secret
When we examine the acat
executable, we can see that it has the setuid bit set (it’s the s
after w
and before r
).
$ ls -al acat -rwsr-xr-x 1 root user 16944 sep 4 13:44 acat
The setuid bit allows us to execute acat
with the privileges of the file owner, in this case root
.
Examining acat
The source code of acat
is as follows:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #define MAXLINE 128 int main(int argc, char *argv[]) { char buff[MAXLINE] = "/bin/cat "; if (argc != 2) { fprintf(stderr, "Usage: ./acat <file>\n"); return 0; } strncat(buff, argv[1], MAXLINE - strlen(buff) - 1); setreuid(geteuid(), geteuid()); system(buff); return 0; }
The two relevant function calls are setreuid
and system
. Even though we execute acat
as user
, the effective user id is that of the file owner, root
(because the setuid bit is set). Then, geteuid()
will return 0
, which is the user ID of root
. Calling setreuid
with this argument will give the program root privileges.
system
executes a shell command. In this case, we call it with argument:
system("/bin/cat <arg>")
Where arg
is the command-line argument passed to the program.
We compile and set the setuid bit of this program as follows:
$ gcc -o acat acat.c $ sudo chown root acat $ sudo chmod u+s acat
Which will generate a acat
executable as the one we described at the beginning of this post.
Exploiting acat
A setuid programs is vulnerable to exploits such as privilege escalation and we should be very careful when writing or using one.
The problem with our example program is that it doesn’t sanitize its input! We can pass anything to it and it will blindly try to run it.
$ ./acat "file1 file2" /bin/cat: file1: No such file or directory /bin/cat: file2: No such file or directory
This can be readily exploited to get access to a root shell.
$ whoami user $ ./acat "file; sh" /bin/cat: file: No such file or directory # whoami root
The ;
is used to separate command-line commands. Effectively, we’re running the two following commands (with root
privileges):
$ /bin/cat file $ sh
Which will spawn a root
shell as we saw above.
Calls to system
, especially in a setuid executable, open the way to many vulnerabilities and we should be very careful with them.