Insecure Dynamic Library Loading
Insecure Dynamic Library Loading
Description
Dynamic loading of libraries, when not implemented securely, can introduce a range of significant vulnerabilities that pose serious risks to the security and integrity of an application:
Insecure Loading Path: This vulnerability arises when an application loads libraries from untrusted or manipulated locations. If an application unwittingly loads libraries from malicious sources, it opens the door to potential attacks. Attackers can exploit this weakness by placing malicious libraries in untrusted locations, leading to code execution with elevated privileges or unauthorized access to sensitive resources.
Library Hijacking: Library hijacking occurs when an attacker substitutes a legitimate library with a malicious one. By tampering with the library loading process, the attacker can deceive the application into loading the malicious library instead. This can enable a wide range of attacks, including code injection, privilege escalation, and unauthorized access to sensitive data.
These vulnerabilities, if left unaddressed, can have severe consequences. Attackers can inject malicious code into an application, compromise its integrity, gain unauthorized access to critical resources, and potentially exploit other security vulnerabilities.
Examples of vulnerable implementations:
void loadDependency(String unsanitized_user_input) {
// Dynamically load the library without sanitizing the input
final dylib = DynamicLibrary.open(unsanitized_user_input);
// Resolve and call a function from the loaded library that contains malicous code
final libraryMethod =
dylib.lookupFunction<Pointer<Utf8> Function(), Pointer<Utf8> Function()>(
'getSensitiveData');
final result = libraryMethod();
}
func loadDynamicLibrary(unsanitized_user_input: String) {
// Attempt to dynamically load the library without sanitizing user input
if let libraryHandle = dlopen(unsanitized_user_input, RTLD_NOW) {
// Library loaded successfully, resolve a function that could contain malicous code
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) {
// Load the library dynamically without sanitizing the input
System.load(unsanitized_user_input)
// Perform some operation using the dynamically loaded library
val result = libraryMethod()
}
Recommendation
When dealing with dynamic library loading, A developer should:
- Implement robust input validation and sanitization techniques to prevent directory traversal and injection attacks.
- Only load libraries from trusted and verified sources, ensuring the integrity and authenticity of the libraries.
- Enforce strict access controls to prevent unauthorized library loading.
- Regularly update and patch libraries to address known vulnerabilities.
- Employ strong code signing and integrity verification mechanisms to ensure the integrity of dynamically loaded libraries.
Examples of secure implementations :
void validation(String input){
// Verify library file integrity
Uint8List fileBytes = libraryFile.readAsBytesSync();
Digest fileDigest = SHA256Digest().process(fileBytes);
Uint8List expectedChecksum = Uint8List.fromList([...]);
if (fileDigest.bytes != expectedChecksum) {
return false; // Invalid file checksum
}
if (/* checks for .. paterns */ )
return false; // Invalid path
// Add additional validation checks specific to your implementation
return true;
}
void loadDependency(String unsanitized_user_input) {
// sanitize user input
if (validation(unsanitized_user_input) == false)
throw FormatException("invalid input");
// Dynamically load the library with a validated input
final dylib = DynamicLibrary.open(unsanitized_user_input);
// Resolve and call a function from the loaded library
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 // Failed to read file data
}
let fileDigest = SHA256.hash(data: fileData)
// Compare the calculated checksum with the expected checksum
let expectedChecksum: [UInt8] = [ /* Replace with your expected checksum */ ]
if fileDigest != expectedChecksum {
return false // Invalid file checksum
if (/* checks for .. paterns */ )
return false; // Invalid path
// Add additional validation checks specific to your implementation
return true;
}
}
func loadDynamicLibrary(unsanitized_user_input: String) {
// Validate your user input
if !validation(unsanitized_user_input){
throw CustomValidationError.invalidInput
}
// Attempt to dynamically load the library with validated user input
if let libraryHandle = dlopen(unsanitized_user_input, RTLD_NOW) {
// Library loaded successfully, resolve a function that could contain malicous code
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){
// Verify library file integrity
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 (/* checks for .. paterns */ )
return false // Invalid path
// Add additional validation checks specific to your implementation
return true
}
fun loadDependency(unsanitized_user_input : String) {
// validate your uses input
if (!validation(unsanitized_user_input))
throw IllegalArgumentException("Invalid input")
// Load the library dynamically with the validated input
System.load(unsanitized_user_input)
// Perform some operation using the dynamically loaded library
val result = libraryMethod()
}
Links
Standards
- 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