This page looks best with JavaScript enabled

AppArmor

 ·  🎃 kr0m

AppArmor is a Mandatory Access Control (MAC) system based on the Linux Security Modules (LSM) interface. In practice, the kernel asks AppArmor before each system call to determine if a process is authorized to perform that operation. Through this mechanism, AppArmor confines a program to a limited set of resources.

To make AppArmor work, we must have certain kernel options enabled:

CONFIG_SECURITY_APPARMOR=y
CONFIG_AUDIT=y
CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
CONFIG_DEFAULT_SECURITY_APPARMOR=y

We install the user-lands:

emerge -av sys-apps/apparmor sec-policy/apparmor-profiles sys-apps/apparmor-utils

In this example, we will apply an AppArmor profile to the PHP FPM, thus limiting the actions allowed to the PHP code.
Apache and PHP will be compiled as follows:

vi /etc/make.conf

PHP_TARGETS="php7-2"
PHP_INI_VERSION="production"
vi /etc/portage/package.use/apache
www-servers/apache threads
vi /etc/portage/package.use/php
dev-lang/php apache2 berkdb bzip2 cli crypt ctype curl curlwrappers exif fileinfo filter ftp gd gdbm hash iconv imap intl json mysql mysqli nls odbc pdo phar posix readline session simplexml soap sockets sqlite ssl sysvipc threads tokenizer unicode xml xmlreader xmlrpc xmlwriter zip zlib threads fpm cgi truetype bcmath ldap pcntl

We compile PHP:

emerge -av www-servers/apache dev-lang/php

We configure FPM:

vi /etc/php/fpm-php7.2/fpm.d/www.conf

listen = /var/run/php7.2-fpm.sock
listen.owner = apache
listen.group = apache
user = apache
group = apache

We restart the service:

/etc/init.d/php-fpm restart

We create a test vhost:

vi /etc/apache2/vhosts.d/test.conf

<VirtualHost *:80>
        ServerAdmin sys@alfaexploit.com
        DocumentRoot /var/www/test
        ServerName www.test.com
        ErrorLog /var/log/apache2/test.error_log
        CustomLog /var/log/apache2/test.access_log combined
        DirectoryIndex index.php index.htm index.html

        AddHandler application/x-httpd-php .php .php5 .phtml
        AddHandler application/x-httpd-php-source .phps

        <FilesMatch ".php$">
            SetHandler "proxy:unix:///var/run/php7.2-fpm.sock|fcgi://localhost/"
        </FilesMatch>

        <Directory "/var/www/test">
            Options -Indexes +FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>

</VirtualHost>

We create the docroot directory and apply ACLs so that the apache user can read and write to it:

mkdir /var/www/test
chown -R kr0m:kr0m /var/www/test
setfacl -dR -m u:apache:rwX -m u:kr0m:rwX /var/www/test
setfacl -R -m u:apache:rwX -m u:kr0m:rwX /var/www/test

We apply the changes:

/etc/init.d/apache2 restart

We program a small form with a text field, the content of which will be saved in a file:

vi /var/www/test/index.php

<body>
  <form action="/writeFile.php" method="post">
    Code: <input type="text" name="code" style="width: 1024px;"><br>
    <input type="submit" value="Submit">
  </form>
</body>
vi /var/www/test/writeFile.php
<?php
 $fichero = 'file.php';
 file_put_contents($fichero, $_POST["code"]);
?>

To test it, we will upload a small webshell, access the website, and paste the following code into the text field:
http://www.test.com/

Code:

<?php echo shell_exec($_GETcmd.' 2>&1'); ?>

We check if it worked using curl:

uid=81(apache) gid=81(apache) groups=81(apache)

Before generating the apparmor profile, we stop it:

/etc/init.d/apparmor stop

We start saving the operations performed by FPM by generating the profile:

aa-genprof /usr/bin/php-fpm

We navigate through the website to log the calls.
We perform typical FPM tasks:

/etc/init.d/php-fpm restart
/etc/init.d/php-fpm stop
/etc/init.d/php-fpm start
/etc/init.d/php-fpm status

We press S

Updating AppArmor profiles in /etc/apparmor.d.

It will ask us if we want to include the indicated ACLs, in the following style:

 [1 - signal send set=term peer=unconfined,]
(A)llow / [(D)eny] / (I)gnore / Audi(t) / Abo(r)t / (F)inish

When finished, press F
Check that a new profile exists:

ls -la /etc/apparmor.d/

-rw------- 1 root root 190 nov 7 15:38 usr.lib64.php7.2.bin.php-fpm

By default, it puts profiles on us, but we only want to limit FPM:

cd /etc/apparmor.d
find -type f -maxdepth 1 -exec aa-disable {} ;

Start apparmor and enable the profile to apply:

/etc/init.d/apparmor start
aa-enforce /etc/apparmor.d/usr.lib64.php7.2.bin.php-fpm

Check the status:

apparmor_status

1 profiles are in enforce mode.
 /usr/lib64/php7.2/bin/php-fpm

Add apparmor to the boot:

rc-update add apparmor boot

Now if we try to write the file to the hard drive:

tail -f /var/log/messages
Nov 7 16:34:31 NZXT48 kernel: [62029.240917] audit: type=1400 audit(1541604871.745:525): apparmor=“DENIED” operation=“open” profile="/usr/lib64/php7.2/bin/php-fpm" name="/var/www/test/file.php" pid=705 comm=“php-fpm” requested_mask=“wc” denied_mask=“wc” fsuid=81 ouid=81

No file has actually been generated:

ls -la /var/www/test/
total 20
drwxrwxr-x+ 2 kr0m kr0m 4096 nov 7 16:34 .
drwxr-xr-x 9 apache root 4096 nov 7 13:44 ..
-rw-rw-r–+ 1 kr0m kr0m 176 nov 7 13:49 index.php
-rw-rw-r–+ 1 kr0m kr0m 79 nov 7 13:51 writeFile.php

NOTE: If the profile already exists, it is better to manually delete it and regenerate it with aa-genprof.

If you liked the article, you can treat me to a RedBull here