8个版本
0.3.3 | 2024年1月17日 |
---|---|
0.3.2 | 2023年7月1日 |
0.3.1 | 2023年5月4日 |
0.3.0 | 2022年11月25日 |
0.1.0 | 2021年11月3日 |
64 在 操作系统 中
3,287 每月下载量
在 2 crates 中使用
91KB
1.5K SLoC
secmem-proc
secmem-proc
是一个crate,旨在通过系统API加固进程以抵御在同一系统上运行的 低权限 攻击者尝试获取当前进程的秘密内存内容。更具体地说,该crate禁用核心转储,尽力禁用跟踪其的能力,并尽可能检测已附加的跟踪器。
注意:该crate所做的只是 加固,即它试图让攻击更难。它绝对不能保证任何安全性!特别是,当攻击者在执行 harden_process
之前将ptrace附加到进程时,进程就失败了。这个crate不能替代正确加固您的操作系统(配置)!
请注意,加固进程也会严重限制调试它的能力。因此,建议您只加固发布构建,而不是调试构建。
Windows
在Windows上,harden_process
为进程设置了一个严重受限的DACL。 (更精确地说,只有 PROCESS_QUERY_LIMITED_INFORMATION
、PROCESS_TERMINATE
和 SYNCHRONIZE
权限被启用。) 这可能过于严格,以至于无法让应用程序正确运行。当需要更多权限时,可以使用 win_acl
模块中的安全API创建和设置自定义DACL。
在Windows上,这个crate通过依赖windows
crate依赖于std
。
示例
以下示例中,某个应用程序的main函数调用此crate提供的main hardening函数:harden_process
。这将在目标平台上执行所有可用的hardening步骤(除了不稳定的步骤)。当其中一个hardening步骤失败或检测到调试器时,该函数返回错误。建议在任何错误发生时终止应用程序。
fn main() {
// call `secmem_proc::harden_process` before doing anything else, to harden the process
// against low-privileged attackers trying to obtain secret parts of memory which will
// be handled by the process
if let Err(e) = secmem_proc::harden_process() {
println!("ERROR: could not harden process, exiting");
println!("ERROR: {}", e);
return;
}
// rest of your program
}
也可以配置要执行哪些类型的hardening步骤。为此,可以使用config
中的API。以下是一个示例:
fn main() {
// harden before doing anything else
let mut config = secmem_proc::Config::DEFAULT;
config.set_anti_tracing(false);
config.set_fs(false);
if let Err(e) = config.harden_process() {
println!("ERROR: could not harden process, exiting");
println!("ERROR: {}", e);
return;
}
// rest of your program
}
在最后一个示例中,我们使用win_acl
API在Windows上设置自定义DACL。在示例中,我们除了默认权限外,还授予了PROCESS_CREATE_THREAD
权限。请注意,在这种情况下,同样可以使用Config::set_win_dacl_custom_user_perm
实现,这显然要简单得多。然而,下面的方法要灵活得多。
#[cfg(windows)]
fn set_windows_dacl() -> secmem_proc::Result {
use windows::Win32::System::Threading::{
PROCESS_CREATE_THREAD, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_SYNCHRONIZE,
PROCESS_TERMINATE,
};
use secmem_proc::win_acl::{AddAllowAceAcl, EmptyAcl, TokenUser};
// First obtain the SID of the process user
let user = TokenUser::process_user()?;
let sid = user.sid();
// Now specify the ACL we want to create
// Only things explicitly allowed with `AddAllowAceAcl` will be allowed; noting else
let acl_spec = EmptyAcl;
let access_mask = PROCESS_QUERY_LIMITED_INFORMATION
| PROCESS_TERMINATE
| PROCESS_SYNCHRONIZE
| PROCESS_CREATE_THREAD;
let acl_spec = AddAllowAceAcl::new(acl_spec, access_mask, sid);
// Create ACL and set as process DACL
let acl = acl_spec.create()?;
acl.set_process_dacl_protected()?;
Ok(())
}
fn main() {
// harden before doing anything else
let mut config = secmem_proc::Config::DEFAULT;
#[cfg(windows)]
config.set_win_dacl_custom_fn(set_windows_dacl);
config.set_fs(false);
if let Err(e) = config.harden_process() {
println!("ERROR: could not harden process, exiting");
println!("ERROR: {}", e);
return;
}
// rest of your program
}
Cargo功能
std
(默认):启用需要std
的功能。目前需要用于Error
实现、Linux上的反跟踪通过/proc/self/status
和测试。此功能默认启用。unstable
:启用依赖于未记录或不稳定的操作系统/平台细节的功能。此功能仅启用对这些功能的支持;要实际启用这些反调试方法,必须在配置中专门启用。dev
:此功能启用运行测试套件所需的所有功能,并且仅应为此目的启用。
实现
- 使用prctl在Linux上禁用进程的ptrace和core dumps
- 使用procctl在FreeBSD上禁用进程的ptrace和core dumps
- 使用ptrace在macos上禁用ptrace
- 使用rlimit在POSIX系统上禁用进程的core dumps
- 在Windows上为进程设置受限DACL
- 当启用
std
功能时,通过读取/proc/self/status
在Linux上检测调试器(std,反跟踪) - 使用
IsDebuggerPresent
和CheckRemoteDebuggerPresent
在Windows上检测调试器(反跟踪) - 启用unstable后,在Windows上隐藏线程以防止调试器调试(unstable,反跟踪)
- 启用unstable后,通过从内核结构
KUSER_SHARED_DATA
读取来检测Windows上的调试器(unstable,反跟踪)
反跟踪
此crate使用的强化方法可以分为两组:
- 与安全相关的进程强化,以及
- 反跟踪。
两种方法之间的区别在于线程模型。进程加固通常假设进程尚未受到攻击,例如尚未被跟踪。加固方法随后对进程的配置进行修改,以限制其他进程对其的访问,例如禁用进程跟踪或禁用核心转储。反跟踪假设进程已经被恶意进程(恶意软件)跟踪/调试。目标则是检测跟踪器/调试器。反跟踪方法总是可以被跟踪器/调试器绕过,尽管其中一些比其他方法更难绕过。(Windows上不稳定的KUSER_SHARED_DATA
反跟踪方法就是一个难以绕过的例子。)可以使用以下方式禁用反跟踪:Config::set_anti_tracing(false)
。
待办事项
- 改进测试(具体如何?)
依赖关系
~2–40MB
~630K SLoC