C++ programmers convert between types as often as they go out for beers. The C++ compiler has few built in protections for catching insecure type casting. Because of this, C++ type confusion commonly leads RCE, especially with C++ virtual function tables being some prevalent. The bug class type confusion is the focus of this con talk.
In C++, there are multiple ways of casting but we will focus on two: static_cast and dynamic_cast.
With static casts, a check is done at compile time to convert a pointer of one type to another. Static casts ONLY checks for a feasibility check for the type in the class hierarchies. Dynamic casts have a runtime check (RTTI) in order to distinguish between objects. But, is NOT used in performance critical code and is ONLY limited to polymorphic classes.
When do these types of issues occur?
- Illegal downcasts. For instance, going from child2->parent->child1. The child1 conversion from parent can technically legal from the hierarchical perspective. But, this may not be a valid conversion in terms of memory safety.
- Static Casts allow for conversions from child2->child1 directly! Even though these are different classes, because they have the same parent the type conversion is allowed.
- Dynamic Casts (that are not polymorphic (virtual)) have these issues because no check is done at compile time or runtime for these.
- C-style casting has small checks in place at compile time to validate if the cast is valid or not. But, this is limited.
- Polymorphic child to a non-polymorphic base. This is because the VTable is stored at the beginning of the child, while the base class will NOT have this.
The presentation then proposes a solution to this type casting problem. For all casts (during the compilation process), a type hierarchy is made in order to validate EACH cast that happens. At runtime, instrumentation is added in order to use the hierarchy to validate the conversions. This was done by an LLVM pass that validates within the Clang compiled binary.
To make this more efficient, only the types being casted in the program were added to the type hierarchy. Additionally, the code that verified bugs are compile time was NOT added with instrumentation for runtime. Although, this COULD lead to further memory corruption (down the road) to take a small bug and turn it into a bigger one via this type confusion.
Simply from compiling software and running it found 4 type confusion bugs. By fuzzing with AFL, they found 13 other bugs with the HexType instrumentation. This works well when instrumented with AFL; this is super awesome to hear for C++ projects to find type confusion bugs.
The type confusion checking CAN lead to a significant amount of false positives because of some quirks of C++. Although some things may be a type confusion, they may not be exploitable.
They have this code public in a Github repo at
HexType.
Fun fact from the questions... I'm fairly sure that the women that speaks about Safari is
Natalie Silvanovich from Project Zero, whose
finding the speaker referenced in their slides. Just something that is super odd that I'm not sure the speaker realized (lolz).