Skip to content

AD2030: EnableCastGuard

Summary

Property Value
ID AD2030
Name EnableCastGuard
Category Security
Severity Warning
Applies to PE (Windows) - C++ binaries

Description

CastGuard (/guard:cast) is a compiler mitigation that validates type casts at runtime to prevent type confusion vulnerabilities in C++ code. When enabled, the compiler inserts runtime checks for static_cast and dynamic_cast operations involving polymorphic types.

How It Works

The rule examines the PE binary's load configuration directory for the EH continuation table flag, which indicates CastGuard is enabled. It also verifies via PDB that the binary is a C++ binary compiled with a supporting version of MSVC.

Requirements

  • Visual Studio 2019 version 16.10 or later (MSVC 19.29+)
  • /guard:cf (Control Flow Guard) must also be enabled
  • /GL (Whole Program Optimization) is recommended
  • Only applicable to C++ code with polymorphic types

Why This Matters

Type confusion vulnerabilities have emerged as one of the most powerful attack primitives in modern exploitation. CastGuard adds runtime validation to C++ type casts, catching attacks that bypass traditional memory corruption defenses.

The Type Confusion Attack

Type confusion exploits C++'s type system:

class Base { virtual void f(); };
class DerivedA : public Base { int a; void g(); };
class DerivedB : public Base { void* dangerous_ptr; };

// Attacker corrupts vtable pointer to make DerivedA look like DerivedB
Base* obj = new DerivedA();
// ... memory corruption ...
DerivedB* confused = static_cast<DerivedB*>(obj);  // Type confusion!
confused->dangerous_ptr = attacker_controlled;      // Arbitrary write!

Why Type Confusion Is Powerful

Attack Primitive Type Confusion Enables
Arbitrary read Access different type's fields
Arbitrary write Overwrite different type's fields
Code execution Redirect virtual calls
Info leak Read sensitive data

Real-World Exploitation

Type confusion has enabled major attacks:

Target Technique Result
Browsers DOM object confusion RCE
Office Shape object confusion RCE
Kernels Object type confusion Privilege escalation
PDF readers Annotation confusion RCE

How CastGuard Works

Without CastGuard:
  static_cast<Derived*>(base)  →  Direct pointer adjustment

With CastGuard:
  static_cast<Derived*>(base)  →  Validate RTTI/vtable
                               →  Check inheritance chain
                               →  Fault if invalid
                               →  Then adjust pointer

The compiler inserts checks using CFG's exception handler continuation metadata.

Performance Considerations

CastGuard overhead varies significantly based on code patterns:

Code Pattern Overhead Notes
Few polymorphic casts <1% Minimal impact
Moderate casts 1-3% Acceptable for most apps
Cast-heavy code 3-8% Consider profiling
Hot loop with casts 5-15% May need optimization

Factors affecting overhead: - Number of static_cast and dynamic_cast operations - Frequency of virtual function calls - RTTI complexity (deep inheritance hierarchies)

Optimization strategies: - Profile to identify hot cast sites - Consider caching cast results for repeated checks - Restructure hot loops to minimize casts

Comparison with dynamic_cast:

Operation Without CastGuard With CastGuard
static_cast ~0 cycles RTTI validation
dynamic_cast RTTI check Enhanced RTTI check

For security-critical applications handling untrusted data, CastGuard's overhead is generally acceptable.

Interaction with CFG

CastGuard builds on Control Flow Guard infrastructure:

CFG:       Validates indirect call targets
CastGuard: Validates type cast validity

Combined: Both forward-edge and type-based protection

Use-After-Free + Type Confusion

These attacks often combine:

  1. Free an object of type A
  2. Reallocate memory with type B
  3. Use old pointer with type A semantics
  4. Confuse the type system
  5. Exploit the mismatch

CastGuard detects step 3-4 when casts are involved.

Type confusion vulnerabilities occur when an attacker corrupts an object's vtable pointer or type metadata, causing the application to treat memory as the wrong type. This can lead to:

  • Use-after-free exploitation: Reusing freed memory as a different type
  • Vtable hijacking: Redirecting virtual function calls
  • Type confusion attacks: Treating objects as incompatible types

CastGuard helps detect these attacks at runtime by validating that cast operations are valid.

Resolution

Compiler Command Line

cl.exe /guard:cf /guard:cast /GL ...

Project Properties

  1. Open Project Properties
  2. Navigate to C/C++ → Code Generation
  3. Set "Control Flow Guard" to "Yes (/guard:cf)"
  4. Add /guard:cast to Additional Options
  5. Enable "Whole Program Optimization" (/GL)

CMake

if(MSVC AND MSVC_VERSION GREATER_EQUAL 1929)
    add_compile_options(/guard:cf /guard:cast /GL)
    add_link_options(/guard:cf)
endif()

When to Suppress

This rule can be suppressed in the following scenarios:

  • Pure C code: CastGuard is only for C++ with polymorphic types
  • Non-polymorphic code: Code without virtual functions won't benefit
  • Older compiler required: When targeting older MSVC versions
  • Performance-critical code: CastGuard adds runtime overhead

Caveats

  • Requires Visual Studio 2019 16.10 or later
  • Adds runtime overhead for type cast validation
  • Must be used with Control Flow Guard (/guard:cf)
  • Only protects polymorphic C++ types

References