AppArmor Security Analysis
A skill for analyzing, creating, and testing AppArmor security profiles on Linux systems.
What is AppArmor
AppArmor is a kernel enhancement that restricts program resources through per-program profiles, implementing Mandatory Access Control (MAC) by tying access control attributes directly to programs instead of users.
Key concepts:
- Profiles are loaded into the kernel (usually at boot)
- Profiles dictate what resources a program can access (network, files, sockets)
- Two modes: Enforcement (blocks violations) and Complain (logs violations only)
Quick Status Check
Start by checking what's currently confined:
sudo aa-status
This shows:
- How many profiles are loaded
- Which are in enforce mode vs complain mode
- Which binaries are restricted
Profile naming convention: Replace / with . in the binary path to find the profile file.
- Binary:
/usr/bin/man→ Profile:/etc/apparmor.d/usr.bin.man
Core Commands
Status and Mode Management
aa-status # Check current status
aa-enforce <profile> # Set profile to enforce mode
aa-complain <profile> # Set profile to complain mode
Profile Management
apparmor_parser -a <profile> # Load profile in enforce mode
apparmor_parser -C <profile> # Load profile in complain mode
apparmor_parser -r <profile> # Replace existing profile
apparmor_parser -R <profile> # Remove profile
Profile Creation Tools
aa-genprof <binary> # Interactive profile generation (inspect binary actions)
aa-easyprof <binary> # Create template profile
aa-logprof # Review logs and permit detected violations
aa-mergeprof # Merge policies
Creating Profiles
Method 1: Interactive Generation (aa-genprof)
This is the most thorough approach - AppArmor inspects actual binary behavior:
Start the generator:
sudo aa-genprof /path/to/binaryIn a separate terminal, run the binary with typical operations:
/path/to/binary -a dosomethingReturn to the generator terminal:
- Press
sto review recorded actions - Use arrow keys to select: allow, deny, or ignore each action
- Press
fwhen finished to create the profile
- Press
The profile is saved to /etc/apparmor.d/path.to.binary
Method 2: Template Creation (aa-easyprof)
Quick template generation:
sudo aa-easyprof /path/to/binary
This creates a basic profile structure. Important: By default, nothing is allowed - you must explicitly add permissions:
"/path/to/binary" {
#include <abstractions/base>
/etc/passwd r, # Allow reading /etc/passwd
/var/log/myapp.log w, # Allow writing to log file
/usr/bin/helper ix, # Allow executing helper program
}
Access Control Modifiers
| Modifier | Meaning |
|---|---|
r |
Read |
w |
Write |
m |
Memory map as executable |
k |
File locking |
l |
Create hard links |
ix |
Execute with policy inheritance |
Px |
Execute under another profile (cleaned env) |
Cx |
Execute under child profile (cleaned env) |
Ux |
Execute unconfined (cleaned env) |
Profile Variables
Use variables for flexibility:
#include <tunables/global>
"/path/to/binary" {
@{HOME}/** r, # Read from user's home directory
@{PROC}/** r, # Read from /proc
}
Analyzing Logs
Audit Log Format
AppArmor violations appear in /var/log/audit/audit.log:
type=AVC msg=audit(1610061880.392:287): apparmor="DENIED" \
operation="open" profile="/bin/rcat" name="/etc/hosts" \
pid=954 comm="service_bin" requested_mask="r" denied_mask="r"
Key fields:
operation: What action was attempted (open, getattr, etc.)profile: Which AppArmor profile was activename: Resource that was accessedrequested_mask: What access was requested (r=read, w=write, etc.)denied_mask: What was actually denied
Interactive Log Review
sudo aa-notify -s 1 -v
Shows recent denials in a readable format:
Profile: /bin/service_bin
Operation: open
Name: /etc/passwd
Denied: r
Logfile: /var/log/audit/audit.log
AppArmor in Docker
Default Docker Profile
Docker uses docker-default profile by default. Key restrictions:
- ✅ Allowed: All networking access
- ❌ Denied: Writing to
/procfiles - ❌ Denied: Access to
/procand/syssubdirectories - ❌ Denied: Mount operations
- ⚠️ Limited: Ptrace only on processes with same profile
Important: AppArmor blocks capabilities even if granted. Example:
# This fails - AppArmor blocks /proc write even with SYS_ADMIN
docker run -it --cap-add SYS_ADMIN ubuntu /bin/bash
echo "" > /proc/stat
# sh: 1: cannot create /proc/stat: Permission denied
Running with Custom Profile
docker run --rm -it --security-opt apparmor:myprofile ubuntu /bin/bash
Disabling AppArmor
docker run --rm -it --security-opt apparmor=unconfined ubuntu /bin/bash
Finding Container's Profile
# Check which profile a container uses
docker inspect <container_id> | grep AppArmorProfile
# Find the profile file
find /etc/apparmor.d/ -name "*<profile_name>*" -maxdepth 1 2>/dev/null
Security Testing Considerations
Common Bypass Patterns
1. Path-based bypass: AppArmor is path-based. If /proc is protected but /host/proc is not:
# Mount host /proc to different path
docker run -v /proc:/host/proc ubuntu /bin/bash
# /host/proc may not be protected
2. Shebang bypass: Scripts with shebangs may execute under different profiles:
#!/usr/bin/perl
use POSIX qw(setuid);
POSIX::setuid(0);
exec "/bin/sh"
If you execute this script directly, it may run under the shell's profile, not perl's.
3. Profile modification: If you can modify and reload a profile:
# Edit profile to remove restrictions
sudo vim /etc/apparmor.d/docker-default
# Reload the modified profile
sudo apparmor_parser -r /etc/apparmor.d/docker-default
When Exploits Fail
If you have a privileged capability inside Docker but an exploit isn't working, AppArmor is likely blocking it. Check:
sudo aa-status | grep docker
Workflow Checklist
When analyzing AppArmor on a system:
- Check status:
sudo aa-status - Identify target binary's profile: Find in
/etc/apparmor.d/ - Review profile contents:
cat /etc/apparmor.d/<profile> - Check for denials:
sudo aa-notify -s 1 -v - Test in complain mode:
sudo aa-complain <profile>(if you have access) - Review audit logs:
grep apparmor /var/log/audit/audit.log
Troubleshooting
Profile not loading:
# Check for syntax errors
sudo apparmor_parser -C /etc/apparmor.d/<profile>
Binary not confined:
# Verify profile is loaded
sudo aa-status | grep <binary_name>
# Check if profile is in complain mode (won't block)
Need to debug:
# Switch to complain mode to see what would be blocked
sudo aa-complain <profile>
# Run the binary
# Check logs
sudo aa-notify -s 1 -v
# Switch back to enforce
sudo aa-enforce <profile>