Skip to content

Latest commit

 

History

History
740 lines (473 loc) · 32.4 KB

File metadata and controls

740 lines (473 loc) · 32.4 KB

Lab 2: Security Enhanced Linux

Goal of Lab

The goal of this lab is to use Security Enhanced Linux (SELinux) to help mitigate against attacks due to privilege escalation vulnerabilities in a three part exercise.

  • In the first part of this lab exercise, you will become a hacker and try to execute a real vulnerability on a given Red Hat Enterprise Linux 7 system and explore how SELinux can help to protect this system.

  • In the second part of this lab exercise, you will turn SELinux on for an environment of web servers in an automated fashion using Ansible.

  • In the last part of this lab exercise, you will configure SELinux according to a U.S. Department of Defense STIG security control policy rule.

Introduction

Security Enhanced Linux (SELinux) can help to proactively mitigate systems from the consequences of exploits during the window of vulnerability. Specifically, this is the time window before a security fix is released. This protection is done by defining SELinux policies on your systems.

SELinux policy

SELinux isolates all processes running on the system to mitigate attacks which take advantage of privilege escalation vulnerabilities. A privilege escalation vulnerability means that a process gains more access rights than it should have. To prevent this, SELinux enforces Mandatory Access Control (MAC) mechanism over all processes. It labels every process, file, or directory according to rules specified in a security policy known as the SELinux policy. The SELinux policy also specifies how processes interact with each other and how they can access files and directories. SELinux denies every action that it is not explicitly allowed by the SELinux policy.

In one of the below exercises, we’ll see an example where using this process isolation can help protect us from a privilege escalation vulnerability of an exploit.

Introduction to the Shellshock vulnerability and SELinux

The Shellshock vulnerability is a bash exploit and the root issue is that you could put any command after the env variable in a command , which allows an attacker to execute any arbitrary code. The following pictures shows an example of the bash exploit on an apache server.

lab2 shellshock 1

If you had a cgi script accessing user data or the internal network, then this script could compromise either the internal network or user data on your system.

So what can SELinux do to mitigate against the Shellshock bash exploit?

The important fact to understand is that SELinux does not block the exploit but it will prevent escalation of confined domains. These confined domains are defined by the SELinux policy installed on a system. Because SELinux controls on their types (SELinux labels), the process is doing what it was designed to do and can not access what is not allowed in the SELinux policy.

The picture below shows the situation described above with SELinux enabled and in enforcing mode.

lab2 shellshock 2

If an attacker executed the potential cgi script mentioned earlier, the attacker would not be able to access either user data or certain parts of the internal network as it is defined in the SELinux policy.

How is this done in reality? How do types, which ensure described process separation, look in reality? The below exercises will help answer these questions.

Lab 2.1 Exploiting Red Hat Enterprise Linux 7 with the Shellshock vulnerability

Goal of Lab 2.1

In this first exercise, let’s become a hacker and try to exploit Red Hat Enterprise Linux 7 with the Shellshock vulnerability.

As an administrator of Red Hat Enterprise Linux 7 servers, I want to enable SELinux for the web servers in my environment to mitigate against damages caused by zero day vulnerabilities.

This lab exercise is split into three steps:

  1. Exploiting a RHEL system with SELinux in Permissive mode

  2. Exploiting a RHEL system with SELinux in Enforcing mode

  3. Analyzing SELinux denials

Lab 2.1.1 Logging into the selinux1.example.com system and navigating to the selinux scripts directory

The exploit will be executed from the selinux1.example.com system.

  1. If not already there, log into to the bastion host as lab-user from your desktop system replacing GUID with your lab’s GUID. Use the password r3dh4t1!

    [localhost ~]$ ssh [email protected]
  2. If not already root, become root and then log into the selinux1.example.com system.

    [lab-user@workstation-GUID ~]# ssh [email protected]
  3. Move to directory /root/selinux_sctipts/ where are all the scripts needed for provide attack.

    [root@selinux1 ~]# cd /root/selinux_scripts
    Note
    If you’d like copies of these selinux_scripts, they can also be found in this github link here.
  4. Repeat steps #1-3 above on a second terminal (this terminal window will also be connected to selinux1.example.com)

