• Keine Ergebnisse gefunden

Persistent Data-only Malware

2.2 Virtual Machine Introspection

2.3.2 Persistent Data-only Malware

Over the years, defense mechanisms improved again and were again able to detect such second stage malware. As the second stage introduces code into the system this code might also be detected by a defensive security system. Therefore malware authors are more and more required to implement not only the first exploits, but instead their entire malware leveraging code reuse techniques. This leaves two

Background

2.3. Code Reuse Attacks

possibilities for an attacker: Either the malware lacks of persistence and the attacked system has to be exploited over and over again to execute the malicious functionality. In this case, of course, the malware is not able to react on the behavior of the attacked system (e. g. system call hooking to implement, for example, a key-logger).

This also means that the malware is easily removable by simply fixing vulnerability which was exploited by the malware. An example for such a data-only rootkit was first published by Hundet al. [44].

Another possibility is to implement all rootkit functionality, includ-ing memory persistence, entirely with code reuse techniques. With persistent malware, in this context, we mean a rootkit that is part of the attacked system and may be activated during selected events within the attacked host, such as for example function hooking in the simplest case or on system call invocation or during interrupt handling. In addition, persistent data-only malware has the require-ment, to not only intercept certain events, but also to always hand control back to the original control flow. Persistent malware by its definition is not required to survive, for example, a system reboot.

Voglet al. [100] have shown, that it is possible to achieve a persistent data-only rootkit without modifying existing code or introducing new code into a system. Voglet al.‘s work also containsChuck, the, to our knowledge, first publicly available implementation of a persistent data-only rootkit. Although it was written as pure data-only rootkit, it provides key-logger functionality and is capable of hiding processes and files within the attacked system.

While code reuse exploitsusually only make use of a very small control data structure that simply allocates a writable and executable memory region which is then used to execute traditional shellcode, control data structures of data-only malware are in general quite large. The reason for this is that data-onlymalwaresolely relies on code reuse to function. Each functionality that the malware provides must be implemented by using code reuse. The result are huge chains that contain hundreds of reused instruction sequences [100].

As the author of this thesis was also involved in Vogl et al.‘s work, and his work serves as a motivation for this thesis, we, in the following,

2. Background

describe persistent data-only malware and the challenges involved to create such malware in more detail. First, we shortly discuss the general problems and requirements of persistent data-only malware and then introduce the architecture of the example implementation.

In a classical CRA scenario, an attack can typically be divided in to a first code reuse based exploit that in turn downloads a payload and the execution of that payload as a second chain. In an abstract view, this is also true for persistent data-only malware. While the first stage already contains the payload, it prepares the attacked system to trigger the second stage payload on certain hooks. For this, the first stage ROP chain is also called theinitialization chain.

The initialization chain needs to accomplish multiple steps. First it loads the second stage payload into a suitable memory location of the attacked process, that is not overwritten by the attacked process itself. Then, it alters the attacked system to regularly execute the second stage ROP chain. To remind the reader, this requires to load the virtual address of the payload into the stack pointer to load the chain (the stack pivot) and to execute a return instruction to redirect the control flow to the chains first gadget. In contrast to the first exploitation, where the attacker has a detailed view over the target and may have even control over multiple registers, there is only little influence to the current CPU state, once the second stage chain is triggered.

Up to Voglet al.‘s work the problem of executing callbacks in a return oriented rootkit was still an open problem [23]. Vogl et al.

propose to leverage unused hardware mechanisms as a stack pivot.

Amongst others, they propose to use thesysenter mechanism, a mechanism to trigger context switches from userspace to kernel space.

For this, also the stack pointer and the instruction pointer need to be replaced in an atomic manner. Onx86_64 systems, thesysenter mechanism is superseded by thesyscallinterface and is thus unused.

To use thesysentermechanism to create a callback to the persis-tent part of the data-only rootkit, the initialization chain modifies the appropriate model-specific register (MSR) registers. These are namely the registersIA32_SYSENTER_ESP andIA32_SYSENTER_EIP.

Background

2.3. Code Reuse Attacks

The first register is set up to hold the address of the start of the persistent stage. The second register is set up to hold the virtual address of areturninstruction. This way, every time asysenter instruction is executed, the persistent stage of the data-only rootkit is executed. Thus to enable the callback during an interesting event, the control flow must be redirected to execute a sysenter instruction.

