Deploying Wordpress with SELinux enabled

SELinux can be a pain to work with at times, but that does not justify setting it to permissive mode or disabling it. Wordpress’ popularity makes it a script kiddie’ favourite target. Other than always keeping your Wordpress instance updated, you should be running httpd/Apache in a confined SELinux domain. It reduces the damage someone can do, if (at all) they manage to upload and execute files onto your webserver (ever noticed those random named, hidden binary files in /tmp owned by the user running your webserver ? )

Assumptions

  • SELinux is installed and enabled
  • Wordpress is unzipped into /var/www/html/
  • This has been tested on an Amazon AMI, but should work for all distributions that support SELinux

Getting started

Lets make sure that the stage is setup correctly

Ensuring SELinux is up and running in enforcing mode

sestatus must report the below output. If it doesn’t - you either have it disabled or running in permissive mode. Don’t proceed until you have output that looks exactly like below

[ec2-user@ip-172-30-10-10 ~]$ sestatus  | grep 'SELinux status\|Current mode'
SELinux status:                 enabled
Current mode:                   enforcing

Ensuring httpd is running in confined domain httpd_t

httpd must be running in domain httpd_t. If its unconfined_t then its running in the wrong domain and rules meant to secure it won’t apply.

[ec2-user@ip-172-30-10-10  ~]$ ps uax -Z | grep httpd
unconfined_u:system_r:httpd_t:s0 root    22884  0.0  1.0 324744 11188 ?      Ss   Jan15   0:01 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 apache  22887  0.0  2.7 342656 28556 ?      S    Jan15   0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 apache  23138  0.0  0.6 324876  6812 ?      S    Jan15   0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 apache  23206  0.0  0.5 324744  6064 ?      S    Jan15   0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 apache  23483  0.0  0.5 324744  6064 ?      S    Jan15   0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 apache  23486  0.0  0.5 324744  6064 ?      S    Jan15   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 ec2-user 24944 0.0  0.0 110256 644 pts/0 S+ 03:58   0:00 grep httpd

If your /usr/sbin/httpd is running in domain unconfined_t instead of httpd_t, then your context of /etc/init.d/httpd or /usr/sbin/httpd has somehow changed. Restoring the context should fix it

To restore context run restorecon

[ec2-user@ip-172-30-10-10 ~]$ sudo restorecon -v  /etc/init.d/httpd /usr/sbin/httpd

Allowing httpd to connect to remote database.

If you are hosting your database on a remote server, httpd must be allowed to connect to it.

[ec2-user@ip-172-30-10-10 ~]$ sudo setsebool -P  httpd_can_network_connect_db 1

Note: Connection to local database i.e. localhost:3306 does not need this to be set to true

Whitelisting /var/www/html/wp-content/uploads/ for write access

When uploading images and other media from wp-admin, httpd needs access to write to wordpress’ upload directory. By default all files and directories in /var/www/html are labeled with type httpd_sys_content_t. In this context files are not writeable by process httpd running in domain httpd_t. Changing this to type httpd_sys_rw_content_t will allow write/create/delete access

[ec2-user@ip-172-30-10-10 ~]$ sudo semanage   fcontext -f ""  -a -t  httpd_sys_rw_content_t '/var/www/html/wp-content/uploads(/.*)?'

To apply the change in context for directories and files in /var/www/html/wp-content/uploads/* use restorecon

[ec2-user@ip-172-30-10-10 ~]# restorecon -Rv  /var/www/html
[ec2-user@ip-172-30-10-10 ~]# ls -all -Z /var/www/html/wp-content/uploads/
drwxr-xr-x. apache apache unconfined_u:object_r:httpd_sys_rw_content_t:s0 .
drwxr-xr-x. nobody  65534 unconfined_u:object_r:httpd_sys_content_t:s0 ..
drwxr-xr-x. apache apache unconfined_u:object_r:httpd_sys_rw_content_t:s0 2015

Special note about boolean httpd_unified on CentOS/RHEL distributions

By default httpd_unified is enabled on CentOS/RHEL systems older than version 7. This allows Apache write access to files and directories labeled with context httpd_sys_content_t. We want to make sure that Apache can only write to the directory/files we whitelisted (/var/www/html/wp-content/uploads/). Turning this off is highly recommended to control writes to the filesystem and within the DocRoot

[ec2-user@ip-172-30-10-10 ~]# sudo setsebool -P  httpd_unified  0

Debugging

  • When working with selinux, tailing /var/log/audit/audit.log is always helpful
  • Switch to permissive mode and see if something that breaks while in enforcing mode. This should tell you if SELinux is breaking things.

Exploring other interfaces exposed by selinux_httpd

A list of all boolean interfaces that are exposed by selinux_httpd can be listed using getsebool. An explanation of boolean interface is documented on selinux_httpd’ man page

[ec2-user@ip-172-30-10-10 ~]$ sudo getsebool -a | grep httpd
allow_httpd_anon_write --> off
allow_httpd_mod_auth_ntlm_winbind --> off
allow_httpd_mod_auth_pam --> off
allow_httpd_sys_script_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> on
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_enable_cgi --> on
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_graceful_shutdown --> off
httpd_manage_ipa --> off
httpd_read_user_content --> off
httpd_run_stickshift --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_tmp_exec --> off
httpd_tty_comm --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_fusefs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_verify_dns --> off

Putting it all together

At this point, you should have a working instance of Wordpress served by httpd running in confined domain httpd_t. It should minimised the damage that someone can do, if at all they manage to upload files to your server and attempt to execute them.

These simple steps should keep your Wordpress instance fairly secure and the random binary files in /tmp at bay.

Further reading