Lab 2.1.2 Exploiting the system with SELinux in Permissive mode

Goal of Lab 2.1.2

In this part of the lab exercise, we are going to utilize the two open open terminals from the previous exercise. (both selinux1.example.com). The first terminal window will be for listening on 9999 tcp port and the second terminal window will be for executing the exploit script.

Introduction

Let’s see this visually. Take a look at the image below. This image describes the flow of how the exploit that will be executed. On the left side is the victim server (selinux4 system). From the attacker machine (which is the selinux1 system), a http request will be sent and part of this httpd request will be to open the shell to the attacker machine listening on tcp port 9999.

lab2 shellshock flow

Lab 2.1.2 exercise steps

Now let’s go through the steps we just described above.

  1. Go to your two opened terminals that are connected to the selinux1.example.com systems and pointed to the /root/selinux_scripts directory.

  2. Note that the victim server, selinux4, has SELinux in permissive mode by default. It is running the Apache service running with an older version of bash. Everything is ready to run the exploit.

  3. Based on flow of the ShellShock attack we learned about earlier, it’s necessary to start listening on tcp port 9999 on one of the selinux1 terminals you have opened. We’ll be using Ncat, which is a feature-packed networking utility which reads and writes data across networks from the command line.

    [root@selinux1 selinux_scripts]# nc -lvp 9999
    Ncat: Version 7.50 ( https://nmap.org/ncat )
    Ncat: Listening on :::9999
    Ncat: Listening on 0.0.0.0:9999
  4. Now, from the other selinux1 terminal, let’s run the exploit:

    [root@selinux1 selinux_scripts]# ./shellshock_exploit.sh
  5. Now, on the terminal where nc command was executed, a bash prompt should now appear.

    [root@selinux1 selinux_scripts]# nc -lvp 9999
    Ncat: Version 7.50 ( https://nmap.org/ncat )
    Ncat: Listening on :::9999
    Ncat: Listening on 0.0.0.0:9999
    Ncat: Connection from 192.168.0.24.
    Ncat: Connection from 192.168.0.24:38668.
    bash: no job control in this shell
    bash-4.2$
  6. For testing purpose, few commands could be executed on the victim system (selinux4). Type id and then type uname -a. Then type exit.

    bash-4.2$ id
    id
    uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_sys_script_t:s0
    bash-4.2$ uname -a
    uname -a
    Linux selinux4.example.com 3.10.0-418.el7.x86_64 #1 SMP Thu May 26 20:35:02 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
    # exit
    • The id command prints real and effecitve user and group IDs, where we could see that user and group is apache. This is because cgi scripts are started as the apache owner.

    • The uname command prints system information. You can see the hostname selinux4.example.com being printed, which indicates that this is the victim system. These commands proves that the attack was successful.

Lab 2.1.3 Set SELinux to enforcing mode

The victim server (selinux4 system) has SELinux in permissive mode. Now, let’s switch SELinux to enforcing and repeat the attack.

Connect to selinux4 and switch to Enforcing mode

[root@selinux1 selinux_scripts]# ssh root@selinux4
[root@selinux4 ~]# setenforce 1
[root@selinux4 ~]# exit

Lab 2.1.4 Exploiting system with SELinux in Enforcing mode

Now, let’s repeat the attack but this time with SELinux in Enforcing mode on the victim server (selinux4 ).

Based on flow of the ShellShock attack, let’s again start listening on tcp port 9999 on one of the terminals for the selinux1 system.

[root@selinux1 selinux_scripts]# nc -lvp 9999
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::9999
Ncat: Listening on 0.0.0.0:9999

Ncat is a feature-packed networking utility which reads and writes data across networks from the command line.

Now, from another terminal for the selinux1 system, let’s run the exploit again.

[root@selinux1 selinux_scripts]# ./shellshock_exploit.sh

As you can see, this time around, there is no bash prompt on the terminal where you executed the nc command. This is because SELinux blocked this access. SELinux did its job!

Lab 2.1.5 Analyzing the SELinux denial

Let’s analyze what happened and why SELinux blocked the ShellShock exploit.

Connect to the selinux4 system from the selinux1 machine

[root@selinux1 selinux_scripts]# ssh root@selinux4
[root@selinux4 ~]# ausearch -m AVC -ts today | grep name_connect
type=AVC msg=audit(1524909646.681:86): avc:  denied  { name_connect } for  pid=2091 comm="bashbug.sh" dest=9999 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:jboss_management_port_t:s0 tclass=tcp_socket

This is the avc record from the Audit daemon. This output is saying that the cgi script, called bashbug.sh , labeled as httpd_sys_script_t tried to connect to tcp port 9999 labeled as jboss_management_port_t. Fortunately, there is no allow rules for this access. As a result, the access was denied by the kernel and SELinux mitigated this attack.

Lab 2.2 Enabling SELinux via Ansible

Goal of Lab 2.2

SELinux brings additional security for your environment and very often needs to be further modified to reflect the current environment configuration. For these cases, SELinux can be switched to Permissive mode as a debugging mode to not block basic functionality of systems. With this mode, we can run for a time period to debug all possible SELinux AVC denials, which makes turning SELinux on easier to manage. There are many ways to view or modify the installed SELinux policy.

In this lab, we used the SELinux Ansible role to distribute all needed changes in the SELinux policy to make our Apache configuration working with SELinux in Enforcing mode.

Specifically, in this lab exercise, you will enable SELinux in your environment, which consists of an Apache server using both custom and standard paths for web files . You will enable SELinux so that your Apache server is fully confined by SELinux. Specifically, you will use the SELinux system roles feature as an Ansible role to configure SELinux in an automated fashion.

Introduction and Lab Background Info

In this lab exercise, you have an environment with Apache web servers, where both default and custom paths for Apache web files are used. Specifically:

  • /var/www/html (default)

  • /var/www_new/html (custom)

These web files are accessible using tcp/80 and tcp/7070 ports on each web server.

  • selinux2.example.com:80 (default)

  • selinux2.example.com:7070 (custom)

  • selinux3.example.com:80 (default)

  • selinux3.example.com:7070 (custom)

SELinux is disabled for all web servers by default. In a fully automated fashion, you will turn SELinux on for all web servers without breaking any functionality using the SELinux system roles feature as an Ansible role.

The SELinux part of the lab environment consists of three machines:

  • selinux1, selinux1.example.com (RHEL-7 admin host)

  • selinux2, selinux2.example.com (RHEL-7 host)

  • selinux3, selinux3.example.com (RHEL-6 host)

The first selinux1.example.com host will be used as an admin interface to setup the other two hosts where we will complete all our configuration steps.

Pre-Configured Set Up Steps (Already done for you)

Important: All steps in this Pre-Configured Set Up Steps section have been already performed in the lab environment for you. They are mentioned from an informative purpose and they ONLY need to executed if you use the revert script for this lab

Viewing basic environment pre-configuration information

Let’s take a look at what has been pre-configured for you in this part of the lab exercise.

  1. If not already there, log into to the workstation bastion host as lab-user from your desktop system replacing GUID with your lab’s GUID. Use the password r3dh4t1!

    [localhost ~]$ ssh [email protected]
  2. Log into the selinux1.example.com system as root.

    [lab-user@workstation-GUID ~]# ssh [email protected]
  3. Look at the DNS records on the selinux1 server.

    [root@selinux1 ~]# cat /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.0.20 selinux2
    192.168.0.21 selinux3
  4. The ansible package has been installed on the selinux1 host.

    [root@selinux1 ~]# yum install ansible -y
  5. Enter the selinux_scripts working directory on the selinux1 host.

    [root@selinux1 ~]# cd /root/selinux_scripts
  6. Look at the created inventory file for our Ansible usage.

    [root@selinux1 selinux_scripts]# cat inventory
    selinux2
    selinux3

Pre-Configuration of Apache web servers with SELinux disabled

The apache web servers were set up using the setup_webserver.yml playbook and this playbook was executed on the selinux2 and selinux3 hosts. SELinux was also turned off.

All ansible commands below were executed from selinux1.example.com.

Test whether all servers are available via the ansible command.

  1. If not already there, log into to the workstation bastion host as lab-user from your desktop system replacing GUID with your lab’s GUID. Use the password r3dh4t1!

    [localhost ~]$ ssh [email protected]
  2. If not already root, become root and then log into the selinux1.example.com system.

    [lab-user@workstation-GUID ~]# ssh [email protected]
  3. Now let’s test which servers are accessible.

    [root@selinux1 selinux_scripts]# ansible all -i inventory -m ping -u root
  4. An Ansible script will pass all listed servers in the inventory file and will send a test to see if they are accessible. All servers should return a pong response.

    selinux2.example.com | SUCCESS => {
           	"changed": false,
            "ping": "pong"
    }
       selinux3.example.com | SUCCESS => {
           "changed": false,
            "ping": "pong"
    }
  5. Apache web servers were configured on given servers via the setup_webserver.yml playbook.

    [root@selinux1 selinux_scripts]# ansible-playbook -i inventory -u root setup-webserver.yml

The following actions were performed for all hosts mentioned in the inventory file:

  • SELinux was disabled.

  • Apache webservers were

    • installed

    • configured to listen on tcp/80 and tcp/7070 ports via the linux-sytem-roles/firewall ansible role.

    • configured to use two root directories for web files,

      /var/www/html (default)
      /var/www_new/html (custom)
    • were rebooted,

At the end we installed the setools-console package containing SELinux policy query tools which will be used for SELinux Troubleshooting.

[root@selinux1 selinux_scripts]# ssh root@selinux2
[root@selinux2 ~]# yum install setools-console
[root@selinux2 ~]# exit
[root@selinux1 selinux_scripts]# ssh root@selinux3
[root@selinux3 ~]# yum install setools-console
[root@selinux3 ~]# exit

Lab 2.2.1 Testing the pre-configured setup

In this section, we are going to test our pre-configured setup steps from before.

[root@selinux1 selinux_scripts]# hostname
selinux1.example.com
[root@selinux1 selinux_scripts]# cd /root/selinux_scripts
[root@selinux1 selinux_scripts]# curl selinux2
<h1>Default Document Root</h1>
[root@selinux1 selinux_scripts]# curl selinux2:7070
<h1>Custom Document Root</h1>
[root@selinux1 selinux_scripts]# curl selinux3
<h1>Default Document Root</h1>
[root@selinux1 selinux_scripts]# curl selinux3:7070
<h1>Custom Document Root</h1>
[root@selinux1 selinux_scripts]# ssh root@selinux2
[root@selinux2 ~]# getenforce
Disabled
[root@selinux2 ~]# exit
[root@selinux1 selinux_scripts]# ssh root@selinux3
[root@selinux3 ~]# getenforce
Disabled
[root@selinux3 ~]# exit

Lab 2.2.2 Turning SELinux On

  1. Setup SELinux to permissive mode and relabel the whole filesystem.

    [root@selinux1 selinux_scripts]# ansible-playbook -i inventory -u root enable-selinux.yml
  2. SELinux is switched to permissive mode using the enable-selinux playbook. It means that SELinux policy is enabled but is not enforced. We can use the getenforce and sestatus utility to view the current SELinux mode for our server(s).

    [root@selinux1 selinux_scripts]# ssh root@selinux2
    [root@selinux2 ~]# getenforce
    [root@selinux2 ~]# sestatus
    [root@selinux2 ~]# exit
  3. SELinux does not deny access, but denials are logged for actions that would have been denied if running in enforcing mode. In order to show logged denials for certain actions we need to run the curl command. AVC denial(s) will be generated and we can view it via the ausearch command below.

    [root@selinux1 selinux_scripts]# curl selinux2
    [root@selinux1 selinux_scripts]# curl selinux3
    [root@selinux1 selinux_scripts]# ssh root@selinux2
    [root@selinux2 ~]# ausearch -m AVC -su httpd_t -ts recent
    avc:  denied  { name_bind } for  pid=1830 comm="httpd" src=7070 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket
    avc:  denied  { read } for  pid=1831 comm="httpd" name="index.html" dev="vda3" ino=8511801 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:var_t:s0 tclass=file
    [root@selinux2 ~]# exit

Lab 2.2.3 SELinux Troubleshooting

In the previous step, we turned SELinux on and got AVC denials. Denial messages are logged when SELinux denies access. Let’s find out why we got these AVC denials.

SELinux Troubleshooting can be performed on both the selinux2 and selinux3 hosts. We will use the selinux2 host for the following examples.

  1. Log into the selinux2 host.

    [root@selinux1 selinux_scripts]# ssh root@selinux2

Lab 2.2.3.1 SELinux Port

  1. SELinux httpd_t process domain used for Apache web servers is not able to bind to tcp/7070 port by default. There is no default rule for this access in the SELinux policy on the RHEL-7 selinux2 host.

    [root@selinux2 ~]# sesearch -A -s httpd_t -t unreserved_port_t -c tcp_socket -p name_bind -C
     [root@selinux2 ~]# exit
  2. Use port instead of unreserved_port_t for this query on the selinux3 host.

     [root@selinux1] ssh selinux3
    [root@selinux3 ~]# sesearch -A -s httpd_t -t port_t -c tcp_socket -p name_bind -C
     [root@selinux3 ~]# exit
  3. Compare to that Apache webservers can bind to other ports and these SELinux port types can be assigned to our selected custom port (tcp/7070).

    [root@selinux1] ssh selinux2
    [root@selinux2 ~]# sesearch -A -s httpd_t -c tcp_socket -p name_bind

Lab 2.2.3.2 SELinux File context

  1. SELinux httpd_t process domain used for Apache webservers is not able to read a general /var content with SELinux var_t file type. There is no rule for this access in the SELinux policy.

    [root@selinux2 ~]# sesearch -A -s httpd_t -t var_t -c file -p read
  2. Compare to that Apache webservers can read a specific content with a specific SELinux file type.

    [root@selinux2 ~]# sesearch -A -s httpd_t -c file -p read
  3. We can use the matchpathcon utility to decide what should be a proper context for our alternative location for web files.

    [root@selinux2 ~]# matchpathcon /var/www/html
    /var/www/html    system_u:object_r:httpd_sys_content_t:s0
    [root@selinux2 ~]# exit

Lab 2.2.4 Viewing and Executing the SELinux setup-selinux.yml ansible playbook

We will execute an SELinux Ansible playbook which will switch SELinux to Enforcing mode and apply all needed changes for our web servers' configuration.

The playbook uses the linux-system-roles/selinux Ansible role.

Let’s take a quick look at this Ansible playbook.

  1. Make sure you are on the selinux1 system and navigate to the /root/selinux_scripts directory.

    [root@selinux1 selinux_scripts]# hostname
    selinux1.example.com
    [root@selinux1 selinux_scripts]# pwd
    /root/selinux_scripts
  2. Open the setup-selinux.yml Ansible playbook.

    [root@selinux1 selinux_scripts]# cat setup-selinux.yml
      - hosts: all
      become: true
      become_user: root
      vars:
        SELinux_type: targeted
        SELinux_mode: enforcing
        SELinux_change_running: 1
        SELinux_file_contexts:
           - { target: '/var/www_new(/.*)?', setype: 'httpd_sys_content_t', ftype: 'a' }
        SELinux_restore_dirs:
          - /var/www/html
          - /var/www_new/
        SELinux_ports:
          - { ports: '7070', proto: 'tcp', setype: 'http_port_t', state: 'present' }
      roles:
        - linux-system-roles.selinux
  3. Let’s take a closer look at the setup_selinux.yml Ansible playbook.

    • In the vars section, we are switching SELinux to Enforcing mode.

      SELinux_type: targeted
      SELinux_mode: enforcing
      SELinux_change_running: 1
    • Webservers use the custom /var/www_new/html path for web pages. SELinux labels have to be fixed for this directory and sub directories/files to reflect the default SELinux security labels for the /var/www/html location. It is ensured by the following lines in the playbook:

      SELinux_file_contexts:
          - { target: '/var/www_new(/.*)?', setype: 'httpd_sys_content_t', ftype: 'a' }
    • Once SELinux security labels are defined in the SELinux context database, these labels should be applied into extended attributes of selected files. It is ensured by the following lines in the playbook:

      SELinux_restore_dirs:
          - /var/www_new
    • All web servers are binded to the custom tcp/7070 port in our configuration. This setup needs to be reflected in a SELinux configuration. It is ensured by the following lines in the playbook:

      SELinux_ports:
          - { ports: '7070', proto: 'tcp', setype: 'http_port_t', state: 'present' }
  4. Now let’s execute this setup_selinux.yml Ansible playbook and apply these defined configurations for all servers.

    [root@selinux1 selinux_scripts]# ansible-playbook -i inventory -u root setup-selinux.yml

Lab 2.2.5 Viewing all SELinux configuration changes

  1. Now let’s test and view all our recent SELinux configuration changes.

    [root@selinux1 selinux_scripts]# ssh selinux2
    [root@selinux2 ~]# semanage export
    [root@selinux2 ~]# exit
    [root@selinux1 selinux_scripts]# ssh selinux3
    [root@selinux3 ~]# semanage -o -
    [root@selinux3 ~]# exit
  2. Check the current SELinux status for all servers..

    [root@selinux1 selinux_scripts]# ansible all -i inventory -u root -a getenforce
  3. Check the functionality with enabled SELinux.

    [root@selinux1 selinux_scripts]# curl selinux2
    [root@selinux1 selinux_scripts]# curl selinux2:7070
    [root@selinux1 selinux_scripts]# curl selinux3
    [root@selinux1 selinux_scripts]# curl selinux3:7070

Revert script

This step is required for the next lab exercise.

Also, for those of you that want to re-do this lab exercise from the beginning, you can run this revert script. All the steps in the Pre-Configured Set-Up steps section mentioned in the beginning of this lab will need to be executed , with the exception of the package installation steps.

[root@selinux1 selinux_scripts]# hostname
selinux1.example.com
[root@selinux1 selinux_scripts]# pwd
/root/selinux_scripts
[root@selinux1 selinux_scripts]# cat inventory
selinux2
selinux3
[root@selinux1 selinux_scripts]# ansible-playbook -i inventory -u root revert-all.yml

Lab 2.3 How to set up a system with SELinux confined users

Goal of Lab 2.3

As an enterprise system administrator, I may want my systems to follow the US Department of Defense STIG security rule V-71971 so that my system will be fully confined without unconfined users. I also would only want one administrator user who can become root and manage the system, and limit the access of other users.

This lab exercise is split into three steps:

  1. Confine regular Linux users

  2. Confine Linux root users

  3. Revert script

Introduction

In Red Hat Enterprise Linux, Linux users are mapped to the SELinux unconfined_u user by default. All processes run by unconfined_u are in the unconfined_t domain. This means that users can access across the system within the limits of the standard Linux DAC policy. However, a number of confined SELinux users are available in Red Hat Enterprise Linux. This means that users can be restricted to limited set of capabilities. Each Linux user is mapped to an SELinux user using SELinux policy, allowing Linux users to inherit the restrictions placed on SELinux users.

Lab 2.3.1 Confine regular Linux users

  1. Make sure that the "revert script" from previous step was executed.

    [root@selinux1 selinux_scripts]# ansible-playbook -i inventory -u root revert-all.yml
  2. All actions are performed on the selinux2 host , which is a RHEL 7.5 system.

  3. If not already there, log into to the bastion host as lab-user from your desktop system replacing GUID with your lab’s GUID. Use the password r3dh4t1!

    [localhost ~]$ ssh [email protected]
  4. Log into the selinux1.example.com system as root.

    [lab-user@workstation-GUID ~]# ssh [email protected]
    [root@selinux1 ~]# ssh root@selinux2
  5. Linux users can be assigned to SELinux users using semanage login tool. By default users are mapped to unconfined_u:

    [root@selinux2 ~]# semanage login -l

Lab 2.3.1.1 Change the default mapping

  1. In order to change mapping all Linux users we need to modify the record with default which represents all users without explicit mapping.

system_u is a special user used only for system processes and in the future will not be listed.

[root@selinux2 ~]# semanage login -m -s user_u -r s0 __default__
[root@selinux2 ~]# semanage login -l

Lab 2.3.1.2 Add a test user

  1. After this, when users (not root) logs in, their processes will run the user_t domain. Every user session but root will run with user_t:

    [root@selinux2 ~]# adduser user42
    [root@selinux2 ~]# passwd user42
    (Feel free to pick whatever password you want for user42. But, be sure to pick a password you can remember.)
    [root@selinux2 ~]# ssh user42@localhost
    user42@localhost's password:
    [user42@selinux2 ~]$ id -Z
    user_u:user_r:user_t:s0
    [user42@selinux2 ~]$ ps axZ
    LABEL                     PID TTY    STAT  TIME COMMAND
    -                           1 ?      Ss    0:00 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
    user_u:user_r:user_t:s0  2780 ?      S     0:00 sshd: user42@pts/1
    user_u:user_r:user_t:s0  2781 pts/1  Ss    0:00 -bash
    user_u:user_r:user_t:s0  2808 pts/1  R+    0:00 ps axZ
    # exit
  2. Now we can try if the user can become root.

  3. Let’s add this line to the /etc/sudoers.d/administrators file:

    user42  ALL=(ALL)       NOPASSWD: ALL
    [root@selinux2 ~]# visudo -f /etc/sudoers.d/administrators
  4. In the text editor, Press i to insert and copy and paste this line into the text editor:

    user42  ALL=(ALL)       NOPASSWD: ALL
  5. Next, press esc and then press :wq! to save and exit.

  6. Let’s confirm our changes.

    [root@selinux2 ~]# grep user42 /etc/sudoers.d/administrators
    user42  ALL=(ALL)       NOPASSWD: ALL
    [root@selinux2 ~]# ssh user42@localhost
    user42@localhost's password:
    [user42@selinux2 ~]$ sudo -i
    sudo: PERM_SUDOERS: setresuid(-1, 1, -1): Operation not permitted
    sudo: no valid sudoers sources found, quitting
    sudo: setresuid() [0, 0, 0] -> [1001, -1, -1]: Operation not permitted
    sudo: unable to initialize policy plugin
  7. And the same attempt in permissive mode:

    [user42@selinux2 ~]$ exit
    [root@selinux2 ~]# id -Z
    unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
    [root@selinux2 ~]# setenforce 0
    [root@selinux2 ~]# ssh user42@localhost
    user42@localhost's password:
    [user42@selinux2 ~]$ sudo -i
    [root@selinux2 ~]# id
    uid=0(root) gid=0(root) groups=0(root) context=user_u:user_r:user_t:s0
    [root@selinux2 ~]# id -Z
    User_u:user_r:user_t:s0
    [root@selinux2 ~]# exit
    [user42@selinux2 ~]$ exit
    [root@selinux2 ~]# setenforce 1

Since SELinux denials are not enforced in permissive mode, user42 can become root but we can see that the context stayed user_t and didn’t change to unconfined_t.

Lab 2.3.2 Confined Administrator

  1. There are two basic methods for confining the administator user:

    • Administrator can be directly mapped to sysadm_u SELinux user so that when such user logs in, the session will be run with sysadm_t domain. In this case you need to enable the ssh_sysadm_login SELinux boolean in order to allow users assigned sysadm_u to login using ssh.

      [root@selinux2 ~]# semanage user -m -R "sysadm_r secadm_r" sysadm_u
      [root@selinux2 ~]# adduser -G wheel -Z sysadm_u admin1
      [root@selinux2 ~]# passwd admin1
      (Feel free to pick whatever password you want for admin1. But, be sure to pick a password you can remember.)
      [root@selinux2 ~]# semanage login -l | grep admin
      admin1               sysadm_u             s0-s0:c0.c1023       *
      [root@selinux2 ~]# setsebool -P ssh_sysadm_login on
      [root@selinux2 ~]# ssh admin1@localhost
      [admin1@selinux2 ~]$ id -Z
      sysadm_u:sysadm_r:sysadm_t:s0-s0:c0.c1023
      [admin1@selinux2 ~]$ sudo -i
      [sudo] password for admin1:
      [root@selinux2 ~]# id -Z
      sysadm_u:sysadm_r:sysadm_t:s0-s0:c0.c1023
      • Now we can try to perform admin’s operation which can be executed only by admin SELinux users.

        [root@selinux2 ~]# systemctl restart sshd
        [root@selinux2 ~]# exit
        [admin1@selinux2 ~]# exit
    • The other way is to assign u administer users to staff_u and configure sudo so that particular users can gain SELinux administrator role.

      [root@selinux2 ~]# adduser -G wheel -Z staff_u admin2
      [root@selinux2 ~]# passwd admin2
      (Feel free to pick whatever password you want for admin1. But, be sure to pick a password you can remember.)
      [root@selinux2 ~]# semanage login -l | grep admin
      admin1               sysadm_u             s0-s0:c0.c1023       *
      admin2               staff_u              s0-s0:c0.c1023       *
      [root@selinux2 ~]# ssh admin2@localhost
      [admin2@selinux2 ~]$ id -Z
      staff_u:staff_r:staff_t:s0-s0:c0.c1023
      [admin2@selinux2 ~]$ sudo -i
      [sudo] password for admin2:
      -bash: /root/.bash_profile: Permission denied
      -bash-4.2# id -Z
      staff_u:staff_r:staff_t:s0-s0:c0.c1023
  2. Now we can again try to perform administrator’s operation which can be executed only by administrator SELinux users.

    -bash-4.2# systemctl restart sshd
    Failed to restart sshd.service: Access denied
    See system logs and 'systemctl status sshd.service' for details.
    -bash-4.2# exit
    [admin2@selinux2 ~]$ exit
  3. To allow admin2 user to gain SELinux administrator role you need to add the following rule to sudoers.

    [root@selinux2 ~]# visudo -f /etc/sudoers.d/administrators
  4. Append following line to end of file. In the text editor, Press o then copy and paste these lines below into the text editor. Then, press esc and then press :wq! to save and exit.

    admin2  ALL=(ALL)  TYPE=sysadm_t ROLE=sysadm_r    ALL
    admin2  ALL=(ALL)  TYPE=secadm_t ROLE=secadm_r /usr/sbin/semanage,/usr/sbin/semodule
  5. Admin2 can gain administrator role using sudo now.

    [root@selinux2 ~]# ssh admin2@localhost
    [admin2@selinux2 ~]$ sudo -i
    [sudo] password for admin2:
    [root@selinux2 ~]# id -Z
    staff_u:sysadm_r:sysadm_t:s0-s0:c0.c1023
    [root@selinux2 ~]# systemctl restart sshd
    [root@selinux2 ~]#
    [root@selinux2 ~]# exit
    [admin2@selinux2 ~]# exit

Revert script

There is a revert script to restore the default SELinux Users configuration. If you want to run this revert script, run it on the selinux2 host.

[root@selinux2 ~]# hostname
selinux2.example.com
[root@selinux2 ~]# cd /root
[root@selinux2 ~]# sh confined_users_revert.sh