SELinux Targeted Policy

(Featured image is a PostScript file written to exploit servers running GhostScript. It was used to get an shell on our servers to mine bitcoin)

Default SELinux policy enabled in CentOS/RHEL is targeted policy. Processes that are targeted run in a confined domain. Other processes are run in unconfined domain. Processes runs on unconfined domain still confined such that they can not do things like allocating writable memory and execute it. These are prevented setting Booleans. We will talk about Booleans later. For now, they are settings which can me modified at runtime to change SELinux policy.

Confined Processes:

Confined processes are runs on its own domain such that compromising that process will limit the compromise to the system. Processes like SSH, HTTPD by default runs on its own domain.

Verify SELinux Status

Use sestatus to see the SELinux status.

$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 31

Above output says, SELinux is enabled and is on enforcing mode and using targeted policy.

Lets look at SELinux at action.

Following example, I am gonna to create a file in /var/www/html folder and it will be accessible by http based on default SELinux policy (Why? there is a rule that says files created, not moved, on html directory has the label httpd_sys_content_t that gived http ability to open that file). We can use curl -I to see what kind of of permission does the process http has to the file. Then we will change the label, type, of that file (temporary) to something else to see if http can still access it.

1. Create a file

# touch /var/www/html/testfile

2. See its label t verify default type applied to it

# ls -Z /var/www/html/testfile
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/testfile

File has the default label, httpd_sys_content_t, so it should be accessible by httpd process and we should see the http header status code 200 (HTTP OK) when we request this file.

3. Use curl to see the header

% curl -I localhost/testfile
HTTP/1.1 200 OK
Date: Sun, 09 Sep 2018 20:33:07 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Sun, 09 Sep 2018 20:23:36 GMT
ETag: "0-5757603f7f9ae"
Accept-Ranges: bytes
Content-Type: text/plain; charset=UTF-8

Yes! we can access it. Lets change the file type

4. Changing file type temporally using chcon

# chcon -t user_home_t /var/www/html/testfile

now this is a file accessible by processes in user_home_t domain, and httpd is not one of them. Lets see what cURL says

# curl -I localhost/testfile
HTTP/1.1 403 Forbidden
Date: Sun, 09 Sep 2018 20:58:03 GMT
Server: Apache/2.4.6 (CentOS)
Content-Type: text/html; charset=iso-8859-1

Yey! As expected httpd can not access files in user’s home directory. This is a common issue people run in to when they install httpd (Apache) on linux with SELinux enforced. To solve such access issue you can use sesearch to figure out what type associated with your program

# sesearch --allow --source httpd_t --target httpd_sys_content_t --class file
Found 5 semantic av rules:
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ;
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ;
   allow httpd_t httpdcontent : file { ioctl read write create getattr setattr lock append unlink link rename open } ;
   allow httpd_t httpdcontent : file { read getattr execute open } ;
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ;

this tell you that httpd_t process can ioctl, read ,getattr, lock, and open files with type httpd_sys_content_t . If you need to access the file over httpd, this tell you that you need to change file type to httpd_sys_content_t for accessing it over web.

Unconfined Processes:

Unconfined processes runs on unconfined domains. Common ones are initrc_t and kernel_t domains. They are domain which will be used by init programs and kernel programs, respectively. They are still confined in a way that SELinux policy allows processes running in unconfined domain to have all access. Note: There are default set of security layer call DAC which is applied to all running processes. SELinux is on a layer above. It DAC denies any operation then the SELinux Policy can’t do anything to allow it.

Let see what an unconfined process can do and the result will make sure you confine all processes (well not all, use common sense).

Following example goes though the same steps but in this case httpd is of type unconfined_t and our test file is user_home_t

1. Change the file label to user_home_t

# chcon -t user_home_t /var/www/html/testfile

2. set httpd to unconfined_t

# chcon -t unconfined_exec_t /usr/sbin/httpd

3. Make sure it changed

# ls -Z /usr/sbin/httpd
-rwxr-xr-x. root root system_u:object_r:unconfined_exec_t:s0 /usr/sbin/httpd

4. Start httpd

# systemctl start httpd

5. Make sure it runs on unconfined_t

# ps -eZ | grep httpd
system_u:system_r:unconfined_t:s0 7027 ? 00:00:01 httpd
system_u:system_r:unconfined_t:s0 7028 ? 00:00:00 httpd
system_u:system_r:unconfined_t:s0 7029 ? 00:00:00 httpd
system_u:system_r:unconfined_t:s0 7030 ? 00:00:00 httpd
system_u:system_r:unconfined_t:s0 7031 ? 00:00:00 httpd
system_u:system_r:unconfined_t:s0 7032 ? 00:00:00 httpd

Yey! it is. You might not able to start httpd after changing to unconfined_exec_t due to some other SELinux policies.

6. access the file

# curl -I localhost/testfile 
HTTP/1.1 200 OK 
Date: Sun, 09 Sep 2018 21:18:04 GMT 
Server: Apache/2.4.6 (CentOS) 
Last-Modified: Sun, 09 Sep 2018 21:14:31 GMT 
ETag: "0-575760fa3b1ce" 
Accept-Ranges: bytes 
Content-Type: text/plain; charset=UTF-8

This is because http process is not confined.

Thats it for the tutorial. Now lets revert that httpd before bad things happens. Following command will do the job

# restorecon -v /usr/sbin/httpd
# systemctl restart httpd