Insecure Dynamic Library Loading
不安全的动态库加载
描述
如果未安全实现动态加载库,可能会引入一系列重大漏洞,对应用程序的安全性和完整性构成严重风险:
不安全的加载路径 (Insecure Loading Path):当应用程序从不受信任或被篡改的位置加载库时,就会出现此漏洞。如果应用程序在不知情的情况下从恶意来源加载库,就会为潜在的攻击敞开大门。攻击者可以利用此弱点将恶意库放置在不受信任的位置,从而导致以提升的权限执行代码或未经授权访问敏感资源。
库劫持 (Library Hijacking):当攻击者用恶意库替换合法库时,就会发生库劫持。通过篡改库加载过程,攻击者可以欺骗应用程序转而加载恶意库。这可以实现广泛的攻击,包括代码注入、权限提升以及未经授权访问敏感数据。
如果不解决这些漏洞,可能会产生严重的后果。攻击者可以将恶意代码注入应用程序,破坏其完整性,未经授权访问关键资源,并可能利用其他安全漏洞。
易受攻击的实现示例:
void loadDependency(String unsanitized_user_input) {
// 在未对输入进行清理的情况下动态加载库
final dylib = DynamicLibrary.open(unsanitized_user_input);
// 解析并调用已加载库中包含恶意代码的函数
final libraryMethod =
dylib.lookupFunction<Pointer<Utf8> Function(), Pointer<Utf8> Function()>(
'getSensitiveData');
final result = libraryMethod();
}
func loadDynamicLibrary(unsanitized_user_input: String) {
// 尝试在未对用户输入进行清理的情况下动态加载库
if let libraryHandle = dlopen(unsanitized_user_input, RTLD_NOW) {
// 库加载成功,解析可能包含恶意代码的函数
if let method = dlsym(libraryHandle, "libraryMethod") {
typealias FunctionType = @convention(c) () -> String
let function = unsafeBitCast(libraryMethod, to: FunctionType.self)
let result = function()
}
dlclose(libraryHandle)
}
}
fun loadDependency(unsanitized_user_input : String) {
// 动态加载库而未清理输入
System.load(unsanitized_user_input)
// 使用动态加载的库执行某些操作
val result = libraryMethod()
}
建议
在处理动态库加载时,开发人员应该:
- 实施强大的输入验证和清理技术,以防止目录遍历(directory traversal)和注入攻击。
- 仅从受信任和已验证的来源加载库,确保库的完整性和真实性。
- 实施严格的访问控制以防止未经授权加载库。
- 定期更新库并应用补丁,以解决已知漏洞。
- 采用强大的代码签名和完整性验证机制,确保动态加载的库的完整性。
安全的实现示例:
void validation(String input){
// 验证库文件完整性
Uint8List fileBytes = libraryFile.readAsBytesSync();
Digest fileDigest = SHA256Digest().process(fileBytes);
Uint8List expectedChecksum = Uint8List.fromList([...]);
if (fileDigest.bytes != expectedChecksum) {
return false; // 文件校验和无效
}
if (/* 检查 .. 模式 */ )
return false; // 路径无效
// 添加特定于您的实现的其他验证检查
return true;
}
void loadDependency(String unsanitized_user_input) {
// 清理用户输入
if (validation(unsanitized_user_input) == false)
throw FormatException("invalid input");
// 使用经过验证的输入动态加载库
final dylib = DynamicLibrary.open(unsanitized_user_input);
// 解析并调用已加载库中的函数
final libraryMethod =
dylib.lookupFunction<Pointer<Utf8> Function(), Pointer<Utf8> Function()>(
'getSensitiveData');
final result = libraryMethod();
}
func validation(unsanitized_user_input: String){
guard let fileData = fileManager.contents(atPath: libraryURL.path) else {
return false // 读取文件数据失败
}
let fileDigest = SHA256.hash(data: fileData)
// 将计算出的校验和与预期校验和进行比较
let expectedChecksum: [UInt8] = [ /* 替换为您预期的校验和 */ ]
if fileDigest != expectedChecksum {
return false // 文件校验和无效
if (/* 检查 .. 模式 */ )
return false; // 路径无效
// 添加特定于您的实现的其他验证检查
return true;
}
}
func loadDynamicLibrary(unsanitized_user_input: String) {
// 验证您的用户输入
if !validation(unsanitized_user_input){
throw CustomValidationError.invalidInput
}
// 尝试使用经过验证的用户输入动态加载库
if let libraryHandle = dlopen(unsanitized_user_input, RTLD_NOW) {
// 库加载成功,解析可能包含恶意代码的函数
if let method = dlsym(libraryHandle, "libraryMethod") {
typealias FunctionType = @convention(c) () -> String
let function = unsafeBitCast(libraryMethod, to: FunctionType.self)
let result = function()
}
dlclose(libraryHandle)
}
}
fun validation(input : String){
// 验证库文件完整性
val fileBytes = Files.readAllBytes(libraryFile.toPath())
val digest = MessageDigest.getInstance("SHA-256")
val fileDigest = digest.digest(fileBytes)
val expectedChecksum = byteArrayOf(...)
if (!fileDigest.contentEquals(expectedChecksum)) {
return false
}
if (/* 检查 .. 模式 */ )
return false // 路径无效
// 添加特定于您的实现的其他验证检查
return true
}
fun loadDependency(unsanitized_user_input : String) {
// 验证您的用户输入
if (!validation(unsanitized_user_input))
throw IllegalArgumentException("Invalid input")
// 使用经过验证的输入动态加载库
System.load(unsanitized_user_input)
// 使用动态加载的库执行某些操作
val result = libraryMethod()
}
链接
标准
- OWASP_MASVS_L1:
- MSTG_PLATFORM_3
- OWASP_MASVS_L2:
- MSTG_PLATFORM_3
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_11_3
- OWASP_MASVS_v2_1:
- MASVS_CODE_4
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213
- SECURITY255