Bookmark this page

Guided Exercise: Enabling SELinux from the Disabled State

In this exercise, you will enable enforcing mode for SELinux on a server that has been running with SELinux disabled.

Outcomes

You should be able to:

  • Put a system that is running with SELinux in disabled mode into permissive mode.

  • Ensure the audit system is running, find AVCs due to missing or incorrect labels on files and ports, and resolve them.

  • Put the system into enforcing mode and confirm its correct operation.

Confirm that the workstation, serverc, and serverd machines are started.

Log in to workstation as student using student as the password. On workstation, run lab selinux-mode setup to verify that the environment is ready. This script also puts serverc and serverd in SELinux disabled mode and deploys a test application on those systems.

[student@workstation ~]$ lab selinux-mode setup
  1. The Apache HTTP Server on serverc hosts the following web application:

    • The /data/www/html/speed.html web page, which is the main application page. It contains a form through which a user can test the response time of a remote web server. This form calls the speed.py CGI script.

    • The speed.py CGI script, in /var/www/cgi-bin/, runs the curl command to measure the response time of the given remote web server.

    • The httpd server listens on port 4242 and its DocumentRoot parameter is set to /data/www/html/.

    • A security issue in the application allows malicious users to run arbitrary commands on the system.

    Confirm that this application works as expected when SELinux is in the disabled mode. Try to exploit the security bug.

    1. On workstation, open Firefox and browse to http://serverc.lab.example.com:4242/speed.html.

    2. As a test, in the Web server to test field, enter classroom.example.com to measure the response time of the web server running on the classroom system. Click Submit.

      The application returns the web server response time. This test confirms that the application is working as expected.

    3. Exploit the security bug. Click the Go back link to go back to the main page. In the Web server to test field, enter the following string.

      classroom.example.com ; mail -s 'I love you, Student' student@serverc

      The exploit allows a user to enter an arbitrary command at the end of the request. The command in this example sends an unsolicited and anonymous email to the student user on serverc.

      Click Submit.

    4. Confirm that student has received a new email. Log in to serverc as student. No password is required.

      [student@workstation ~]$ ssh student@serverc
      [student@serverc ~]$ 

      Run the mail command to confirm that the unsolicited email is in the student user's inbox.

      [student@serverc ~]$ mail
      Heirloom Mail version 12.5 7/5/10.  Type ? for help.
      "/var/spool/mail/student": 1 message 1 unread
      >U  1 Apache        Fri Jul 20 04:24  19/669   "I love you, Student"
      & 1
      Message  1:
      From apache@serverc.lab.example.com  Fri Jul 20 04:24:23 2018
      Return-Path: <apache@serverc.lab.example.com>
      X-Original-To: student@serverc
      Delivered-To: student@serverc.lab.example.com
      Date: Fri, 20 Jul 2018 04:24:22 -0400
      To: student@serverc.lab.example.com
      Subject: I love you, Student
      User-Agent: Heirloom mailx 12.5 7/5/10
      Content-Type: text/plain; charset=us-ascii
      From: apache@serverc.lab.example.com (Apache)
      Status: RO
      
      
      & q
      Held 1 message in /var/spool/mail/student
  2. The development team is working on fixing the security flaw, but in the meantime put your system in SELinux permissive mode. In this debugging mode, the application is still available while you fix the potential SELinux denials. When SELinux does not report any more errors, you can switch the system to the enforcing mode.

    1. Confirm the actual SELinux mode.

      [student@serverc ~]$ getenforce
      Disabled
    2. Use the sudo -i command to switch identity to the root user. Use student as the password.

      [student@serverc ~]$ sudo -i
      [sudo] password for student: student
      [root@serverc ~]# 
    3. Edit the /etc/selinux/config file and set the SELINUX variable to permissive.

      [root@serverc ~]# vim /etc/selinux/config
      ...output omitted...
      SELINUX=permissive
      ...output omitted...
    4. To switch from disabled to permissive or enforcing, you need to reboot the system. In disabled mode, the system does not maintain the labels on files and directories. Consequently, create the .autorelabel file at the root of the file system to force a complete relabel during the next boot.

      [root@serverc ~]# touch /.autorelabel
      [root@serverc ~]# systemctl reboot
      Connection to serverc closed by remote host.
      Connection to serverc closed.
      [student@workstation ~]$ 
  3. Wait for serverc to reboot and confirm that the application still works. Remember that in permissive mode, SELinux reports the denials but does not enforce them.

    1. Log in to serverc as student. No password is required.

      [student@workstation ~]$ ssh student@serverc
      [student@serverc ~]$ 
    2. Confirm that SELinux is now in permissive mode.

      [student@serverc ~]$ getenforce
      Permissive
    3. To confirm that the application works, use Firefox on workstation and browse to http://serverc.lab.example.com:4242/speed.html. Enter classroom.example.com in the Web server to test field and click Submit.

      The application returns the web server response time.

  4. Confirm that the auditd service is running, search for SELinux denials in its log file, and fix the reported issues.

    1. On serverc, use the sudo -i command to switch identity to the root user. Use student as the password.

      [student@serverc ~]$ sudo -i
      [sudo] password for student: student
      [root@serverc ~]# 
    2. Use the systemctl command to determine if the auditd service is running.

      [root@serverc ~]# systemctl is-active auditd
      active

      Note

      The audit package is installed by default on Red Hat Enterprise Linux systems and the auditd service is enabled by default.

    3. Because the auditd service is running, SELinux log messages are in the /var/log/audit/audit.log log file. Use the grep command to list the SELinux denials.

      [root@serverc ~]# grep denied /var/log/audit/audit.log
      type=AVC msg=audit(1532077511.575:15): avc:  denied  { open } for  pid=607 comm="audispd" path="/etc/ld.so.cache" dev="vda1" ino=191606 scontext=system_u:system_r:audisp_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file
      type=AVC msg=audit(1532077511.575:16): avc:  denied  { getattr } for  pid=607 comm="audispd" path="/etc/ld.so.cache" dev="vda1" ino=191606 scontext=system_u:system_r:audisp_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file
      type=AVC msg=audit(1532077570.615:105): avc:  denied  { name_bind } for  pid=1036 comm="httpd" src=4242 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket
      type=AVC msg=audit(1532077947.699:142): avc:  denied  { getattr } for  pid=1078 comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      type=AVC msg=audit(1532077947.702:143): avc:  denied  { read } for  pid=1078 comm="httpd" name="speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      type=AVC msg=audit(1532077947.702:143): avc:  denied  { open } for  pid=1078 comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      type=AVC msg=audit(1532077956.965:144): avc:  denied  { name_connect } for  pid=1228 comm="curl" dest=80 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket

      Alternatively, you can use the ausearch command to get a more readable output. The -m AVC and -ts boot options filter the output to only display the messages from SELinux, and since the last system boot.

      [root@serverc ~]# ausearch -m AVC -ts boot
      ----
      time->Fri Jul 20 05:06:10 2018
      type=PROCTITLE msg=audit(1532077570.615:105): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
      type=SYSCALL msg=audit(1532077570.615:105): arch=c000003e syscall=49 success=yes exit=0 a0=4 a1=5637fe33fdb8 a2=1c a3=7ffe76a479a0 items=0 ppid=1 pid=1036 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
      type=AVC msg=audit(1532077570.615:105): avc:  denied  { name_bind } for  pid=1036 comm="httpd" src=4242 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket
      ----
      time->Fri Jul 20 05:12:27 2018
      type=PROCTITLE msg=audit(1532077947.699:142): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
      type=SYSCALL msg=audit(1532077947.699:142): arch=c000003e syscall=4 success=yes exit=0 a0=5637fe3f1758 a1=7ffe76a47830 a2=7ffe76a47830 a3=7fb3f23bd712 items=0 ppid=1036 pid=1078 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
      type=AVC msg=audit(1532077947.699:142): avc:  denied  { getattr } for  pid=1078 comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      ----
      time->Fri Jul 20 05:12:27 2018
      type=PROCTITLE msg=audit(1532077947.702:143): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
      type=SYSCALL msg=audit(1532077947.702:143): arch=c000003e syscall=2 success=yes exit=10 a0=5637fe3f1828 a1=80000 a2=0 a3=7ffe76a474d0 items=0 ppid=1036 pid=1078 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
      type=AVC msg=audit(1532077947.702:143): avc:  denied  { open } for  pid=1078 comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      type=AVC msg=audit(1532077947.702:143): avc:  denied  { read } for  pid=1078 comm="httpd" name="speed.html" dev="vda1" ino=8443147 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file
      ----
      time->Fri Jul 20 05:12:36 2018
      type=PROCTITLE msg=audit(1532077956.965:144): proctitle=2F75...703A
      type=SYSCALL msg=audit(1532077956.965:144): arch=c000003e syscall=42 success=no exit=-115 a0=3 a1=7fff60b95bb0 a2=10 a3=7fff60b95610 items=0 ppid=1227 pid=1228 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="curl" exe="/usr/bin/curl" subj=system_u:system_r:httpd_sys_script_t:s0 key=(null)
      type=AVC msg=audit(1532077956.965:144): avc:  denied  { name_connect } for  pid=1228 comm="curl" dest=80 scontext=system_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket
    4. The first error indicates that SELinux denies httpd from binding to port 4242.

      Use the semanage port -l command to get the list of allowed ports for httpd.

      [root@serverc ~]# semanage port -l | grep http
      http_cache_port_t     tcp    8080, 8118, 8123, 10001-10010
      http_cache_port_t     udp    3130
      http_port_t           tcp    80, 81, 443, 488, 8008, 8009, 8443, 9000
      pegasus_http_port_t   tcp    5988
      pegasus_https_port_t  tcp    5989

      Use the semanage port -a command to add port 4242 to the http_port_t port type list.

      [root@serverc ~]# semanage port -a -t http_port_t -p tcp 4242
      [root@serverc ~]# semanage port -l | grep ^http_port_t
      http_port_t      tcp   4242, 80, 81, 443, 488, 8008, 8009, 8443, 9000
    5. The next three errors indicate that SELinux does not allow the httpd process to access, open, or read the /data/www/html/speed.html file. This is because the httpd DocumentRoot parameter points to this custom /data/www/html directory for which the policy does not have a rule.

      Confirm that no rule exists for the /data directory.

      [root@serverc ~]# semanage fcontext -l | grep ^/data
      [root@serverc ~]# 
    6. To create a new rule for the custom /data/www/html directory, you need to identify which context type to set. For that, get the context of the default DocumentRoot, /var/www/html.

      [root@serverc ~]# ls -Zd /var/www/html
      drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html
    7. Use the semanage fcontext -a command to add a new rule for the /data/www/html directory.

      [root@serverc ~]# semanage fcontext -a -t httpd_sys_content_t \
      > '/data/www/html(/.*)?'
      [root@serverc ~]# 

      In the previous command, you do not define the context type for the /data/www/html/speed.html file itself, but for its parent directory, /data/www/html. This way, if you add new files in /data/www/html, they automatically inherit the correct context type.

      The EXAMPLE section of the semanage-fcontext(8) manual page gives an example of the semanage fcontext -a command.

    8. Recursively restore the context of the /data/www/html directory.

      [root@serverc ~]# restorecon -Rv /data/www/html
      restorecon reset /data/www/html context system_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0
      restorecon reset /data/www/html/speed.html context system_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0
    9. The last denial indicates that SELinux does not allow the curl command to establish a network connection. The speed.py CGI script uses the curl command to connect and measure the access time of remote web servers.

      By default, SELinux does not allow the httpd_t domain type, used by the httpd daemon and its children, to establish network connections. You can however set the httpd_can_network_connect SELinux Boolean to on to allow this type of access.

      To get more details on this Boolean, install the policycoreutils-devel package, use the sepolicy manpage -a command to build the SELinux manual pages, and open the httpd_selinux(8) manual page.

      [root@serverc ~]# yum install policycoreutils-devel
      ...output omitted...
      Is this ok [y/d/N]: y
      ...output omitted...
      Complete!
      [root@serverc ~]# sepolicy manpage -a
      ...output omitted...
      /tmp/httpd_selinux.8
      ...output omitted...
      [root@serverc ~]# man /tmp/httpd_selinux.8
      ...output omitted...
    10. Use the setsebool command to set the httpd_can_network_connect Boolean to on.

      [root@serverc ~]# setsebool -P httpd_can_network_connect on
      [root@serverc ~]# 
  5. Confirm that SELinux does not generate any more denials for the web application.

    1. On serverc, use the tailf command to follow the denials in /var/log/audit/audit.log.

      [root@serverc ~]# tailf /var/log/audit/audit.log | grep denied
       
    2. Restart httpd to confirm that it can bind to port 4242 without being denied by SELinux.

      Open a new terminal on workstation and log in to serverc as student. Use the sudo command to execute the systemctl restart httpd command. Use student as the password. Log out when done.

      [student@workstation ~]$ ssh student@serverc
      [student@serverc ~]$ sudo systemctl restart httpd
      [sudo] password for student: student
      [student@serverc ~]$ 

      In the first terminal, where the tailf command is running, confirm there are no new denials.

    3. On workstation, use Firefox to browse to http://serverc.lab.example.com:4242/speed.html. In the Web server to test field, enter classroom.example.com and click Submit. The application returns the web server response time.

      In the terminal where the tailf command is running, confirm there are no new denials.

  6. Put the system into enforcing mode and confirm correct operation.

    1. Press Ctrl+C to stop the tailf command, and use the setenforce 1 command to put the system into enforcing mode.

      ^C
      [root@serverc ~]# setenforce 1
      [root@serverc ~]# getenforce
      Enforcing
    2. Confirm that the application still works.

      On workstation, use Firefox again to browse to http://serverc.lab.example.com:4242/speed.html. In the Web server to test field, enter classroom.example.com and click Submit. The application returns the web server response time.

    3. Persistently set the SELinux mode by editing the /etc/selinux/config file and setting the SELINUX variable to enforcing.

      [root@serverc ~]# vim /etc/selinux/config
      ...output omitted...
      SELINUX=enforcing
      ...output omitted...
  7. Try to exploit the security bug by sending an email to student.

    1. In Firefox browse to http://serverc.lab.example.com:4242/speed.html. In the Web server to test field, enter the following string.

      classroom.example.com ; mail -s 'I still love you, Student' student@serverc

      Click Submit.

    2. Confirm that this time student has not received the email. When done, log out from serverc.

      [root@serverc ~]# logout
      [student@serverc ~]$ mail
      Heirloom Mail version 12.5 7/5/10.  Type ? for help.
      "/var/spool/mail/student": 1 message
      > 1 Apache                Fri Jul 20 04:24  19/670   "I love you, Student"
      & q
      Held 1 message in /var/spool/mail/student
      [root@serverc ~]# logout
      [student@serverc ~]$ logout
      [student@workstation ~]$ 

      Notice that only the initial email is in the inbox.

      Note

      SELinux mitigates the risks while the development team is fixing the issue. Everything that SELinux allows to the httpd_t domain, which is the SELinux domain for the httpd daemon, can still be exploited.

  8. serverd is hosting the same web application and is also in disabled mode. Rather than repeating the same manual steps you did for serverc, use the Ansible Playbook that the exercise setup script deployed on workstation in /home/student/RH415/labs/selinux-mode/.

    Review and run the playbook to put SELinux in enforcing mode on serverd.

    1. On workstation, review the /home/student/RH415/labs/selinux-mode/speed-selinux.yml playbook.

      [student@workstation ~]$ cd ~/RH415/labs/selinux-mode
      [student@workstation selinux-mode]$ cat speed-selinux.yml
      ...output omitted...

      The first play, Change SELinux mode to Enforcing, sets the SELinux mode to enforcing and reboots the system. It calls the linux-system-roles.selinux role, which is provided by the rhel-system-roles package and is part of the Red Hat Enterprise Linux System Roles. By defining the SELinux_type and SELinux_mode variables, the role configures the SELinux mode.

      The second play, Configure SELinux for the Speed application, also uses the linux-system-roles.selinux role. The SELinux_file_contexts, SELinux_restore_dirs, SELinux_ports, and SELinux_booleans variables tell the role what to configure.

      SELinux_file_contexts

      List of file contexts to define. Works like the semanage fcontext -a command.

      SELinux_restore_dirs

      Relabel the given files and directories. This works like the restorecon command.

      SELinux_ports

      List of ports to associate with SELinux port types. Works like the semanage port -a command.

      SELinux_booleans

      List of Booleans to enable or disable. Works like the setsebool command.

    2. Use the ansible-playbook command to run the playbook.

      [student@workstation selinux-mode]$ ansible-playbook speed-selinux.yml
      ...output omitted...
      PLAY RECAP ***********************************************************
      serverd.lab.example.com : ok=18  changed=12  unreachable=0   failed=0
    3. Confirm that serverd is now in enforcing mode.

      Log in to serverd as student. No password is required. Use the getenforce command to get the current SELinux mode. Log out of serverd when done.

      [student@workstation selinux-mode]$ ssh student@serverd
      [student@serverd ~]$ getenforce
      Enforcing
      [student@serverd ~]$ logout
      [student@workstation selinux-mode]$ 
    4. Confirm that the web application is working.

      On workstation, open Firefox and browse to http://serverd.lab.example.com:4242/speed.html. In the Web server to test field, enter classroom.example.com and click Submit. The application returns the web server response time. This test confirms that the application is working as expected.

Cleanup

On workstation, run the lab selinux-mode cleanup script to clean up this exercise.

[student@workstation ~]$ lab selinux-mode cleanup

This concludes the guided exercise.

Revision: rh415-7.5-813735c