Vvun91e0n · 2015/10/04 but
Original: www.virusbtn.com/virusbullet…
By Patrick Wardleku
Translation level is limited, please understand, please correct
DLL hijacking is a well-known attack technique that has long been thought to affect only Windows systems. However, this article will show that OS X system also has dynamic link library hijacking. By taking advantage of the undocumented techniques and several features of OS X dynamic library Loaders, attackers load carefully crafted dynamic linked libraries containing malicious code into vulnerable programs. In this way, attackers can perform a variety of malicious actions, including: covert residence, process loading injection, bypassing security software, and of course, bypassing Gatekeeper (providing the opportunity for remote injection). Because the attacker takes advantage of legitimate function calls provided by the operating system, it can only be defended and cannot be completely patched. This article provides techniques and tools for finding vulnerable binaries, as well as for detecting if hijackings have occurred.
0 x01 background
Before going into the details of the Dynamic Library (Dylib) hijacking attack on OS X, let’s look at the Dynamic Link Library (DLL) hijacking attack on Windows. Because the two attacks are conceptually similar. Learning mature Windows platform attack methods can help you understand OS X platform methods.
DLL hijacking is defined by Microsoft as: “When a program loads a DLL dynamically, Windows will try to search for the DLL in some of the default directories if the full path is not given. If an attacker gains control of one of these directories, he can have a program load a malicious DLL in place of the original one.” 【 1 】
It should be noted that the default search path of the Windows loader is to search some specific directories (such as the directory where the program is located or the current working directory) before searching the Windows system directory. This processing strategy leads to vulnerabilities. For example, a program tries to load a system library without a full path, giving only the name. At this point, an attacker planted a malicious DLL with the same name in the previous search directory. The Windows loader will find the malicious DLL first, rather than the original legitimate DLL, and load it into the vulnerability program.
As illustrated in Figures 1 and 2 below, a vulnerable program is hijacked by a malicious DLL. The malicious DLL is in the current working directory.
Figure 1 Loading a normal system DLL
Figure 2 loading the attacker’s malicious DLL
DLL hijacking attacks first gained widespread impact in 2010 and quickly gained media and hacker attention. With names like “binary implant”, “insecure library loading”, “DLL prefab attack” and so on. The person who discovered this vulnerability is widely believed to be H.D.Moore [2], [3]. However, the NSA was the first to discover the vulnerability, 12 years before Moore’s discovery. In 1998, the NSA described the DLL hijacking vulnerability and warned against it in its unclassified ‘Windows NT Security Guidelines’ :
‘It is important that an attacker cannot insert a fake DLL with the same name before the searcher finds a legitimate DLL.’ [4]
DLL hijacking can be used in many ways by an attacker. For example, an attacker can make a malicious library start loading quietly (without changing any registration information or other system components), permissions can be promoted, and even remote infections can be carried out.
Malware authors were quick to recognize the advantages of DLL hijacking. In a blog post “What the FXSST? “[5] In it, Mandiant researchers described how they had discovered a number of different, unrelated samples of malware called fxSst.DLL. Upon further investigation, they found that these samples exploited a DLL hijacking vulnerability in Windows shell (Explorer.exe). The vulnerability provides a way to secretly reside on the system. The reason is that since Explorer. Exe is installed in C:\Windows, embedding a malicious dynamic library file called FXsst.dll in this directory will successfully host the malicious DLL on the system. Because the loader will search the program directory before it searches the system directory where the real FXSst.DLL exists.
Another example of malware using DLL hijacking techniques can be found in the leaked banking Trojan ‘Carberp’ [6]. The source code shows that the malware bypasses UAC by hijacking the DLL of sysprep.exe (Figure 3). This application is an automatic empowerment process, that is, it does not require any UAC requests to obtain higher permissions. Unfortunately, it has DLL hijacking vulnerability, which can be used by attackers to load malicious DLLS (cryptbase.dll) [7].
Figure 3. Carberp uses DLL hijacking to bypass UAC
DLL hijacking has become rare on Windows platforms recently. Microsoft moved quickly to counter the attack, patching vulnerable applications and detailing how to avoid the problem (for example, specifying an absolute path to DLLS that need to be loaded) [8]. However, operating system-level defenses are required, such as safedLlSearchMode or cwdillegalindllSearch registry key enabled to prevent most DLL hijackings.
0 x02 Dylib hijacked
There was a problem with dynamic library hijacking that was thought to be unique to a Windows platform. However, as an astute StackOverflow user pointed out in 2010, ‘any operating system that allows dynamic linking to external libraries is theoretically vulnerable’ [9]. It took him until 2015 to prove it right. This article will reveal the destructive dynamic library hijacking techniques in OS X.
The purpose of this study is to reveal whether OS X platform is vulnerable to dynamic library attacks. Furthermore, this study needs to answer the following question: under OS X platform, whether an attacker can implant a malicious dynamic library that can be automatically loaded into the vulnerability program by the loader. The assumption is that hijacking on OS X can be as effective as DLL hijacking on Windows, allowing the attacker to achieve a large number of attacks. Such as clandestine resident, load-time injection, secure software bypass, and perhaps remote infection.
It should be noted that this study was based on some limitations. First, success is limited to making no changes to the system, other than creating files (or folders). To put it another way, this study ignores the attack environment requirements that require modifications to particular binaries (such as patches) or system configuration files (such as’ auto-run ‘plists, etc.). Such attacks are well known, easy to prevent and detect, and therefore ignored. This study tries to find a hijacking method that is independent of the user environment. OS X also provides a variety of legal ways to load dynamic libraries, allowing the loader to force automatic loading of malicious libraries into the target process. These methods, such as setting the DYLD_INSERT_LIBRARIES environment variable, are user-specific, well-known, and easy to detect. So we don’t study it, we just ignore it.
This study begins with an analysis of OS X’s dynamic connector and loader: DYLD. This binary file in /usr/bin provides standard loader and connector functionality for finding, loading, and connecting dynamic libraries.
Because Apple made DyLD open source [10], it was easy and straightforward to analyze. For example, reading the source code gives you a good understanding of how DYLD is loaded as an executable, including the loading and wiring of the libraries it depends on. The following points briefly summarize the steps to begin DYLD (focusing on those relevant to this study)
- When any new process starts, the kernel sets the user mode entry point to __dyLD_start (dyLDstartup.s). This function simply sets the stack and jumps to dyldbootstrap::start(), which jumps to _main() of the loader.
- The _main() function of Dyld (dyld.cpp) calls link(), which then calls the Link () method of an ImageLoader object to start the main program’s connection process.
- The ImageLoader class (imageloader.cpp) contains many functions called by DYLD to implement binary loading logic. For example, the class contains the link() method. When called, this method calls the object’s recursiveLoadLibraries() method to load all the required dynamic libraries.
- ImageLoader’s recursiveLoadLibraries() method identifies all the required libraries and then calls Context.loadLibrary () to load them one by one. The Context object is a simple structure that contains function Pointers passed between methods and functions. The loadLibrary member of this structure is initialized in the libraryLocator() function (dyld.cpp), which simply calls the load() function.
- The load() function (dyld.cpp) calls various helper functions, loadPhase0() to loadPhase5(). Each function is responsible for a specific task of the loading process’s work. For example, parsing paths or handling environment variables that affect the loading process.
- After loadPhase5(), the loadPhase6() function loads the required dylib from the file system into memory. An instance object of the ImageLoaderMachO class is then called. To complete the specific load and connect logic for each Dylib object Mach O file.
With the basic dyLD initial loading logic understood, the research focus shifted to finding the logic that could dylib hijack. In particular, the team was interested in code that failed to report an error when the loader did not find a Dylib, and in code that looked for dylib in multiple places. If any of these scenarios are found in the loader, we can hopefully do OS X’s Dylib hijacking attack.
We first looked at the first scenario, in which we assumed that a loader could handle the situation where dylib was not found, and that an attacker could place a malicious Dylib in that location. Thus, the loader finds the placed Dylib and loads the attacker’s malicious code unchecked.
In retrospect, the loader calls the ImageLoader class’s recursiveLoadLibraries() method to find and load all required libraries. As figure 4 shows, the code in the load code that handles dylib load failures is contained in the try/catch block.
FIG. 4 Processing logic when dyilB fails to load
As expected, the processing logic throws an exception (with a message) when the library fails to load. Interestingly, this only throws an exception if a variable called ‘required’ is set to true. In addition, the comments in the source code indicate that it is ok to fail to load the ‘weak’ library. This means that in some cases, the loader loads some libraries also will continue to work properly – | | is great!
Dig into the source code of the loader program to find out where the ‘required’ variable is set. The result is that the doGetDependentLibraries() method of the ImageLoaderMacho class parsed the load command (described below) and assigned the variable by the LC_LOAD_WEAK_DYLIB flag bit of the load command.
Load commands are a required part of the Mach-O file format (OS X’s native binary format). Following the Mach-o header in the file, it provides different commands to the loader. For example, load commands can be used to specify binaries
Figure 5 sets the required variable
The layout of the component in memory, the initial execution state of the main thread, and the details of the required dynamic library. You can use the tool to view information about load commands for compiled binaries. Such as MachOView [11], or /usr/bin/otool (using the -l argument). (See Figure 6)
The code in Figure 5 shows the loader processing all the load commands in turn, looking for all the dynamic libraries that declarations are poured into. The definitions of these load commands can be found in the mach-o/loader.h file.
Figure 6 shows the loading command for Calculator.app through MachOView
Figure 7 Format of the LC_LOAD_* load command
The corresponding executable program needs each dynamic link library, and the program header contains a LC_LOAD_* loading command (LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, etc.). As shown by the loading code in Figure 4 and figure 5, the LC_LOAD_DYLIB load command declares a required dynamic library, and the library declared through LC_LOAD_WEAK_DYLIB is optional. In the previous case (LC_LOAD_DYLIB), an exception is thrown if the required library is not found, and the loader gives up and terminates the process. But in the latter case (LC_LOAD_WEAK_DYLIB), the dynamic library is optional and no impact is declared if it is not found. The main program will continue.
Figure 8 trying to load the weak library
The loader logically satisfies the condition of the first hypothetical hijacking scenario, so that a dynamic library hijacking attack can be carried out against the OS X platform. In other words, as shown in Figure 9, if a declared weak reference library is not found, an attacker can place a malicious dynamic library file at that location. The loader then finds the attacker’s dynamic library and loads the malicious code into the vulnerability’s process space.
Figure 9 hijacking through a malicious’ weak ‘dynamic library
Another hijacking attack mentioned earlier assumes that a loader is looking for dynamic libraries in multiple places. In this case, it is assumed that an attacker could place a malicious dynamic library in one of the search directories (the legitimate dynamic library is elsewhere). Let the loader find the attacker’s malicious dynamic library first, and load the attacker’s malicious dynamic library directly without checking.
On OS X, load commands like LC_LOAD_DYLIB always give the path to the dynamic library (Windows only gives the name of the dynamic library). Because the path is given, the DYLD loader does not need to search different directories to find dynamic libraries, but instead loads dylib directly into the specified directory. However, an analysis of dyLD source code revealed that dyLD did not do this in one of the cases.
As shown in Figure 10, there is some interesting processing logic in the loadPhase3() function in dyld.cpp.
Figure 10 loading libraries that depend on ‘rpath’
Dyld iterates over the RP -> Paths vector to dynamically build the paths (stored in the ‘newPath’ variable) and then calls the loadPhase4 () function. This satisfies the requirements of the second hijack scenario (dyld looking for the same dylib in multiple locations), and of course requires a bit of path order checking.
In Figure 10, [email protected] is the document, which is a special load keyword (introduced in OS X 105, Leopard) that defines a dynamic library as’ run-path-dependent Library ‘[12]. Apple explains that run-Path-Denpendent Library is a dependent library whose full installation path is not known at the time of creation. Other documents [13] and [14], etc., provide more detail on what this library does, [email protected] : ‘Frameworks and dynamic libraries to finally be built only once and used for both system-wide installations and embedding without changes to their install names, and allowing applications to provide alternate locations for a given library, Or even override the location specified for a deeply embedded library ‘[14].
This feature makes it easier for software developers to deploy complex programs, but it also facilitates dynamic library hijacking. In order for an executable program to use the run-path-dependent library, it needs to provide the loader with a list of search paths at runtime, and the loader finds these libraries at load time [12]. This code can be found in many places in dyLD code. Include the code snippet shown in Figure 10.
Because the run-path-dependent library is a relatively new and somewhat unknown concept, it is necessary to provide an example that includes the run-path-dependent library and an example program that uses the library.
A run-path-dependent [email protected]ylib. As shown in Figure 11, creating such a dynamic library in Xcode is as simple as installing dylib’s [email protected]
Figure 11. Creating a run-path-dependent library
When the run-path-dependent library is successfully compiled, check the dylib runtime path shown by the LC_ID_DYLIB load command (which contains the dylib identifier). In particular, the ‘name’ field in the LC_ID_DYLIB load command shows the name of the dylib file (rpathlib. framework/ Versions/A/rpathLib) [email protected]
[email protected]
It is also straightforward to build a program that loads the run-path-dependent library. First, add the run-path-dependent library to Xcode’s Libraries list. Then, add the run-path Search Paths to the ‘Runpath Search Paths’ list. Finally, these search directories will be searched when the dynamic loader loads the library to determine the specific directory of the run-path-dependent library.
Figure 13 link setup for the @rPath library and declare the run path search path
Once the application is created, the loading command for the program displays various commands related to the run-path dependency library. A standard LC_LOAD_DYLIB load command provides information for the associated dependencies of run-path-dependent dylib that need to be loaded, as shown in Figure 14.
Figure 14 dependencies for the @rpath library
In Figure 14, notice that the installation name name entry points to run-path-dependent [email protected] and is the same as the name value of the LC_ID_DYLIB command for run-path-dependent dylib in Figure 12. The LC_LOAD_DYLIB load command that the program contains associated with run-path-dependent dylib tells the loader: ‘I need rapthLib dylib, but I don’t know where it is installed at the time of building. Please find and load it using the run-path search path I included. ‘
We previously added run-path Search Paths to the ‘Runpath Search Paths’ form in Xcode. These search paths generate LC_RPATH load commands in the program, one for each path. Looking at the compiled program, you can see the LC_RPATH load command included, as shown in Figure 15.
Figure 15 Run-path search path in the load command
By understanding run-path-dependent dylib and the program to load it, we can understand the dyLD source code responsible for loading the dynamic library more easily.
When a program starts, dyLD will parse the program’s LC_LOAD_* load command to load and connect all dependent dylibs. For run-path-dependent libraries, dyLD is divided into two steps: extract all the contained run-path search paths, and then search for and load all the run-path-dependent libraries through the search path list.
To extract all run-Path search paths, Dyld calls the getRpaths() method of the ImageLoader class. This method (called by the recursiveLoadLibraries() method) simply parses all the LC_RPATH load commands in the program. For each of these load commands, DyLD extracts the run-path search path and adds it to a vector (for example, a table), as shown in Figure 16.
Figure 16 Extract and save all the built-in run-path search paths
With the run-path search path list, dyld can find all the dependent run-path-dependent libraries. This logic is in the loadPhase3() function of dyld. CPP. As shown in Figure 17, the [email protected] word. If so, Dyld iterates through the run-path search table, [email protected], and then tries to load dylib from the newly generated path.
Figure 17 Search run-path search directory, [email protected]
It is important to note that the path order of the DYLD search is determined in accordance with the order of the LC_RPATH load command. The code snippet shown in Figure 17 shows that the search loop will keep searching until either the target dylib is found or all paths are searched.
Figure 18 illustrates the search process. You can see that Dyld searched for different run-path search paths to find the desired run-path-denpendent dylib. Notice that in this example, the target dylib is found in the second search directory.
Figure 18 Dyld searching multiple run-path search directories
To summarize the findings so far: an OS X system can be hijacked if any program has any of the following conditions: 1, contains a LC_LOAD_WEAK_DYLIB load command, but the associated dylib does not exist. 2, including a LC_LOAD*_DYLIB load command pointing to a run-path-denpendent library ([email protected]’) and multiple LC_RPATH load commands. And the run-path-Denpendent library is not in the first run-path search directory.
The rest of this article covers a complete dylib hijacking attack, then several different attacks (resident, load-time hijacking, remote injection, etc.), and concludes with a summary of how to defend against such attacks.
To help readers better understand dylib hijacking attacks, we will try to give details of hijacking attacks, including attempted attacks, errors encountered, and success. With this knowledge, it is easier to understand automated attacks, attack scenario identification, and how to defend against them.
Review the example program described earlier (‘ rpathapp.app ‘). We used to explain the run-path-denpendent dylib connection. This program will be the target of a hijack attack.
Dylib hijacking attacks can only target programs with vulnerabilities (programs that meet one of the two hijacking conditions described earlier). Because this example program (rpathapp. app) needs to connect to a run-path-dependent dylib, it may satisfy the second condition above. The easiest way to detect this is to enable debug Logging in the loader and simply run the program from the command line. To enable this logging, you need to set DYLD_PRINT_[email protected][email protected] to an existing vulnerability (for example, the first extension points to a non-existent dylib) as shown in Figure 20.
Figure 20 Test program rPathApp with vulnerability
Figure 20 shows that when the loader first looks for the target dylib, it does not find it at the specified location. In this case, as shown in Figure 19, an attacker can deploy a malicious dylib to the path just searched the first time, after which the loader loads the malicious library.
We created a simple dylib to act as a malicious hijacked library. To enable automatic execution at load time, the dylib implements a constructor. This constructor is automatically executed after a successful dylib load. This is a nice feature because normal Dylib code does not execute until the main program calls one of its export functions.
Figure 21 A dylib constructor will execute automatically
When the build is complete, rename dylib to the name of the target library: rpathlib. Need next, create the directory structure (Library/One/rpathLib framework Versions / / A) and A dylib malicious copy into the directory. This ensures that whenever the program is started, Dyld will find hijack Dylib when searching for run-path-denpendent dylib.
Figure 22 Malicious dylib is placed in the first run-path search directory
Unfortunately, this hijacking attempt failed. The program crashed unexpectedly. As shown in figure 23.
Figure 23 successfully parses the path and then crashes
It failed, but the good news is that the loader found and tried to load hijacked dylib (see ‘RPATH Successful Expansion… ‘Log message). Although the program crashed, the loader threw a detailed exception message. This exception appears to be self-explanatory: the version of the hijacked library is different from the required version. Re-examining the loader’s source code, I found the code that threw this exception. As shown in figure 24.
Figure 24. Dyld extraction and more appropriate version numbers
As you can see, the loader calls the doGetLibraryInfo() method to extract the compatible and current version numbers from the LC_ID_DYLIB load command in the loaded library. The extracted compatible version number (‘minVersion’) is then compared with the version requested by the program. If the version number is too low, an incompatible exception will be thrown.
Fixing this compatibility problem is not difficult, just by updating the version number in Xcode and recompiling it. As shown in figure 25.
Figure 25 Setting compatibility and the current version number
Check the LC_ID_DYLIB load command for recompiled hijack dylib. Verify that the version number has been updated. As shown in figure 26
Figure 26 Compatible version and current version
The updated version of hijacked dylib is copied into the program’s first run-path search directory. Restarting the vulnerability shows that the loader found hijack Dylib and tried to load it. But although the dylib version is now compatible. But a new exception is thrown, and the program crashes again. As shown in figure 27.
Figure 27 ‘Symbol not found’ exception
Again, the explanation given by the exception makes it clear why the loader threw the exception. The purpose of a program to connect to a dynamic library is to obtain the functions (such as functions, objects, etc.) exported by the dynamic library. Once the required dylib is loaded into memory, the loader attempts to parse (by exporting symbols) the function object that the dependent library is trying to export. If the function object is not found, the connection fails and the connection process terminates, causing the main program to crash.
There are several ways to ensure that hijacking dylib produces the correct symbol table so that it can be fully joined. A simple way to do this is to hijack dylib and directly copy the exported information of the target dylib. Maybe this will work, it seems a bit complicated and different dylibs have different characteristics (for example, attacking another dylib requires additional export information). A more elegant approach is to simply tell the connector to look elsewhere for the symbol it requires. The other place, of course, is the legal dylib. In this scenario, hijacking dylib would simply be a proxy or a ‘re-exporter’ dylib, and the loader would follow its re-export instructions and no connection errors would be thrown.
Figure 28 Re-export a valid dylib
It takes some effort to get the re-exported library to work perfectly. The first step is to go back to Xcode and add multiple linked flags to the hijack dylib project. These flags include ‘-xlinker’, ‘reexport_library’, and then the path to the target library that contains the interface the vulnerability actually needs to export.
Figure 29 requires a link flag to implement re-exporting
These link flags generate a built-in LC_REEXPORT_DYLIB load command. This contains the path to the target dylib. As shown in figure 30.
Figure 30 The built-in LC_REEXPORT_DYLIB load command
However, things are not so simple. Because the hijacked dylib reexport target is a run-path-Denpendent library. LC_REEXPORT_DYLIB (exported from legal dylib LC_ID_DYLIB load command) [email protected], because unlike LC_LOAD*_DYLIB load command, Dyld does not resolve the run-path-denpendent path in the LC_REEXPORT_DYLIB load command. In other words, [email protected][email protected].
[email protected], provide the full path of the target library to the LC_REEXPORT_DYLIB load command. This requires the help of An Apple developer tool: Install_name_tool. To update install name in the LC_REEXPORT_DYLIB load command. The tool is executed with the -change option, followed by the existing name (in LC_REEXPORT_DYLIB), and the new name, which hijacks the path to dylib. As shown in figure 31.
Figure 31 uses Installl_tool_name to update the built-in name
After the LC_REEXPORT_DYLIB load command is updated correctly, hijacked dylib is copied back to the first run-path search directory of the main program and the program restarts. Figure 32 shows the successful execution.
Figure 32 successful hijacking of a buggy program
To recap: Because rPathApp connects to a run-path-denpendent library that was not found in the first run-path search directory, dylib hijack vulnerability exists. Embedding a specially compatible malicious dylib in the first search directory will cause the loader to blindly load the malicious dylib every time the program executes. Since the malicious dylib has the correct version information, it also re-exports all symbols of the legitimate target dylib and resolves all needed symbols, thus ensuring that the functionality of the program is not compromised.
0 x03 reference
- Secure loading of libraries to prevent DLL preloading attacks. blogs.technet.com/cfs-file.as… .
- DLL about. En.wikipedia.org/wiki/Dynami… .
- Dynamic – the Link Library about. www.exploit-db.com/wp-content/… .
- Windows NT Security Guidelines. www.autistici.org/loa/pasky/N… .
- What the fxsst? www.mandiant.com/blog/fxsst/.
- Leaked Carberp source code. github.com/hzeroo/Carb… .
- Windows 7 UAC whitelist: Proof – of – concept source code. www.pretentiousname.com/misc/W7E_So… .
- Microsoft Security Advisory 2269637; Insecure Library Loading Could Allow Remote Code Execution. technet.microsoft.com/en-us/libra… .
- What is dll hijacking? Stackoverflow.com/a/3623571/3… .
- OS X loader (dyld) source code. www.opensource.apple.com/source/dyld.
- MachOView. Sourceforge.net/projects/ma… .
- The Run – Path Dependent Libraries. Developer.apple.com/library/mac… .
- Using the @ rpath: according to the and How. www.dribin.org/dave/blog/a… .
- Friday Q&A: 2012-11-09 dyld: Dynamic Linking On OS x. www.mikeash.com/pyblog/frid… .