Rootkit

Lecture



A rootkit (English rootkit , that is, a “root set”) is a set of software (for example, executable files, scripts, configuration files) to provide:

  • masking objects (processes, files, directories, drivers)
  • control (events occurring in the system)
  • data collection (system parameters)

The term Rootkit has historically come from the UNIX world, and this term is understood as a set of utilities or a special kernel module that an attacker installs on a hacked computer system immediately after obtaining the superuser's rights. This set, as a rule, includes various utilities for “tracing” traces of the invasion into the system, making invisible sniffers, scanners, keyloggers, and Trojans replacing the main UNIX utilities (in the case of a non-nuclear rootkit). Rootkit allows a hacker to gain a foothold in the hacked system and hide the traces of its activity by hiding files, processes, and the very presence of the rootkit in the system.

A rootkit can be installed into the system in various ways: download via an exploit, after receiving shell access (in such a case, a tool like wget or the original FTP client can be used to download the rootkit from a remote device), in the source code or software product resources.

Content

[remove]
  • 1 Rootkit classification
  • 2 Basic implementation methods
    • 2.1 In Microsoft Windows
      • 2.1.1 Capturing Call Tables
      • 2.1.2 Interception by Modifying Function Code
      • 2.1.3 DKOM (Direct Kernel Object Manipulation)
    • 2.2 UNIX and linux
  • 3 Additional features
  • 4 Legal rootkits
  • 5 Anti-rootkits
  • 6 Notes
  • 7 References
  • 8 Literature

Rootkit classification

  • By privilege level
    • User level ( user-mode )
    • Kernel level ( kernel-mode )
  • By the principle of action
    • modifying algorithms for performing system functions ( Modify execution path )
    • modifying system data structures ( Direct kernel object manipulation ) [1]

Basic implementation methods

In Microsoft Windows

There are various rootkit technologies, the most common: capturing call tables (IAT, IDT, SSDT, GDT), intercepting functions (for example, modifying the initial bytes), directly modifying system objects (DKOM), methods for using drivers.

Call Table Capture

The call table is an array in which each element stores the address of the corresponding procedure. Such tables exist in kernel mode (IDT, CPU MSRs, GDT, SSDT, IRP dispatch table), and in user mode (IAT).

Import Address Table (IAT) is the main table of user mode module calls. Most executable files have one or more built-in IATs containing addresses of library procedures imported from a DLL. [2]

On a multiprocessor machine, there are several instances of call tables (for example, IDT, GDT, MSR). Since each processor has its own system registers (in particular, GDTR - global descriptor table register (GDT), IDTR - interrupt table descriptor register (IDT) and IA32_SYSENTER_EIP - contains the virtual address of the input point in kernel mode (MSR)), it also has own system structures. [3]

When you change an entry in the call table, program execution is monitored and, if necessary, redirected to the required functions. An intercepted procedure can [4] :

  • block calls made by certain applications (for example, antivirus)
  • replace the original procedure
  • monitor the system by intercepting input parameters
  • filter output parameters

The general idea of ​​capturing is as follows:

  • Identify the call table, get its address
  • Save existing entry in the table
  • Replace entry with a new address
  • Restore original record

  Rootkit

If the interception function involves calling the original procedure, then blocking and monitoring are performed before the call, filtering the parameters after.

IAT is a table of calls placed in the file structure of the application. IAT stores the address of the procedures exported by a specific DLL. Each DLL with which the application locks at boot time has its own IAT. To capture the IAT, you must perform the following steps:

  • Get access to processor address space
  • Localize IAT in processor memory image
  • Modify required IAT
  Rootkit
Interception Call Table (IAT)

For IAT manipulation, access to the address space of the application to which the table belongs is required. One way is to inject a DLL. Among the methods for introducing a DLL into the address space of a process, you can specify [5]

  • Modifying the AppInit_DLL Registry Value
  • API call SetWindowsHookEx ()
  • Using remote threads

Interception by function code modification

The principle of operation is based on the fact that the first bytes of the intercepted functions are replaced by the interceptor code. It should be emphasized that when installing the interceptor, the code of the function being intercepted is not analyzed: the N first bytes change, not the first N machine commands. The consequence of this fact is [6] :

  1. the interceptor code can only be set at the beginning of the function;
  2. for each call of the intercepted function, the interceptor must restore its machine code before the call and re-intercept it after the end of the call.

Algorithm of the rootkit:

  1. An array is created in the interceptor body, in which the first N bytes of each of the intercepted functions are written (usually, the size of the modified code does not exceed 20 bytes)
  2. The array is filled with the reference machine code of the intercepted functions.
  3. At the beginning of each function being intercepted, a code is written that transfers control to the interceptor.