For this, a pointer may be modified to point to the correct location.

Note that this is orthogonal to the use of the system call mechanism, as this typically uses thesyscallinstruction.

After we have described the initialization of the malware, we will now discuss the requirements to the persistent portion of the malware.

There are multiple problems, that an attacker needs to face in order to successfully implement such malware. The first problem, is that the control structure of the malware is on the stack. This means, that the executed instructions may also modify the stack and thus destroy the chain. This is especially a problem if parts of the chain execute external functions. A second problem is, that the malware may be triggered by multiple events at the same time. Thus the payload needs to be reentrant. A third major problem is, that the malware needs to restore the systems state after it finishes its execution. That is, not only must the malware store the current state of all registers, the registers need to be restored once the chain ends.

To comply with these requirements, Voglet al. propose to separate the persistent chain into three different sub-chains. Thecopy chain, thedispatcher chain, and thepayload chain. The copy chain is held to a minimum. Its only purpose is to save the current CPU state to a dedicated memory location that is already allocated by the initialization chain and to create a unique version of the dispatcher chain for each invocation. Thus each invocation of the dispatcher and the payload chain may destroy their chain while executing. In addition, thecopy chainuses the fact, that thesysentermechanism temporarily disables interrupts on the system. For this, it guarantees, different concurrent invocations of the callback do not interfere with each other. Lastly, the copy chain enables interrupts again and hands over control to the dispatcher chain. This next chain is

2. Background

Kernel StackCopy Chain(persistent)Payload Chain (volatile stack)Original RBPprepare Kernel Stackck PAYLOAD SAVE REGISTERS COPYDispatcher Switch to Dispatcher13restore Registers PAYLOADState Determine Process Switch to PayloadGLOBALState Dispatcher Chain(volatile Stack)ReserveMemory 2457Patch Payload COPYPayload 89106111213Leave;Ret;14

Figure 2.3.: This figure illustrates the tasks of the different ROP-chains required to create data-only malware. It is is originally taken from Figure 4 of [100].

then responsible to create a custom version of the payload chain by copying it to a new location in memory and modifying process relevant information. Finally, the task of the payload chain is to provide the malicious functionality and then to restore the original register state of the system at the time of the hook to solve the third problem described above. For this, it needs to access the information stored by the copy chain. A well-arranged summary of this process is given in Figure 2.3, originally taken from Figure 4 of the original work [100].

Note that the content of the original stack pointer is lost when leveraging the stack pivot mechanism described above. To solve this problem, the reference implementation makes use of the old frame pointer. As the callback used for the example rootkit is within the system call handler function, the implementation knows the offset between the stack pointer and the frame pointer at the time of the hook.

This has a big impact on defensive security mechanisms. Defenders not only need to implement code integrity mechanisms to ensure, that the code within a system is not malicious and can not be modified by an attacker. Also defenders need to be able to detect control structures for data only malware in memory by ensuring the integrity of the data memory that is contained within a system. This data can typically be separated into control flow relevant data like stacks and jump tables, as well as control flow irrelevant data. Voglet al. [99]

also showed, that it is possible to attack a system by only changing non-control data, as this data is also considered for control flow decisions.

Related W o rk

Chapter 3

Related Work

As we have discussed the background relevant for this thesis in the last chapter, we will now introduce related work and discuss its influence on this work.

3.1. Code Integrity Validation

One goal of this thesis is to efficiently and securely validate the integrity of kernel code of modern operating systems which perform different forms of self-patching during both loadtime and more im-portantly during runtime. In the following we introduce different existing solutions to code validation and motivate our research effort in this direction.

Lots of approaches where presented to handle CIV. Many of these use dedicated hardware extensions, like Trusted Platform Modules (TPMs) or leverage smart-cards to execute code sections which

de-serve particular protection. In contrast, in this work we focus on mechanisms that can be applied to modern operating systems using off-the-shelf hardware. Another avenue to protect code integrity is

3. Related Work

the application of program obfuscation. However it was shown, that program obfuscation is not applicable in practice [9, 10]. In addition, obfuscation based program integrity mechanisms aim to defend the code against malicious modification and hope, that unauthorized modification leads to a crash of the program. In our work we aim to validate the integrity of program code, even if some level of self modification is applied.