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:
- Free an object of type A
- Reallocate memory with type B
- Use old pointer with type A semantics
- Confuse the type system
- 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¶
Project Properties¶
- Open Project Properties
- Navigate to C/C++ → Code Generation
- Set "Control Flow Guard" to "Yes (/guard:cf)"
- Add
/guard:castto Additional Options - 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