Interceptor operation algorithm:

  1. Sequence of actions determined by the attacker.
  2. Recovery of the first N bytes of the intercepted function.
  3. Calling an intercepted function.
  4. Re-modification of the machine code of the intercepted function: rewriting the code that transfers control to the interceptor into the first bytes.
  5. Analysis and, if necessary, modification of the results of the original function.
  6. Execute the ret operation, returning control to the program that called the function.

  Rootkit

To intercept, it is sufficient to modify the five first bytes of the function, in which place the jmp operation is transferred, which transfers control to the rootkit interceptor.

It should be noted that the simplest systems are protected against attacks of this type and check the first byte of the called functions for the presence of the machine operation code jmp. As a countermeasure measure, rootkit developers use methods of “masking” the code recorded at the beginning of the interceptor function (using commands like PUSH / RET, placing several NOP operators or a garbage code like PUSH AX / POP AH, as well as elements of polymorphism).

The method of modifying the first byte of functions has a number of disadvantages, mainly due to the need to restore the machine code of the intercepted functions before calling them and re-intercepting them after the call. These operations reduce system performance and can cause disruptions in multi-threaded applications.

DKOM (Direct Kernel Object Manipulation)

Windows NT operating systems use standard object models. The various components of the executing system define one or more types of objects. Each component exports, in kernel mode, a set of supported functions and properties, called a COM interface, for manipulating this type of object. No component can directly access another component object. Typical kernel mode objects are: [7]

  • a device type object (defined by the I / O manager, a type of privileged mode object used to represent a physical, logical, or virtual device)
  • file object
  • symbolic links
  • registry keys
  • threads and processes
  • dispatching object (the privileged mode object type class used to manage dispatch and synchronization processes)

This design provides flexibility and portability (portability), for example, future releases of the operating system may contain kernel components that define similar objects, but have a completely different internal structure. If such components export functions with preserved names and parameters, the change will have no effect. [eight]

Direct manipulation of kernel objects is a fairly powerful technology that is difficult to detect. However, there are a number of drawbacks, such as method instability, version dependence, implementation complexity due to the lack of a documented description of the structures and properties of objects. Despite these limitations, this method allows you to hide processes, device drivers, ports, increase the level of privileges of threads (hence, processes).

EPROCESS is a structure that serves as an internal representation of the process (process object). Windows uses a circular doubly linked list of EPROCESS structures to track the execution process. References linking EPROCESS objects are contained in the ActiveProcessLink field, whose structure is LIST_ENTRY [9] :

typedef struct _LIST_ENTRY {

  struct _LIST_ENTRY * Flink;
  struct _LIST_ENTRY * Blink;

} LIST_ENTRY, * PLIST_ENTRY;

The simplest process hiding algorithm:

  1. Getting a pointer to the process to which the current thread belongs, by calling PsGetCurrentProcess ()
  2. Getting the PID of the process
  3. If the PID does not match the desired one, a double-linked list is searched (ActiveProcessLinks field, type LIST_ENTRY)
  4. Change fields ActiveProcessLinks. In particular, the reference to the next block EPROCESS of block A is installed on block C, similarly the link to the previous block in block C. The links of block B are closed on its record. Thus, two lists are created, one of which consists of one element.

Excluding a process from the process list does not affect its execution. In Windows, code execution is planned at the thread level, the processes determine the context in which the threads are started. The process is hidden at the external level in tools that rely on the objects of EPROCESS processes, such as Task Manager. The kernel dispatcher uses a different accounting scheme that relies on other data structures (mainly the ETHREAD object). This method allows you to hide processes without losing functionality. [9]

Drivers. The Microsoft driver model supports a multi-layered architecture, so an I / O request (I / O request, data exchange between applications and drivers) can be serviced by a series of connected drivers, each of which performs its own task. The chain of drivers serving a physical device is called a stack. This modular approach allows new drivers to be included in the stack to increase functionality. In this case, only a separate part of the chain is changed or added. Also, some peripheral devices use the same controllers (and, accordingly, I / O buses). Modularity allows you to optimize the use of identical blocks of code, instead of writing a separate driver for each device.

The WDM model defines three types of drivers: a bus driver, functional drivers, and filter drivers. Filter drivers are usually located between other modules and capture IRPs passing through them. Before sending the IRP to the adjacent driver, the filter can view the contents or change it to affect the future behavior of the system. For example, when taking a disk image from a server that is critical to downtime, the driver filter can be used to modify the data stream in order to hide some files.

