Return-oriented programming lets an exploit run attacker-chosen code without injecting any, by overwriting return addresses on the stack so that each function return lands on a chosen fragment of existing code. MITRE D3FEND names the countermeasure that catches this Shadow Stack Comparisons (D3-SSC) and defines it as "Comparing a call stack in system memory with a shadow call stack maintained by the processor to determine unauthorized shellcode activity." It is a Detect technique under Process Analysis, and its only digital artefact is the Stack Frame. This card explains what D3-SSC compares, which ATT&CK techniques D3FEND relates it to, where shadow stacks exist today in processors, operating systems and compilers, how to confirm they are active, and where they stop helping. It is written for detection engineers, endpoint security teams and platform owners who already know the basics in the Exploit Mitigations Guide.
Key takeaways
- Two copies of every return address. A shadow stack keeps a second, protected record of return addresses; a mismatch at return time means the normal stack was tampered with.
- D3FEND describes the counting variant. Its definition and sole reference (a CrowdStrike patent) count mismatches from a processor performance counter and act when a threshold is crossed, whereas modern hardware shadow stacks fault on the first mismatch.
- The ATT&CK link is exploitation. D3FEND infers relations to five exploitation techniques through the Stack Frame artefact: T1068, T1203, T1210, T1211 and T1212.
- Coverage depends on three layers at once. Hardware (Intel CET or AMD shadow stacks), an operating system that enables it, and binaries built or marked as compatible all have to line up, so many estates have far less coverage than their CPUs allow.
- It does not see jump-oriented attacks. D3FEND's own considerations say the technique may miss JOP, because no return instruction executes, and may miss single-gadget attacks such as return-to-libc if the threshold is set high.
D3-SSC at a glance
| Attribute | Value |
|---|---|
| D3FEND ID | D3-SSC (d3f:ShadowStackComparisons) |
| Tactic | Detect |
| Parent technique | Process Analysis |
| Digital artefact | Stack Frame (D3FEND relation: analyzes Stack Frame) |
| D3FEND reference | CrowdStrike Inc patent US20140075556A1, "Threat detection for return oriented programming" |
| What it observes | Disagreement between the return address on the in-memory call stack and the copy held in a processor-maintained shadow stack |
| Typical outputs | Process termination or crash on a control-protection fault; exploit protection audit events; endpoint agent alerts built on mismatch telemetry |
| Effort | Low to switch on where hardware and OS support it; medium to reach broad coverage because of application and driver compatibility |
| Main limitation | Sees only return-based control-flow hijacking; forward-edge attacks need other controls |
How it works
D3FEND's article describes the comparison like this: the call stack stored in system memory is compared with the shadow call stack held by the processor, because a return-oriented programming attack may be able to control or spoof the call stack but not the shadow stack. Mismatches are counted, and a count above a threshold indicates unauthorised activity and triggers a security response.
The patent behind the entry reads the count from a processor performance monitoring counter of call stack prediction mismatches, where the processor's shadow copy is its return stack buffer in cache. It describes thresholds learned per process or per class of process, so software that normally produces many mispredictions does not raise false alerts, and response actions that range from alerting and reporting to a remote server, through halting the processes, to collecting more data on their execution.
Hardware shadow stacks built for enforcement take the same idea further. The Linux kernel documentation for x86 CET explains that on a CALL the processor pushes the return address to both the normal stack and a shadow stack that applications cannot directly modify, and on return compares the two and raises a control-protection fault if they differ. In that design the "comparison" is done by the CPU on every return and the first mismatch stops execution, so detection and prevention collapse into one event. Both variants analyse the same artefact; they differ in whether the signal is a count or a fault.
| Variant | Shadow copy lives in | Signal | Strength | Weakness |
|---|---|---|---|---|
| Performance counter mismatch counting (D3FEND reference) | Processor return stack buffer | Count over threshold, then alert or halt | Works on processors without enforcement shadow stacks; can stay in detect-only mode | Threshold tuning; short chains may stay under it |
| Hardware shadow stack (Intel CET, AMD shadow stacks) | Protected memory pages the application cannot write | Control-protection fault on first mismatch | Deterministic, no tuning | Needs OS, runtime and binary compatibility |
| Software shadow stack (compiler instrumentation) | Separate memory region addressed through a reserved register | Mismatch avoided by loading the saved copy; no comparison event by default | Works on architectures without hardware support | Security rests on the shadow stack address staying secret |
ATT&CK techniques D3FEND relates to D3-SSC
Relationship type: inferred only. D3FEND lists no hand-made ATT&CK mapping for D3-SSC. Every row below is inferred through the shared Stack Frame artefact: these techniques modify, or may modify, a Stack Frame, and D3-SSC analyses it. D3FEND labels such relations "inferred and experimental" (D3FEND 1.6.0, checked November 2026). Each ID was checked against ATT&CK v20.
| ATT&CK ID | Technique | D3FEND relation (inferred via artefact) | What a shadow stack comparison can catch |
|---|---|---|---|
| T1203 | Exploitation for Client Execution | Same artefact: modifies Stack Frame | A browser, document reader or other client exploit that pivots through a ROP chain |
| T1068 | Exploitation for Privilege Escalation | Same artefact: may modify Stack Frame | Local exploits against user-mode services or, with kernel shadow stacks, against the kernel |
| T1210 | Exploitation of Remote Services | Same artefact: may modify Stack Frame | Memory corruption in a network-facing service exploited for lateral movement |
| T1211 | Exploitation for Stealth | Same artefact: may modify Stack Frame | Exploits used to bypass or disable security software |
| T1212 | Exploitation for Credential Access | Same artefact: may modify Stack Frame | Exploits against authentication components to obtain credentials |
Read these as "where a stack-smashing exploit would surface", not as coverage of the technique. Any of the five can be carried out with a logic flaw, a forward-edge hijack or a data-only attack that never touches a return address. Technique detail is in T1068 Exploitation for Privilege Escalation, the MITRE ATT&CK T1203 Exploitation for Client Execution guide, the MITRE ATT&CK T1210 Exploitation of Remote Services guide, the MITRE ATT&CK T1211 Exploitation for Stealth guide and the MITRE ATT&CK T1212 Exploitation for Credential Access guide.
Where it is implemented
Platforms are listed alphabetically; order is not a ranking.
| Layer | Feature | How it is switched on | Documented behaviour |
|---|---|---|---|
| Compiler (Clang/LLVM) | ShadowCallStack | -fsanitize=shadow-call-stack at compile and link; AArch64 also needs x18 reserved (-ffixed-x18) unless the target reserves it | Software shadow stack for AArch64 (described as production ready, with a runtime in Android's bionic libc), RISC-V and Hexagon; x86_64 support was removed in LLVM 9.0 |
| Compiler (GCC) | -fcf-protection | =return for return checks, =branch for indirect branches, =full (the default when no value is given) for both | Marks and instruments binaries so the hardware can enforce control-flow checks |
| Linux kernel (x86) | CET user shadow stack | Kernel built with X86_USER_SHADOW_STACK; enabled per thread by the loader or runtime (glibc is the documented example) through arch_prctl() with ARCH_SHSTK_ENABLE; disabled at boot with nousershstk | 64-bit userspace only; control-protection fault on mismatch |
| Processors | AMD shadow stacks (Zen 3 and newer); Intel CET (for example 11th Gen Intel Core Mobile and newer) | Firmware and OS support | Processor-maintained shadow stack that the OS exposes |
| Windows (user mode) | Hardware-enforced Stack Protection in exploit protection | Per application, with an "Audit only" option and "Enforce for all modules instead of Compatible modules" | Opt-in; audit events visible in Event Viewer and in Microsoft Defender for Endpoint advanced hunting |
| Windows (kernel mode) | Kernel-mode Hardware-enforced Stack Protection | Requires VBS and Memory integrity (HVCI); Group Policy "Turn on Virtualization Based Security", option set to "Enabled in enforcement mode", or the Core isolation toggle | Off by default; a mismatch causes a stop error; blocklisted incompatible drivers are prevented from loading |
Endpoint detection and response agents may also read processor performance counters or shadow stack events to raise alerts in the counting style D3FEND describes. That is a product capability to confirm in each vendor's documentation, not a platform default. Compiler-only software shadow stacks, such as ShadowCallStack, protect the return address but do not produce a comparison event, so they are prevention rather than D3-SSC detection.
Implementation steps
- Inventory the three layers. For each server and endpoint class record CPU support, operating system build and whether the main applications are shadow stack compatible. On Linux,
/proc/cpuinfoshowsuser_shstkwhen hardware and kernel support exist, andreadelf -non a binary shows the SHSTK note when it was built for it. - Start with audit on Windows endpoints. Enable Hardware-enforced Stack Protection in "Audit only" for the applications most exposed to client exploitation (browsers, document readers, mail clients) and collect the audit events centrally.
- Clear driver blockers before kernel mode. Use "Review incompatible drivers" in Windows Security on pilot devices; Microsoft Learn notes the feature fails to enable while a blocklisted driver is installed, and code obfuscation engines are a common cause.
- Pilot enforcement in rings. Move audited applications to enforcement on a pilot ring, then broaden. Microsoft Learn warns older .NET applications may crash or show high CPU usage even in audit mode, so include them in the pilot.
- Build and ship compatible binaries. For in-house Linux software, compile with
-fcf-protection=full(or at least=return) and ship on a CET-enabled kernel and C library; for Android or AArch64 code, consider ShadowCallStack. - Route the signal. Treat a shadow stack violation in an exposed process as a possible exploitation attempt: collect the crash dump, the parent process and the document or network input that preceded it.
- Roll back per application. Exploit protection settings are per program, so a breaking application can be returned to audit without turning the mitigation off for the rest of the fleet.
How to verify it works
- Linux process check: read
/proc/<pid>/status; thex86_Thread_featuresline listsshstkwhen the shadow stack is on, andx86_Thread_features_lockedshows whether the setting is locked. - Windows policy check: confirm the exploit protection configuration reached each device and, for kernel mode, that the Core isolation toggle shows enabled after restart.
- Controlled test: in a lab, run a deliberately vulnerable test program from an authorised exploit mitigation test suite and confirm the process is stopped and the event reaches the SIEM. Do this under change control, never on production hosts.
- Coverage report: compare the count of devices with capable CPUs against devices with the mitigation active.
| Metric | Example target (NHI Mgmt Group suggestion, not a standard) | Why it matters |
|---|---|---|
| Capable devices with user-mode shadow stacks enforced for high-exposure applications | Rising quarter on quarter, toward all capable devices | Hardware already bought is protection not yet used |
| Capable devices with kernel-mode stack protection on | Tracked and rising | Covers kernel privilege escalation exploits |
| Shadow stack violations investigated within one working day | 100% | A violation in an exposed process may be an exploit attempt |
| Applications held in audit because of incompatibility | Falling, each with an owner and a fix date | Prevents permanent exceptions |
Limits, bypasses and failure patterns
- Forward-edge attacks: jump-oriented and call-oriented programming hijack indirect jumps and calls, not returns. D3FEND notes JOP may go undetected. Pair D3-SSC with indirect branch tracking or Control Flow Guard, and with the D3-PAN Pointer Authentication and D3-PV Pointer Validation techniques where the platform supports them.
- Thresholds that hide short chains: in the counting variant, D3FEND warns that a threshold set too high may miss a one-gadget attack such as return-to-libc or return-to-plt.
- Data-only attacks: an exploit that changes a flag or a pointer used later, without overwriting a return address, never causes a mismatch.
- Compatibility exceptions that become permanent: an application left in audit mode, or a single incompatible driver that blocks kernel-mode protection, quietly removes coverage from a whole device class.
- Software shadow stack disclosure: the Clang documentation warns that the shadow stack address can leak through side channels,
setjmp/longjmpbuffers or code that does not reserve the register, after which the attacker can rewrite both copies. - Assuming capable hardware means coverage: on Linux the kernel does not enable shadow stacks from ELF markers itself, and features are disabled again on exec until the loader turns them on; a capable CPU running unmarked binaries has no shadow stack.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev 5 | SI-16 Memory Protection | Controls that protect memory from unauthorised code execution |
| NIST SP 800-53 Rev 5 | SI-4 System Monitoring | Turning violations into monitored events |
| NIST CSF 2.0 | DE.CM-09 | Monitoring computing hardware, software and runtime environments for adverse events |
| CIS Controls v8.1 | Safeguard 10.5 Enable Anti-Exploitation Features | Turning on platform exploit mitigations |
| MITRE ATT&CK mitigations | M1050 Exploit Protection | The mitigation family this detection sits beside |
| MITRE D3FEND | Process Analysis, D3-SSC | Parent and technique |
The prevention side of the same capability is covered in M1050 Exploit Protection. The D3FEND parent, Process Analysis, groups the process behaviour detections; a sibling at the same layer is D3-PSA Process Spawn Analysis, which catches what an exploited process does next.
Related countermeasures
- Stack Frame Canary Validation: a compiler-placed canary that detects linear stack overwrites before return. See D3-SFCV Stack Frame Canary Validation.
- Pointer Authentication and Pointer Validation: protect code pointers and indirect branch targets that shadow stacks do not cover.
- System Call Analysis: catches the system calls a successful ROP chain eventually makes. See D3-SCA System Call Analysis.
- Process Spawn Analysis: spots the child process an exploited application starts.
Practitioner checklist
- Record CPU shadow stack capability per device class and compare it with what is enabled.
- Enable Hardware-enforced Stack Protection in audit for browsers, document readers and mail clients first.
- Collect exploit protection audit events centrally and review them before enforcement.
- Resolve incompatible drivers, then enable kernel-mode stack protection with VBS and Memory integrity.
- Build in-house Linux software with
-fcf-protectionand run it on a CET-enabled kernel and C library. - Check
/proc/<pid>/statuson key Linux services to confirmshstkis active. - Treat shadow stack violations in exposed processes as possible exploitation and preserve the crash dump.
- Pair D3-SSC with forward-edge controls, because it does not see jump or call oriented attacks.
- Give every compatibility exception an owner and an end date.
Standards and references
- MITRE D3FEND: Shadow Stack Comparisons (D3-SSC)
- Google Patents: US20140075556A1 Threat detection for return oriented programming
- Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack
- Microsoft Learn: Kernel-mode Hardware-enforced Stack Protection
- Microsoft Learn: Exploit protection reference
- LLVM: Clang ShadowCallStack
- GCC: Program Instrumentation Options (-fcf-protection)
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Exploit Mitigations Guide · M1050 Exploit Protection · D3-SFCV Stack Frame Canary Validation · MITRE D3FEND Guide