This course is using an outdated version of the technology and is now considered to be Legacy content. It will be removed from our catalog on June 28, 2024. Please be sure to complete your course and finish any remaining labs before that date. We recommend moving to version 9.2, which is the latest version currently available.
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
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.
On workstation, open Firefox and browse to http://serverc.lab.example.com:4242/speed.html.
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 .
The application returns the web server response time. This test confirms that the application is working as expected.
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 .
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 ~]$Fri Jul 20 04:2419/669 "I love you, Student" &1Message 1: Fromapache@serverc.lab.example.comFri Jul 20 04:24:23 2018Return-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 -0400To: 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 &qHeld 1 message in /var/spool/mail/student
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.
Confirm the actual SELinux mode.
[student@serverc ~]$getenforceDisabled
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 ~]#
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...
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 rebootConnection to serverc closed by remote host. Connection to serverc closed.[student@workstation ~]$
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.
Log in to serverc as student.
No password is required.
[student@workstation ~]$ssh student@serverc[student@serverc ~]$
Confirm that SELinux is now in permissive mode.
[student@serverc ~]$getenforcePermissive
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 .
The application returns the web server response time.
Confirm that the auditd service is running, search for SELinux denials in its log file, and fix the reported issues.
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 ~]#
Use the systemctl command to determine if the auditd service is running.
[root@serverc ~]#systemctl is-active auditdactive
The audit package is installed by default on Red Hat Enterprise Linux systems and the auditd service is enabled by default.
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.logtype=AVC msg=audit(1532077511.575:15): avc: denied { open } for pid=607comm="audispd" path="/etc/ld.so.cache" dev="vda1" ino=191606scontext=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=607comm="audispd" path="/etc/ld.so.cache" dev="vda1" ino=191606scontext=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=1036comm="httpd" src=4242scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_sockettype=AVC msg=audit(1532077947.699:142): avc: denied {getattr} for pid=1078comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147scontext=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=1078comm="httpd" name="speed.html" dev="vda1" ino=8443147scontext=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=1078comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147scontext=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=1228comm="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 2018type=PROCTITLE msg=audit(1532077570.615:105): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44type=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=1036auid=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=1036comm="httpd" src=4242scontext=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 2018type=PROCTITLE msg=audit(1532077947.699:142): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44type=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=1036pid=1078auid=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=1078comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file ---- time->Fri Jul 20 05:12:27 2018type=PROCTITLE msg=audit(1532077947.702:143): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44type=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=1036pid=1078auid=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=1078comm="httpd" path="/data/www/html/speed.html" dev="vda1" ino=8443147scontext=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=1078comm="httpd" name="speed.html" dev="vda1" ino=8443147scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:default_t:s0 tclass=file ---- time->Fri Jul 20 05:12:36 2018type=PROCTITLE msg=audit(1532077956.965:144): proctitle=2F75...703Atype=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=1227pid=1228auid=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=1228comm="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
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 httphttp_cache_port_t tcp 8080, 8118, 8123, 10001-10010 http_cache_port_t udp 3130http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000pegasus_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_thttp_port_t tcp4242, 80, 81, 443, 488, 8008, 8009, 8443, 9000
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 ~]#
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/htmldrwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html
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.
Recursively restore the context of the /data/www/html directory.
[root@serverc ~]#restorecon -Rv /data/www/htmlrestorecon 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
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...
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 ~]#
Confirm that SELinux does not generate any more denials for the web application.
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
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.
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 .
The application returns the web server response time.
In the terminal where the tailf command is running, confirm there are no new denials.
Put the system into enforcing mode and confirm correct operation.
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 ~]#getenforceEnforcing
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 .
The application returns the web server response time.
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...
Try to exploit the security bug by sending an email to student.
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 .
Confirm that this time student has not received the email.
When done, log out from serverc.
[root@serverc ~]#logout[student@serverc ~]$>1 Apache&Fri Jul 20 04:2419/670 "I love you, Student"qHeld 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.
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.
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.
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.
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
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 ~]$getenforceEnforcing[student@serverd ~]$logout[student@workstation selinux-mode]$
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 .
The application returns the web server response time.
This test confirms that the application is working as expected.