IRP packet (I / O request packet) is a Windows kernel data structure that provides data exchange between applications and the driver, as well as between the driver and the driver. When a request is received from an application, the I / O manager creates an appropriate IRP that localizes and sends to the top object in the driver stack. If the top driver was able to independently process the incoming IRP, it completes the request and returns the IRP to the I / O manager. Otherwise, the driver performs partial processing, localizes the underlying object in the stack and requests the I / O manager to transfer the IRP to the next driver.

When creating an IRP, the I / O manager reserves the memory area after the header. The allocated memory is used to write an array of IO_STACK_LOCATION structures allocated for each stack driver:

Memory size corresponds to the number of drivers in the stack. The array is numbered from 1, corresponding to the lower stack driver. The structure contains information about the driver control functions called by the I / O manager (MajorFunction and MinorFunction fields), parameters passed to the function (Parameters field, contents vary depending on the function), pointer to the driver object (DeviceObject), pointer to the completion function (CompletionRoutine field, this function is in the top level driver).

The driver management function, when it first receives the IRP, restores the parameters from the corresponding position in the I / O stack, making a call to IoGetCurrentIrpStackLocation (). Next, the prescribed actions are performed, after which, in the case of IRP forwarding to the lower stack driver, occurs:

  • setting the position of the I / O stack in the IRP
  • registration of the completion function (optional)
  • sending the IRP to the bottom driver
  • return status code (NTSTATUS)

There are two standard ways to set the stack position for the following driver: [10]

  • Current position is sent unchanged, function:

VOID IoSkipCurrentIrpStackLocation (IN PIRP Irp);

The function decrements the pointer to the IO_STACK_LOCATION array by one. Thus, when the IRP is sent, the pointer will be restored (automatically incremented by one), as a result, the same stack will be used. When using this method, there will be an unused area at the end of the stack.

  • If you need to transfer the contents of the current stack position, with the exception of the pointer to the completion function (the CompletionRoutine field), use:

VOID IoCopyCurrentIrpStackLocationToNext (IN PIRP Irp);

IRP transfer to the following driver is performed using the function: NTSTATUS IoCallDriver (IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);

The first argument is a pointer to the underlying driver object. The method of obtaining such an address is determined by a specific control function; there is no standard method.

  Rootkit
Completing IRP Processing

Each request must be completed either by the last driver in the stack (no further IRP forwarding is possible) or by one of the upstream.

The I / O manager initializes the completion process for a given IRP when any of the drivers that process the IRP calls the IoCompleteRoutine () termination function. When it is called, the I / O manager fills the portion of the I / O stack of the current driver with zeros, then calls the higher-level driver with the completion function set to this IRP. To determine how the lower level driver will process the request for a higher level driver function, only an I / O status block is available in the IRP.

Actually, the driver filter thus installed allows you to process not only incoming IRP packets (for example, block reading of a certain sector of the disk), but also manage the results of processing downstream drivers by initializing the completion function. [eleven]

Another way to implement rootkits is to modify the MBR and boot up to the operating system kernel, bootkits (for example, BackDoor.MaosBoot).

This type of malicious code in the Windows environment has been known since the early 1990s as stealth viruses.

UNIX and linux

  • implemented by the substitution of basic system utilities (very easily detected by means of integrity monitoring, in addition, easily blocked by means of access control *** such as SELinux or AppArmor;
  • implemented as a kernel module and based on VFS patching or interception of the system call table (sys_call_table);
  • based on the modification of the physical memory of the kernel.

Additional features

In addition to itself, a rootkit, as a rule, can mask the presence in the system of any directories and files on the disk described in its configuration, keys in the registry. For this reason, “mounted” rootkit libraries have naturally appeared. Many rootkits install their drivers and services into the system (naturally, they are also “invisible”).

Legal rootkits

Rootkits can “pop up” not only attackers. It is a well-known case when Sony has built in the similarity of a rootkit into its licensed audio CDs. Rootkits are in essence the majority of software copy protection tools (and means of circumventing these protections — for example, emulators of CD and DVD drives). They differ from “illegal” only in that they are installed with the knowledge of the user [ source not specified 1635 days ] .

Anti-rootkit

These are utilities or resident modules that detect the presence of rootkits in the system and (in varying degrees) remove them. There are many competing tools for this - both paid and free, but they all use similar principles of operation:

Finding discrepancies

Against MEP-rootkits. The same information is obtained in several ways using the API and "directly" and looking for discrepancies. In particular, import tables, the Native API table, the file system are usually scanned.

created: 2014-08-31
updated: 2021-03-13
132517



Rating 9 of 10. count vote: 2
Are you satisfied?:



Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Cryptanalysis, Types of Vulnerability and Information Protection

Terms: Cryptanalysis, Types of Vulnerability and Information Protection