Bit Focus

A note of sudo and the user-setting permission

Posted at 2021-01-18 03:41:43 | Updated at 2021-01-18 03:41:43

sudo is the magic word in Unix-like world. It grants normal users with administrator access, right?

Actually, that is not so true. The correct way to describe it, which you can find in man sudo, is that

sudo allows a permitted user to execute a command as the superuser or another user

So how does sudo work to serve that purpose? The answer is the user-setting bit in the permission.

First, let's check the permission of your shell program. Here is an example from my system.

% ls -l $SHELL
-rwxr-xr-x 1 root root 858K  Feb 24 2020 /bin/zsh*

You can see the permission string is -rwxr-xr-x. This is normal, as expected. Then let's take a look at sudo.

% ls -l `which sudo`
-rwsr-xr-x 1 root root 163K  Jul 15 2020 /usr/bin/sudo*

Oh, we can see the permission string is a little uncommon. It is -rwsr-xr-x. An x is replace by an s. That is the user-setting bit. It allows the program is executed with the owner of the file as the effective user.

Technically speaking, at the moment the sudo process is running, it already runs as root (or the system administrator), and it can do whatever it wants. However, for security reasons, of course it validates if the actual user has permission (set in the sudoers file).

Be careful when try the following code and make sure your system is free from unexpected access

Then what if we remove such validations? We can try it by compile a simple shell-like program, and change its permission in the same way sudo has.

The C code is like this

Code Snippet 0-0

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>

int main(int argc, char* argv[])
    struct passwd *p = getpwuid(getuid());
    printf("User: %d:%s\n", getuid(), p->pw_name);
    struct passwd *ep = getpwuid(geteuid());
    printf("Effective user: %d:%s\n", geteuid(), ep->pw_name);

    // here is the magic function call, which make `root` as the current user

    p = getpwuid(getuid());
    printf("User: %d:%s\n", getuid(), p->pw_name);
    ep = getpwuid(geteuid());
    printf("Effective user: %d:%s\n", geteuid(), ep->pw_name);

    // typically, normal users do not have permission to read /etc/sudoers
    return system("cat /etc/sudoers");

Compile this code with gcc and you would get an a.out file. Then run the following to change it permission

% sudo chmod 4777 a.out

You should be able to see the permission is like

% ls -l a.out
-rwsrwxrwx 1 root root 17K  Jan 18 12:26 a.out*

Try it, and it would print out the user name and effective user name before and after invocation of setuid. At this moment, we can see that the user is changed from the current user to root. Then it will give us the content of /etc/sudoers.


To create a backdoor in the system, based on the code above, just replace the system(...) with system(argv[1]), and change the permission of the compiled executable, it will then become an sudo without validation and allows arbitary commands given in argv[1] to be executed as root!

Post tags:   sudo  Linux

Leave a comment:

Creative Commons License Your comment will be licensed under
CC-NC-ND 3.0

. Back to Bit Focus
NijiPress - Copyright (C) Neuron Teckid @ Bit Focus
About this site