Type Casting Verification: Stopping an Emerging Attack Vector Byoungyoung Lee, Chengyu Song, Taesoo Kim, and Wenke Lee Georgia Institute of Technology 1
Vulnerability Trends Microsoft vulnerability trends (2013) Use-after-free Stack overflow Heap overflow Bad casting (or type confusion) 2
Stack Overflows Microsoft vulnerability trends (2013) # of Stack overflows is decreasing
Use-After-Free # of Use-after-free is increasing Preventing Use-after-free with Dangling Pointers Nullification [NDSS ’15] Microsoft vulnerability trends (2013)
Bad-casting Bad-casting (or type confusion) is still not solved. 5
Type Conversions in C++ • static_cast – Compile-time conversions – Fast : no extra verification in run-time – No information on actually allocated types in runtime. • dynamic_cast – Run-time conversions – Requires Runtime Type Information (RTTI) – Slow : Extra verification by parsing RTTI – Typically prohibited in performance critical applications 6
Upcasting and Downcasting • Upcasting – From a derived class to its parent class • Downcasting – From a parent class to one of its derived classes 7
Upcasting and Downcasting • Upcasting – From a derived class to its parent class • Downcasting – From a parent class to one of its derived classes Element HTMLElement SVGElement 7
Upcasting and Downcasting • Upcasting – From a derived class to its parent class • Downcasting – From a parent class to one of its derived classes Upcasting Element HTMLElement SVGElement 7
Upcasting and Downcasting • Upcasting – From a derived class to its parent class • Downcasting – From a parent class to one of its derived classes Downcasting Upcasting Element HTMLElement SVGElement 7
Upcasting and Downcasting • Upcasting – From a derived class to its parent class • Downcasting – From a parent class to one of its derived classes Downcasting Upcasting Element HTMLElement SVGElement Upcasting is always safe, but downcasting is not! 7
Downcasting is not always safe! class P { class D: public P { virtual ~P() {} virtual ~D() {} int m_P; int m_D; }; }; 8
Downcasting is not always safe! class P { class D: public P { virtual ~P() {} virtual ~D() {} int m_P; int m_D; }; }; vftptr for P int m_P Access scope of P* 8
Downcasting is not always safe! class P { class D: public P { virtual ~P() {} virtual ~D() {} int m_P; int m_D; }; }; vftptr for D vftptr for P int m_P int m_P Access scope of P* int m_D Access scope of D* 8
Downcasting can be Bad-casting P *pS = new P(); D *pD = static_cast<D*>(pS); pD->m_D; 9
Downcasting can be Bad-casting Bad-casting occurs: D is not a sub-object of P Undefined behavior P *pS = new P(); D *pD = static_cast<D*>(pS); D *pD = static_cast<D*>(pS); pD->m_D; 9
Downcasting can be Bad-casting P *pS = new P(); D *pD = static_cast<D*>(pS); pD->m_D; pD->m_D; Memory corruptions 9
Downcasting can be Bad-casting vftptr for P P *pS = new P(); int m_P D *pD = static_cast<D*>(pS); pD->m_D; pD->m_D; Memory corruptions 9
Downcasting can be Bad-casting &(pD->m_D) vftptr for P P *pS = new P(); int m_P D *pD = static_cast<D*>(pS); pD->m_D; pD->m_D; Memory corruptions 9
Downcasting can be Bad-casting &(pD->m_D) vftptr for P P *pS = new P(); int m_P D *pD = static_cast<D*>(pS); int m_D pD->m_D; pD->m_D; Memory corruptions 9
Downcasting can be Bad-casting &(pD->m_D) vftptr for P P *pS = new P(); int m_P D *pD = static_cast<D*>(pS); int m_D pD->m_D; pD->m_D; Memory corruptions 9
Real-world Exploits on Bad-casting • CVE-2013-0912 – A bad-casting vulnerability in Chrome – Used in 2013 Pwn2Own ContainerNode Element HTMLElement SVGElement HTMLUnknownElement 10
Real-world Exploits on Bad-casting • CVE-2013-0912 – A bad-casting vulnerability in Chrome – Used in 2013 Pwn2Own ContainerNode Element HTMLElement SVGElement HTMLUnknownElement 1. Allocated 10
Real-world Exploits on Bad-casting • CVE-2013-0912 – A bad-casting vulnerability in Chrome – Used in 2013 Pwn2Own ContainerNode 2. Upcasting Element HTMLElement SVGElement HTMLUnknownElement 1. Allocated 10
Real-world Exploits on Bad-casting • CVE-2013-0912 – A bad-casting vulnerability in Chrome – Used in 2013 Pwn2Own ContainerNode 2. Upcasting 3. Downcasting Element HTMLElement SVGElement HTMLUnknownElement 1. Allocated 10
Real-world Exploits on Bad-casting • CVE-2013-0912 – A bad-casting vulnerability in Chrome – Used in 2013 Pwn2Own ContainerNode 2. Upcasting 3. Downcasting Element HTMLElement SVGElement 160 bytes HTMLUnknownElement 1. Allocated 96 bytes 10
Real-world Exploits on Bad-casting ScriptWrapperble NoBaseWillBeGarbageCollectedFinalized<> EventTarget TreeShared<Node> Node ContainerNode Element HTMLElement PseudoElement VTTElement VTTElement SVGElement LabelableElement HtmlTableElement HTMLRubyElement HTMLFontElement 57 classes! HTMLMenuElement HTMLLabelElement … HTMLUnknownElement 11
Real-world Exploits on Bad-casting ScriptWrapperble NoBaseWillBeGarbageCollectedFinalized<> EventTarget TreeShared<Node> Node ContainerNode Very complex class hierarchies Element Error-prone type casting operations HTMLElement PseudoElement VTTElement VTTElement SVGElement LabelableElement HtmlTableElement HTMLRubyElement HTMLFontElement 57 classes! HTMLMenuElement HTMLLabelElement … HTMLUnknownElement 11
Existing Solutions and Challenges • Replace all static_cast into dynamic_cast • dynamic_cast on a polymorphic class (with RTTI) – A pointer points to a virtual function table pointer – Traversing a virtual function table leads to RTTI Offset to the top ptr &std::type_info A class name vftptr 1 st virtual function … … 12
Existing Solutions and Challenges • dynamic_cast on a non-polymorphic class – A pointer points to the first member variable – Simply traversing such a variable leads to a runtime crash ptr … ... 13
Existing Solutions and Challenges • dynamic_cast on a non-polymorphic class – A pointer points to the first member variable – Simply traversing such a variable leads to a runtime crash ptr … ... C++ supports no reliable methods to resolve whether a pointer points to polymorphic or non-polymorphic classes. 13
Existing Solutions and Challenges • dynamic_cast on a non-polymorphic class – A pointer points to the first member variable – Simply traversing such a variable leads to a runtime crash ptr … ... C++ supports no reliable methods to resolve whether a pointer points to polymorphic or non-polymorphic classes. Previous solutions including Undefined Behavior Sanitizer relies on blacklists. 13
CaVer: CastVerifier • CaVer : CastVerifier – A bad-casting detection tool • Design goals – Easy-to-deploy: no blacklists – Reasonable runtime performance 14
CaVer Overview Emit THTable Source code Instrumentation Compile 15
CaVer Overview Emit THTable Source code Instrumentation CaVer Runtime Compile Link 15
CaVer Overview Emit THTable Source Secured code executable Instrumentation CaVer Runtime Compile Link 15
Technical Goal of CaVer P *ptr = new P ; static_cast< D *>( ptr ); 16
Technical Goal of CaVer P *ptr = new P ; Allocated static_cast< D *>( ptr ); 16
Technical Goal of CaVer P *ptr = new P ; Allocated static_cast< D *>( ptr ); To be casted 16
Technical Goal of CaVer P *ptr = new P ; Allocated static_cast< D *>( ptr ); To be casted ptr Object (P) 16
Technical Goal of CaVer P *ptr = new P ; Allocated static_cast< D *>( ptr ); To be casted Q. What are the class relationships b/w P and D? THTable ptr Object (P) 16
Technical Goal of CaVer P *ptr = new P ; Allocated static_cast< D *>( ptr ); To be casted Q. What are the class relationships b/w P and D? THTable ptr Object (P) Q. Is ptr points to P or D? Runtime type tracing 16
Type Hierarchy Table (THTable) • A set of all legitimate classes to be converted – Class names are hashed for fast comparison – Hierarchies are unrolled to avoid recursive traversal THTable (P) THTable (D) h ash(“P”) h ash(“D”) … hash(“P”) … 17
Type Hierarchy Table (THTable) • A set of all legitimate classes to be converted – Class names are hashed for fast comparison – Hierarchies are unrolled to avoid recursive traversal THTable (P) THTable (D) h ash(“P”) h ash(“D”) … hash(“P”) … Hashed class names 17
Type Hierarchy Table (THTable) • A set of all legitimate classes to be converted – Class names are hashed for fast comparison – Hierarchies are unrolled to avoid recursive traversal Unrolled linearly THTable (P) THTable (D) h ash(“P”) h ash(“D”) … hash(“P”) … 17
Runtime Type Tracing P *ptr = new P; P *ptr = new P; trace(ptr, &THTable(P)); 18
Runtime Type Tracing P *ptr = new P; P *ptr = new P; trace(ptr, &THTable(P)); THTable (P) h ash(“P”) … ptr Object (P) 18
Recommend
More recommend