您的应用程序使用了哪些 Linux 安全功能?我最近开发了一个新工具,能够实时打印出能力检查:
#有能力
TIME UID PID COMM CAP NAME AUDIT
22:11:23 114 2676 snmpd 12 CAP_NET_ADMIN 1
22:11:23 0 6990 运行 24 CAP_SYS_RESOURCE 1
22:11:23 0 7003 chmod 3 CAP_FOWNER 1
22:11:23 0 7003 chmod 4 CAP_FSETID 1
22:11:23 0 7005 chmod 4 CAP_FSETID 1
22:11:23 0 7005 chmod 4 CAP_FSETID 1
22:11:23 0 7006 chown 4 CAP_FSETID 1
22:11:23 0 7006 chown 4 CAP_FSETID 1
22:11:23 0 6990 setuidgid 6 CAP_SETGID 1
22:11:23 0 6990 setuidgid 6 CAP_SETGID 1
22:11:23 0 6990 setuidgid 7 CAP_SETUID 1
22:11:24 0 7013 运行 24 CAP_SYS_RESOURCE 1
22:11:24 0 7026 chmod 3 CAP_FOWNER 1
[...]
能够使用bcc,一个前端和一组使用新的 Linux 增强 BPF 跟踪功能的工具。能力通过使用带有 kprobes 的 BPF 来动态跟踪内核 cap_capable() 函数,然后使用表将能力索引映射到输出中看到的名称。这是源代码:它非常简单。
我写它是因为我的同事 Michael Wardrop 询问我们的应用程序实际使用了哪些安全功能。给定一个列表,我们可以使用 setcap(8)(或其他软件)通过只允许必要的功能来提高应用程序的安全性。
非审计检查
cap_capable() 函数有一个审计参数,它指示能力检查是否应该写入审计消息(如果已配置)。默认情况下,我只在正确的地方打印能力检查,但能力也可以使用 -v 选项跟踪所有检查:
#有能力 -h
用法:有能力 [-h] [-v] [-p PID]
跟踪安全能力检查
可选参数:
-h, --help 显示此帮助信息并退出
-v, --verbose 包括非审计检查
-p PID, --pid PID 只跟踪这个 PID
例子:
./capable # 跟踪能力检查
./capable -v # 详细:包括非审计检查
./capable -p 181 # 仅跟踪 PID 181
以下是一些非审计事件:
#有能力 -v
TIME UID PID COMM CAP NAME AUDIT
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
20:53:45 60004 22061 lsb_release 21 CAP_SYS_ADMIN 0
[...]
这些都是什么?
我将从 security/commoncap.c 中的 cap_capable() 函数原型开始:
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
国际上限,国际审计)
现在我可以使用 bcc 的跟踪程序来检查这些调用(请耐心等待),假设 cap 将是 arg3,并且审计 arg4(来自上面的原型):
# trace 'cap_capable "cap: %d, audit: %d", arg3, arg4'
TIME PID COMM FUNC -
20:56:18 25535 lsb_release cap_capable cap: 21, audit: 0
20:56:18 25535 lsb_release cap_capable cap: 21, audit: 0
20:56:18 25535 lsb_release cap_capable cap: 21, audit: 0
20:56:18 25535 lsb_release cap_capable cap: 21, audit: 0
20:56:18 25535 lsb_release cap_capable cap: 21, audit: 0
[...]
该单行程序与我的功能强大的程序非常相似,只是它缺少带有人类可读翻译的“NAME”列。
我真的这样做了,所以我可以添加(新添加的)-K 和 -U 选项,它们打印内核和用户级堆栈跟踪。 我将只使用-K:
# trace -K 'cap_capable "cap: %d, audit: %d", arg3, arg4'
TIME PID COMM FUNC -
[...]
20:59:58 30607 lsb_release cap_capable cap: 21, audit: 0
Kernel Stack Trace:
ffffffff813659d1 cap_capable
ffffffff813684bb security_vm_enough_memory_mm
ffffffff811deda6 expand_downwards
ffffffff811def64 expand_stack
ffffffff81234321 setup_arg_pages
ffffffff8128c10b load_elf_binary
ffffffff81234cee search_binary_handler
ffffffff8128b7ff load_script
ffffffff81234cee search_binary_handler
ffffffff8123635a do_execveat_common.isra.35
ffffffff812367da sys_execve
ffffffff81003bae do_syscall_64
ffffffff81861ca5 return_from_SYSCALL_64
20:59:58 30607 lsb_release cap_capable cap: 21, audit: 0
Kernel Stack Trace:
ffffffff813659d1 cap_capable
ffffffff813684bb security_vm_enough_memory_mm
ffffffff811df623 mmap_region
ffffffff811dff4b do_mmap
ffffffff811c122a vm_mmap_pgoff
ffffffff811c1295 vm_mmap
ffffffff8128bb93 elf_map
ffffffff8128c271 load_elf_binary
ffffffff81234cee search_binary_handler
ffffffff8128b7ff load_script
ffffffff81234cee search_binary_handler
ffffffff8123635a do_execveat_common.isra.35
ffffffff812367da sys_execve
ffffffff81003bae do_syscall_64
ffffffff81861ca5 return_from_SYSCALL_64
[...]
惊人的。所以这些来自security_vm_enough_memory_mm()。通过阅读源代码,我看到它用于为 root 保留一些内存。如果缺少该功能,这不是硬故障。它并不是真正的安全检查,因此它禁用了审计。
我应该为有能力的工具添加一个 -K 选项,这样它也可以打印堆栈跟踪。
较旧的内核
要使用有能力,您需要 4.4 内核。要使用 -K 选项,4.6。
这是使用我较旧的perf-tools集合的版本,它使用 ftrace 并且应该适用于更旧的内核,包括 3.x 系列:
# ./perf-tools/bin/kprobe -s 'p:cap_capable cap=%dx audit=%cx' 'audit != 0'
跟踪 kprobe cap_capable。Ctrl-C 结束。
运行 4440 [003] d... 6417394.367486: cap_capable: (cap_capable+0x0/0x70) cap=0x18 audit=0x1
运行 4440 [003] d... 6417394.367492:
=> ns_capable_common
=> 有能力
=> do_prlimit
=> SyS_setrlimit
=> entry_SYSCALL_64_fastpath
chmod-4453 [006] d... 6417394.399020: cap_capable: (cap_capable+0x0/0x70) cap=0x3 audit=0x1
chmod-4453 [006] d... 6417394.399027:
=> ns_capable_common
=> ns_capable
=> inode_owner_or_capable
=> inode_change_ok
=> xfs_setattr_nonsize
=> xfs_vn_setattr
=> 通知更改
=> chmod_common
=> SyS_fchmodat
=> entry_SYSCALL_64_fastpath
chmod-4453 [006] d... 6417394.399035: cap_capable: (cap_capable+0x0/0x70) cap=0x4 audit=0x1
chmod-4453 [006] d... 6417394.399037:
=> ns_capable_common
=> 能力_wrt_inode_uidgid
=> inode_change_ok
=> xfs_setattr_nonsize
=> xfs_vn_setattr
=> 通知更改
=> chmod_common
=> SyS_fchmodat
=> entry_SYSCALL_64_fastpath
chmod-4455 [007] d... 6417394.402524: cap_capable: (cap_capable+0x0/0x70) cap=0x4 audit=0x1
chmod-4455 [007] d... 6417394.402529:
=> ns_capable_common
=> 能力_wrt_inode_uidgid
=> inode_change_ok
=> xfs_setattr_nonsize
=> xfs_vn_setattr
=> 通知更改
=> chmod_common
=> SyS_fchmodat
=> entry_SYSCALL_64_fastpath
[...]
这是使用我的 kprobe 工具的单线器。它也(目前)有点难以使用:我需要知道这些参数将在哪些寄存器中:上面的示例仅适用于 x86_64。
目前为止就这样了。快乐的黑客。
转载翻译自: https://www.brendangregg.com