📜 ⬆️ ⬇️

Isolation of virtual servers in apache2 - ugidctl

Some time ago, I made a solution for myself that effectively isolates apache2 processes. Now he can process each request on behalf of his system user. Today I want to share this decision.

This is what it is about:

<VirtualHost *:80> ServerName host1.example.com ServerAdmin webmaster1@example.com ServerUserGroup user1 group1 DocumentRoot /var/www/host1 </VirtualHost> <VirtualHost *:80> ServerName host2.example.com ServerAdmin webmaster2@example.com ServerUserGroup user2 group2 DocumentRoot /var/www/host2 </VirtualHost> 

At the same time, the root directories of virtual hosts can be accessed only by the corresponding users:
')
 # ls -la /var/www total 16 drwxr-xr-x 4 root root 4096 Oct 26 16:10 . drwxr-xr-x 21 root root 4096 Oct 26 01:13 .. drwxr-x--- 2 user1 group1 4096 Oct 26 16:10 host1 drwxr-x--- 2 user1 group2 4096 Oct 26 16:10 host2 

These are not regular dances with a tambourine around the multithreading, starting processes from the root, etc. The basic idea is that the process independently decides with what rights it is necessary for it to process the request, took these rights for itself, processed it, and again regained the rights of the main user apache.

At the same time, I wanted apache initially to be limited to the list of users that are described in its configuration at startup, and during the processing of the request it would be extremely difficult (or almost impossible) for the process of “hacking” the switching mechanism and assigning other rights to itself.

The main use for me is linux, but the existing mechanisms in its core are not enough to implement my idea only in the user's environment. Therefore, the solution consists of 2 parts - the kernel module and the apache module. The kernel module provides the / dev / ugidctl device, through which the ioctl (2) system call can manage the lists of allowed users for a process in the privileged mode, and, in fact, switch users in the non-ganged mode. On the apache side, this module is used by another module that implements all this functionality.

A little more detail the algorithm works as follows:

Apache root process:

  1. Opens device / dev / ugidctl
  2. In the process of reading the configuration file collects a list of required users
  3. Uploads this list to ugidctl
  4. Receives a random key from the kernel to switch between users.

Child process:

  1. Resets permissions to primary user.
  2. Waiting for a request, looking what rights it should serve
  3. Using the key obtained during initialization, toggles the user
  4. Handles a request
  5. Using the key, returns the rights of the primary user.
  6. goto 2

In the case of hacking a child process, even when obtaining a switch key, restrictions on the list of users will not allow an attacker to elevate privileges in the system. As a maximum, it will be possible to get into any root directory of any virtual host, which is equivalent to how unmodified apache with MPM prefork processes all requests. At the same time, the complexity of finding a key in the memory of the child process is similar to the difficulty of finding private keys in the memory of the mod_ssl module.

Naturally, according to my whole idea, the module is only designed to work with MPM prefork. It is also worth avoiding multithreading whenever possible when processing requests within the apache process - my module switches only the rights of the main thread of the process.

You can download it here:

Core module
Apache module

A small instruction for assembly on CentOS 7:

We put the necessary packages for the assembly:

 [root@el7 ~]# yum install -y gcc httpd-devel kernel-devel 

Download and unpack the sources:

 [root@el7 ~]# wget -q -O - https://ibuffed.com/pub/ugidctl/ugidctl-0.1.1.tar.gz | tar -xz [root@el7 ~]# wget -q -O - https://ibuffed.com/pub/ugidctl/mod_ugidctl-1.0.1.tar.gz | tar -xz 

Build and load the kernel module:

 [root@el7 ~]# cd ~/ugidctl-0.1.1/ [root@el7 ugidctl-0.1.1]# make [root@el7 ugidctl-0.1.1]# insmod ugidctl.ko 

Build and load the apache2 module:

 [root@el7 ~]# cd ~/mod_ugidctl-1.0.1/ [root@el7 mod_ugidctl-1.0.1]# apxs -i -c mod_ugidctl.c [root@el7 mod_ugidctl-1.0.1]# echo 'LoadModule ugidctl_module modules/mod_ugidctl.so' > /etc/httpd/conf.modules.d/99-ugidctl.conf [root@el7 mod_ugidctl-1.0.1]# systemctl restart httpd 

Or you can use ready-made assemblies for el6 (RHEL 6u2 + / CentOS 6.2 +, only x86_64) and for el7 (RHEL 7 / CentOS 7). This solution has been working smoothly on several el6 servers for over a year now.

Source: https://habr.com/ru/post/269835/


All Articles