Disallowing CAP_NET_RAW Capability for Root User using AppArmor

Photo by Patrick Fore / Unsplash

Is the root user really the most powerful entity in the Linux kernel? Can you block the root user from accessing resources in the system? You might be now thinking what a stupid question it is. Of course, the root user is the highest privileged user in the system and can do literally everything.

I have explained in the Linux privilege escalation series that all the checks for capabilities are bypasses for privileged binaries (EUID=0) or processes created by the root user using sudo (RUID=0). Let see how you can confine the program for all users including the root.

So far you have learned about the basics of AppArmor and its profile in the previous post. If you haven't read that post, it would be hard to understand the concept in this post. In this post, you will get familiar with the commonly used AppArmor utilities by solving the lab on AttackDefence

In the lab, you have the ping command which gets failed due to permission error when executed by a student user because the ping command requires the cap_net_raw capability to work and student user doesn't have. Also, you can see that the suid bit is not set for ping command so it couldn't escalate to the root user and execute successfully. On the other hand, with sudo, it works fine as it forces ping to be launched with the root user bypassing all the checks for permissions and capabilities.

Ping command failed when executed as student user but working with sudo

Configuring Profile to Drop the NET_RAW Capability

AppArmor utility suite provides a bunch of tools for interacting with the program from user mode. One of the most used tools is  aa-status, which will tell you whether the feature is loaded or not and also how many profiles are loaded and classified in enforce mode or complain mode. If you have unconfined processes running whose profile is there but not loaded, you can also see them and in the output of this command. You can also use --json argument in case you want to integrate it into any high-level programming language for automation.

Listing all the profiles loaded in the AppArmor and found ping in complain mode

Let's now find the path of ping binary and its AppArmor profile. To get the path of binary you can use which ping command and the configuration file then can be found in /etc/apparmor.d/$(which ping | cut -d "/" -f2- | tr "/" ".")

AppArmor profile for the ping command

You can see that the ping profile has the complain flag set that is why it is only logging in the /var/log/audit/audit.log but not confining the capabilities and you can see it under the complain mode in aa-status output.

There are two ways to enforce the profile in AppArmor

  • Remove flags=(complain)

    - profile ping /{usr/,}bin/ping flags=(complain) {
    + profile ping /{usr/,}bin/ping {
    

    Now reload the profile manually using apparmor_parser

    $ sudo apparmor_parser -r /etc/apparmor.d/bin.ping
    
  • Use the aa-enforce with the absolute profile path or the name in /etc/apparmor.d/ directory

    # enforce the profile and reload the profile
    $ sudo aa-enforce bin.ping
    
    # only enforce in the profile file but not reload the profile
    $ sudo aa-enforce --no-reload bin.ping
    

In this situation, I will use the second command (aa-enforce) from the AppArmor suite to enforce this profile and automatically reload it in the kernel.

Enforcing the ping command profile and reloading it automatically

If you do the ping with sudo it will still execute the ping command because by default all the rules in the profile definition are meant to be allowed by AppArmor and to disallow them, you need to explicitly tell in the profile to deny the control.

In this case, you can update the profile as shown below.

- capability net_raw,
+ deny capability net_raw,
Deny net_raw capability in the profile

Since the updated contents are not loaded in the AppArmor, you need to now execute the apparmor_parser tool to parse and reload the profile using the -r flag. If  you will now try to ping any IP from the root user, it will fail with "Operation not permitted"

Reload profile and try ping with the root user

Validating Capabilities Drop

So far we have configured the profile to deny net_raw capabilities for the ping command. But what if the command has already cap_net_raw capability set? Let's try to set this cap on the ping command and again try out pinging 127.0.0.1

Adding the net_raw capability gets dropped by AppArmor

So it is now confirmed that the program is truly confined and even when you add the capability to it, it will get dropped by the AppArmor.

References

Gurkirat Singh

Gurkirat Singh

Hey there everyone, I am Gurkirat Singh (aka tbhaxor). I do full-stack development to fund my own learning and experiments. I am a cybersecurity enthusiast and like sharing my knowledge.
India