Kirill Ermakov recently posted a
study he did of SELinux protections against a vulnerable Apache server.
After reading the study you might come a way with the idea that SELinux did not block anything. After all it allowed the hacked process to read /etc/passwd. SELinux also allowed a hacked Apache to upload a file and execute it.
This points out what most people do not understand about SELinux. SELinux does not necessarily block errors in applications from happening. SELinux will just contain them. If you are able to subvert the Apache application then you can become the Apache application and will have the rights allowed to the apache application. In his examples he was able to take over the Apache server and do what an apache server needs to do, including reading the /etc/passwd file. A better test would be:
- Try to connect to a few network ports like the mail port - Out of the box we should not allow Apache to connect to many network ports.
- Read /secrets/mysecrets - Random content on the file system should not be readable by Apache
- Read /home/dwalsh/creditcard.txt - Random content in a users home dir should not be readable by apace
- Read /var/lib/mysql/mysqld.data. - Database data should not be readable by Apache except if allowed through a constricted path like a unix domain socket.
- Try to run su or sudo, or strace, or network sniffer.
All things the Apache server should not be allowed to do.
If an Apache server has a bug in its code, then it can be owned whether or not SELinux is in enforcing mode, the goal is to confine the attacker to just the Apache data and not allow him to attack other data or processes on the system.
Apache Booleans Now lets look further at Apache SELinux policy configuration. A while ago I wrote a blog on
"Security vs Usability", in which I explained the continuing conflict between setting up a machine with security as tight as possible, but not so tight as forcing people to turn the security off. When we ship SELinux policy we have to make compromises on security, to avoid the "Just turn it off crowd".
Lets look at some of these compromises, and maybe explain how you could tighten the security in your Apache.
Out of the box SELinux in RHEL6 has the following boolean settings for an Apache server.
On RHEL6 we have
# semanage boolean -l | grep httpd | grep -v off
httpd_enable_cgi (on , on) Allow httpd cgi support
httpd_dbus_avahi (on , on) Allow Apache to communicate with avahi service via dbus
httpd_unified (on , on) Unify HTTPD handling of all content files.
httpd_builtin_scripting (on , on) Allow httpd to use built in scripting (usually php)
httpd_tty_comm (on , on) Unify HTTPD to communicate with the terminal. Needed for entering the passphrase for certificates at the terminal.On RHEL7 and Fedora we have
# semanage boolean -l | grep httpd | grep -v off
httpd_enable_cgi (on , on) Allow httpd cgi support
httpd_graceful_shutdown (on , on) Allow HTTPD to connect to port 80 for graceful shutdown
httpd_builtin_scripting (on , on) Allow httpd to use built in scripting (usually php)I was interested on how he was able to execute tmp_t content.
# sesearch -A -s httpd_t -t httpd_tmp_t -p execute -C
Found 1 semantic av rules:
DT allow httpd_t httpd_tmp_t : file { ioctl read getattr lock execute
execute_no_trans open } ; [ httpd_tmp_exec httpd_builtin_scripting && ]
# sesearch -A -s httpd_sys_script_t -t httpd_tmp_t -p execute -C
Found 1 semantic av rules:
DT allow httpd_sys_script_t httpd_tmp_t : file { ioctl read getattr lock execute execute_no_trans open } ; [ httpd_tmp_exec httpd_enable_cgi && ]Reading this, it looks like SELinux should have blocked the ability for the Apache process or a cgi script to execute the content by default. IE You would need to turn on the httpd_tmp_exec boolean as well as the httpd_enable_cgi boolean.
But examining further the booleans, I wanted to know what content could httpd_t (Apache) or httpd_sys_script_t (Apache CGI Scripts) could execute and write.
# sesearch -A -s httpd_sys_script_t -t httpd_sys_content_t -p execute -C
Found 3 semantic av rules:
allow httpd_sys_script_t exec_type : file { ioctl read getattr lock execute execute_no_trans open } ;
allow httpd_sys_script_t httpd_sys_content_t : file { ioctl read getattr lock execute entrypoint open } ;
ET allow httpd_sys_script_t httpd_sys_content_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ; [ httpd_enable_cgi httpd_unified && ]So the problem here is actually httpd_unified. httpd_unified basically says to SELinux allow Apache processes to treat all Apache content with the same rules. In RHEL7 we feel users are familiar enough with SELinux to disable the httpd_unified boolean by default. If this boolean is off, then users would have to label files/directories as httpd_sys_content_rw_t if they wanted Apache to be able to write to a directory rather then the read/only label of httpd_sys_content_t. With the boolean on, Apache processes can read/write/execute all httpd_sys_content* labels.
If you are not uploading data to Apache then it is a good idea to turn off this boolean.
# setsebool -P httpd_unified 0Now lets look at other booleans that are turned on by default in RHEL6. (And RHEL7 for that matter).
httpd_enable_cgiThis boolean enables your Apache server to run cgi scripts. We leave this on by default because out of the box, any person running Apache would blow up with a permission denied when they tried to execute a cgi script. If you were not running cgi scripts, it would be a good idea to turn this off.
# setsebool -P httpd_enable_cgi 0httpd_builtin_scriptingThis boolean your Apache server to run builtin scripting, mod_php, mod_python, mod_perl ...
We leave this on by default because out of the box, any person running Apache would blow up with a permission denied when they tried to execute a php script.
If you are just allowing users to view Apache content, then you really should turn off both of these booleans.
# setsebool -P httpd_builtin_scripting 0httpd_tty_comm This boolean allows httpd to talk to the terminal that launches it. The risk here is a hacked apache server could trick an admin into entering his password, by putting a passwd: prompt on the screen and then reading the admins commands. This access is necessary for people who setup apache servers which require a passwd from the admin when they start, it also allow apache to output errors to the screen, like the configuration is screwed up. In Fedora and RHEL7 this output is handled by systemd, so this access is no longer needed, and can be disabled by default. If your apache server does not require a password at start and you know that your config is correct you should turn this boolean off.
# setsebool -P httpd_tty_comm 0httpd_dbus_avahi
This boolean allows apache to communicate with the avahi daemon over DBUS. This boolean should have been disabled by default, but most likely does not add much risk. It is turned off by default in Fedora and RHEL7.
# setsebool -P httpd_dbus_avahi 0Bottom line as people grow to peoples understanding of SELinux, we can slowly tighten up the controls...