├── .gitattributes ├── png ├── CS-01.png ├── CS-02.png ├── S1-01.png └── S1-02.png ├── README.md └── SafetaskList.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /png/CS-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyxiaxiang/Safetasklist/HEAD/png/CS-01.png -------------------------------------------------------------------------------- /png/CS-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyxiaxiang/Safetasklist/HEAD/png/CS-02.png -------------------------------------------------------------------------------- /png/S1-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyxiaxiang/Safetasklist/HEAD/png/S1-01.png -------------------------------------------------------------------------------- /png/S1-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyxiaxiang/Safetasklist/HEAD/png/S1-02.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Safetasklist 2 | 3 | ## 简介 / Introduction 4 | 5 | **Safetasklist** 是一款旨在方便、快速列出没有加载部分已知EDR(如 Checkpoint, SentinelOne, CrowdStrike, Qianxin TianQing, Trellix, Bitdefender 等)DLL的进程的工具。该工具适用于红队任务,帮助红队成员筛选可能不被监控的进程。工具会根据进程类型(.NET 和 PE)进行分类,并排除已知的黑名单进程,最终推荐较为OPSEC的进程。 6 | 7 | 该工具具有以下功能: 8 | 9 | - 快速列出进程,并判断是否加载了特定的EDR DLL。 10 | - 分析进程类型:.NET 进程和 PE 进程。 11 | - 排除已知的系统和黑名单进程,确保检测结果更加精确。 12 | - 推荐较为OPSEC的进程。 13 | - 支持扩展和更新进程及DLL列表,欢迎用户提交新的进程和DLL以供更新。 14 | 15 | **Safetasklist** is a tool designed to quickly list processes that do not load certain known EDR DLLs (e.g., Checkpoint, SentinelOne, CrowdStrike, Qianxin TianQing, Trellix, Bitdefender). The tool is useful for red team operations, helping red team members identify processes that may be less monitored. It categorizes processes as either .NET or PE type, excludes known blacklist processes, and ultimately recommends processes that are more OPSEC-friendly. 16 | 17 | Key features of the tool include: 18 | 19 | - Quickly lists processes and checks if specific EDR DLLs are loaded. 20 | - Categorizes processes into .NET and PE types. 21 | - Excludes known system and blacklist processes for more accurate results. 22 | - Recommends more OPSEC-friendly processes. 23 | - Supports expansion and updates to process and DLL lists. Contributions are welcome! 24 | 25 | ## 使用说明 / Usage 26 | 27 | 1. **下载 / Download**: 从 [GitHub Releases](https://github.com/kyxiaxiang/Safetasklist/releases) 下载最新版本。 28 | 2. **编译 / Compile**: 使用 CSC 命令编译源码。可以使用 CS 内存加载.NET,推荐使用以下项目: 29 | - [PatchlessInlineExecute-Assembly](https://github.com/VoldeSec/PatchlessInlineExecute-Assembly) 30 | - [InlineExecute-Assembly](https://github.com/anthemtotheego/InlineExecute-Assembly) 31 | 3. **运行 / Run**: 运行工具并查看输出结果,其中包含了符合条件的进程列表。 32 | 4. **提交更新 / Submit Updates**: 如果您有新的进程或DLL信息,欢迎向本项目提交更新,帮助工具持续改进。 33 | 34 | 1. **Download**: Download the latest version from [GitHub Releases](https://github.com/kyxiaxiang/Safetasklist/releases). 35 | 2. **Compile**: Compile the source code using the CSC command. You can load .NET in memory using CS, and it's recommended to use: 36 | - [PatchlessInlineExecute-Assembly](https://github.com/VoldeSec/PatchlessInlineExecute-Assembly) 37 | - [InlineExecute-Assembly](https://github.com/anthemtotheego/InlineExecute-Assembly) 38 | 3. **Run**: Run the tool and check the output, which includes a list of processes that meet the criteria. 39 | 4. **Submit Updates**: If you have new process or DLL information, feel free to contribute and submit updates to improve the tool. 40 | 41 | ## 支持的EDR / Supported EDRs 42 | 43 | 当前支持以下EDR产品的DLL监测: 44 | 45 | - Checkpoint 46 | - SentinelOne 47 | - CrowdStrike 48 | - Qianxin TianQing (奇安信天擎) 49 | - Trellix 50 | - Bitdefender 51 | 52 | 后续版本将增加更多支持的EDR,敬请期待。 53 | 54 | Currently, the tool supports monitoring DLLs from the following EDR products: 55 | 56 | - Checkpoint 57 | - SentinelOne 58 | - CrowdStrike 59 | - Qianxin TianQing (奇安信天擎) 60 | - Trellix 61 | - Bitdefender 62 | 63 | More EDRs will be added in future versions, stay tuned. 64 | 65 | 66 | 67 | ![](https://github.com/kyxiaxiang/Safetasklist/blob/main/png/CS-01.png?raw=true) 68 | 69 | ![](https://github.com/kyxiaxiang/Safetasklist/blob/main/png/CS-02.png?raw=true) 70 | 71 | ![](https://github.com/kyxiaxiang/Safetasklist/blob/main/png/S1-01.png?raw=true) 72 | 73 | ![](https://github.com/kyxiaxiang/Safetasklist/blob/main/png/S1-02.png?raw=true) 74 | 75 | 在演示中,SentinelOne开启了完整的激进模式,几乎所有的进程都被监控。因此,可以看到推荐的OPSEC进程列表为空。但红队操作员仍然可以观察到,系统中存在三个可以使用的进程。然而,在加载网络通讯模块时,操作员需要格外小心,以避免被EDR监控到。 76 | 77 | In the demo, SentinelOne is configured with full aggressive mode, where almost all processes are monitored. As a result, the recommended OPSEC process list is empty. However, red team operators can still observe that three processes are available for use. Care should be taken when loading network communication modules to avoid detection by the EDR. 78 | 79 | ## 特性 / Features 80 | 81 | - 自动检测没有加载已知EDR DLL的进程。 82 | - 分类列出 `.NET` 和 `PE` 类型的进程。 83 | - 排除已知的黑名单进程,减少干扰。 84 | - 推荐较为OPSEC的进程。 85 | - 易于扩展和定制,支持用户提交新的进程和DLL信息。 86 | 87 | - Automatically detects processes that do not load known EDR DLLs. 88 | - Categorizes processes into `.NET` and `PE` types. 89 | - Excludes known blacklist processes to reduce noise. 90 | - Recommends more OPSEC-friendly processes. 91 | - Easy to extend and customize, supporting contributions of new process and DLL information. 92 | 93 | ## 贡献 / Contributing 94 | 95 | 欢迎大家为这个项目贡献新的进程和DLL列表,或者提供其他的改进意见。请通过提交Pull Request或在Issues中提出您的建议。 96 | 97 | Contributions of new process and DLL lists, or suggestions for improvements, are welcome! Please submit Pull Requests or open Issues to share your ideas. 98 | 99 | ## License 100 | 101 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 102 | -------------------------------------------------------------------------------- /SafetaskList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using System.Runtime.InteropServices; 6 | 7 | class Program 8 | { 9 | static void Main() 10 | { 11 | // Keywords 12 | string[] dllKeywords = new string[] 13 | { 14 | "InProcessClient*", "bdhkm*", "atcuf*", "FlexHook*", "SBA_ISWWH*", 15 | "cphnt*", "nddPrint.Agent.SpoolMonitor*", "cphusr*", "umppc*", "CsXumd*", 16 | "mfehcinj*", "mfehcthe*", "mvcairo*", "mfedeeprem*", "TmUmEvt*", 17 | "tmmon*", "TmUmSnsr*", "qmhookhelper*", "qmdlphook*", "libcimudisk*", "SafeBase*", "LHShield*" 18 | }; 19 | 20 | // Network DLLs to monitor 21 | string[] networkDlls = new string[] { "wininet.dll", "winhttp.dll", "ws2_32.dll" }; 22 | 23 | // Processes to exclude from monitoring 24 | string[] excludeProcesses = new string[] 25 | { 26 | "AddInProcess", "AddInProcess32", "AddInUtil", "AppLaunch", 27 | "aspnet_compiler", "aspnet_regbrowsers", "aspnet_regiis", "aspnet_regsql", 28 | "aspnet_state", "aspnet_wp", "CasPol", "ComSvcConfig", "csc", "cvtres", 29 | "DataSvcUtil", "EdmGen", "ilasm", "InstallUtil", "jsc", "Microsoft.Workflow.Compiler", 30 | "MSBuild", "mscorsvw", "ngen", "ngentask", "RegAsm", "RegSvcs", "ServiceModelReg", 31 | "vbc", "WsatConfig", "dllhost", "regsvr32", "GPUpdate", "SearchProtocolHost", 32 | "msiexec", "rundll32", "dwm", "lsass", "taskhostw", "vmtoolsd" 33 | }; 34 | 35 | // Get all processes 36 | var processes = Process.GetProcesses(); 37 | 38 | // Lists to store processes that meet OPSEC criteria for PE and .NET processes 39 | List opsecPeProcesses = new List(); 40 | List opsecNetProcesses = new List(); 41 | List opsecAttentionProcesses = new List(); 42 | 43 | // List to store information about all processes 44 | List allProcesses = new List(); 45 | 46 | foreach (var process in processes) 47 | { 48 | try 49 | { 50 | string processName = process.ProcessName; 51 | int processId = process.Id; 52 | 53 | // Skip excluded processes 54 | if (excludeProcesses.Contains(processName, StringComparer.OrdinalIgnoreCase)) 55 | continue; 56 | 57 | var status = GetProcessStatus(process, dllKeywords); 58 | var type = GetProcessType(process); 59 | var networkDllStatus = GetNetworkDllStatus(process, networkDlls); 60 | var privilege = GetProcessPrivilege(process); 61 | 62 | // Add process information to the list 63 | allProcesses.Add(new ProcessInfo 64 | { 65 | ProcessId = processId, 66 | ProcessName = processName, 67 | Status = status, 68 | Type = type, 69 | NetworkDllStatus = networkDllStatus, 70 | Privilege = privilege 71 | }); 72 | 73 | // If the process meets OPSEC rules, classify and store it 74 | if ((type == "[PE]" && status == "[Safe]" && networkDllStatus == "[Loaded]") || 75 | (type == "[.NET]" && status == "[Safe]" && networkDllStatus == "[Loaded]")) 76 | { 77 | if (type == "[PE]") 78 | { 79 | opsecPeProcesses.Add(new ProcessInfo 80 | { 81 | ProcessId = processId, 82 | ProcessName = processName, 83 | Status = status, 84 | Type = type, 85 | NetworkDllStatus = networkDllStatus, 86 | Privilege = privilege 87 | }); 88 | } 89 | else if (type == "[.NET]") 90 | { 91 | opsecNetProcesses.Add(new ProcessInfo 92 | { 93 | ProcessId = processId, 94 | ProcessName = processName, 95 | Status = status, 96 | Type = type, 97 | NetworkDllStatus = networkDllStatus, 98 | Privilege = privilege 99 | }); 100 | } 101 | } 102 | // New condition: Safe but no network DLL loaded 103 | else if (status == "[Safe]" && networkDllStatus == "[Not Loaded]") 104 | { 105 | opsecAttentionProcesses.Add(new ProcessInfo 106 | { 107 | ProcessId = processId, 108 | ProcessName = processName, 109 | Status = status, 110 | Type = type, 111 | NetworkDllStatus = networkDllStatus, 112 | Privilege = privilege 113 | }); 114 | } 115 | } 116 | catch (Exception) 117 | { 118 | // If unable to fetch process information, mark as unknown 119 | var processId = process.Id; 120 | allProcesses.Add(new ProcessInfo 121 | { 122 | ProcessId = processId, 123 | ProcessName = process.ProcessName, 124 | Status = "[Unknown]", 125 | Type = "[Unknown]", 126 | NetworkDllStatus = "[Unknown]", 127 | Privilege = "[Unknown]" 128 | }); 129 | } 130 | } 131 | 132 | // Output information about all processes 133 | Console.WriteLine("\n[All Processes]:"); 134 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 135 | "PID", "ProcessName", "Status", "Type", "NetworkDllStatus", "Privilege"); 136 | foreach (var process in allProcesses) 137 | { 138 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 139 | process.ProcessId, process.ProcessName, process.Status, process.Type, process.NetworkDllStatus, process.Privilege); 140 | } 141 | 142 | // Output PE processes that meet OPSEC criteria 143 | Console.WriteLine("\n[OPSEC] PE Processes (with network DLLs loaded):"); 144 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 145 | "PID", "ProcessName", "Status", "Type", "NetworkDllStatus", "Privilege"); 146 | foreach (var process in opsecPeProcesses) 147 | { 148 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 149 | process.ProcessId, process.ProcessName, process.Status, process.Type, process.NetworkDllStatus, process.Privilege); 150 | } 151 | 152 | // Output .NET processes that meet OPSEC criteria 153 | Console.WriteLine("\n[OPSEC] .NET Processes (with network DLLs loaded):"); 154 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 155 | "PID", "ProcessName", "Status", "Type", "NetworkDllStatus", "Privilege"); 156 | foreach (var process in opsecNetProcesses) 157 | { 158 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 159 | process.ProcessId, process.ProcessName, process.Status, process.Type, process.NetworkDllStatus, process.Privilege); 160 | } 161 | // Output Attention processes that meet OPSEC criteria (Safe but no network DLLs loaded) 162 | Console.WriteLine("\n[OPSEC & Attention] Processes (Safe but no network DLLs loaded):"); 163 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 164 | "PID", "ProcessName", "Status", "Type", "NetworkDllStatus", "Privilege"); 165 | foreach (var process in opsecAttentionProcesses) 166 | { 167 | Console.WriteLine("{0,-10} {1,-30} {2,-10} {3,-10} {4,-15} {5}", 168 | process.ProcessId, process.ProcessName, process.Status, process.Type, process.NetworkDllStatus, process.Privilege); 169 | } 170 | } 171 | 172 | // Determine the process status based on modules loaded 173 | static string GetProcessStatus(Process process, string[] dllKeywords) 174 | { 175 | try 176 | { 177 | var modules = process.Modules.Cast().Select(m => m.ModuleName).ToList(); 178 | 179 | foreach (var keyword in dllKeywords) 180 | { 181 | bool isMatching = modules.Any(m => System.Text.RegularExpressions.Regex.IsMatch(m, keyword.Replace("*", ".*"))); 182 | if (isMatching) 183 | { 184 | return "[Unsafe]"; 185 | } 186 | } 187 | 188 | return "[Safe]"; 189 | } 190 | catch (Exception) 191 | { 192 | return "[Unknown]"; 193 | } 194 | } 195 | 196 | // Determine the process type: .NET or PE 197 | static string GetProcessType(Process process) 198 | { 199 | try 200 | { 201 | var modules = process.Modules.Cast().Select(m => m.ModuleName).ToList(); 202 | 203 | if (modules.Any(m => m.Equals("mscoree.dll", StringComparison.OrdinalIgnoreCase))) 204 | { 205 | return "[.NET]"; 206 | } 207 | 208 | return "[PE]"; 209 | } 210 | catch (Exception) 211 | { 212 | return "[Unknown]"; 213 | } 214 | } 215 | 216 | // Check if the process has loaded network DLLs 217 | static string GetNetworkDllStatus(Process process, string[] networkDlls) 218 | { 219 | try 220 | { 221 | var modules = process.Modules.Cast().Select(m => m.ModuleName).ToList(); 222 | 223 | foreach (var dll in networkDlls) 224 | { 225 | if (modules.Contains(dll, StringComparer.OrdinalIgnoreCase)) 226 | { 227 | return "[Loaded]"; 228 | } 229 | } 230 | 231 | return "[Not Loaded]"; 232 | } 233 | catch (Exception) 234 | { 235 | return "[Unknown]"; 236 | } 237 | } 238 | 239 | // Check the process privilege level 240 | static string GetProcessPrivilege(Process process) 241 | { 242 | try 243 | { 244 | return IsProcessElevated(process) ? "[Elevated]" : "[Normal]"; 245 | } 246 | catch (Exception) 247 | { 248 | return "[Unknown]"; 249 | } 250 | } 251 | 252 | // Check if the process has elevated privileges (admin rights) 253 | static bool IsProcessElevated(Process process) 254 | { 255 | IntPtr tokenHandle = IntPtr.Zero; 256 | 257 | try 258 | { 259 | if (!OpenProcessToken(process.Handle, 0x0008, out tokenHandle)) 260 | { 261 | return false; 262 | } 263 | 264 | var tokenElevation = new TOKEN_ELEVATION(); 265 | int returnLength = 0; 266 | 267 | if (!GetTokenInformation(tokenHandle, TokenInformationClass.TokenElevation, out tokenElevation, Marshal.SizeOf(tokenElevation), out returnLength)) 268 | { 269 | return false; 270 | } 271 | 272 | return tokenElevation.TokenIsElevated > 0; 273 | } 274 | finally 275 | { 276 | if (tokenHandle != IntPtr.Zero) 277 | { 278 | CloseHandle(tokenHandle); 279 | } 280 | } 281 | } 282 | 283 | [DllImport("kernel32.dll", SetLastError = true)] 284 | private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); 285 | 286 | [DllImport("kernel32.dll", SetLastError = true)] 287 | private static extern bool CloseHandle(IntPtr handle); 288 | 289 | [DllImport("kernel32.dll", SetLastError = true)] 290 | private static extern bool OpenProcessToken(IntPtr hProcess, uint dwDesiredAccess, out IntPtr phToken); 291 | 292 | [DllImport("advapi32.dll", SetLastError = true)] 293 | private static extern bool GetTokenInformation(IntPtr hToken, TokenInformationClass tokenInfoClass, out TOKEN_ELEVATION tokenInformation, int tokenInformationLength, out int returnLength); 294 | 295 | // Enum for process access flags 296 | [Flags] 297 | public enum ProcessAccessFlags : uint 298 | { 299 | QueryInformation = 0x0400, // Flag to query process information 300 | } 301 | 302 | // Enum for token information classes 303 | public enum TokenInformationClass 304 | { 305 | TokenElevation = 20 // Information class for token elevation 306 | } 307 | 308 | // Struct to store token elevation information 309 | public struct TOKEN_ELEVATION 310 | { 311 | public uint TokenIsElevated; 312 | } 313 | 314 | // Class to store process information 315 | class ProcessInfo 316 | { 317 | public int ProcessId { get; set; } 318 | public string ProcessName { get; set; } 319 | public string Status { get; set; } 320 | public string Type { get; set; } 321 | public string NetworkDllStatus { get; set; } 322 | public string Privilege { get; set; } 323 | } 324 | } 325 | --------------------------------------------------------------------------------