www.azimuthsecurity.com

Download Report

Transcript www.azimuthsecurity.com

Attacking Interoperability
July 2009
INTRODUCTION
2
 Thesis
- The added complexity of expanded interoperability creates subtle, new, and
interesting opportunities for attackers
• Large, nuanced attack surface
• Speech targets browser components, but ideas applicable elsewhere
 Overview
- Part I – The attack surface
- Part II – Vulnerability classes and results
 We will uncover subtle vulnerability classes present in all major
web browsers!
3
ATTACK SURFACE
4
Interoperability:
 A Large Attack Surface
- Scriptable plugins
- Communications and
marshalling
- Language and DOM
runtimes
 Unique bug classes
- Object Retention
- Type confusion
- Transitive Trust
5
Map of the Modern Web Browser
6
 Scriptable Plugins can be targeted via well-known entry points
- Experienced a lot of scrutiny (ActiveX fuzzers etc, eg: )
- Well-known bug classes exploited often – useful, but boring
- Type manipulation and lifespan of parameters – interesting
 Communications layers are a large attack surface
- Charged with converting data from one representation to another
- Dealing with complex objects
- Marshalling / Serialization
 DOM and Language runtimes
- Lots of native code to target
- Have to deal with same type manipulation / lifespan issues as plugins
7
 Two major competing technologies
- Microsoft ActiveX
- Mozilla NPAPI (Firefox, Safari, Chrome, Opera, the list goes on)
 ActiveX
- Plugin registration
- COM Stuff
• Automation objects
• Persistent Streams
- Data manipulation (VARIANTs and related APIs)
 NPAPI
- Plugin Registration
- NPAPI / NPRuntime
- Data manipulation (NPObject / NPClass usage)
8
ACTIVEX
9
 Everyone knows what ActiveX controls are
- Registered in HKCR\CLSID\{<CLSID>}
 Safe for Initialization (SFI) vs Safe For Scripting (SFS)
- SFI: Instantiation from persistent COM stream
- SFS: Control can be scripted
 Dangerous controls can also be killbitted
- HKLM\Software\Microsoft\Internet Explorer\ActiveX Compatibility (0x400)
- IE8: Per-user killbitting possible:
HKCU\Software\Microsoft\Windows\CurrentVersion\Ext\Settings\{CLSID}
(Flags value = 1)
 Pre-approved list of controls added to IE7+
- HKLM\Software\Microsoft\Windows\CurrentVersion\Ext\PreApproved
- No prompting for these controls
- IE8: controls can be pre-approved per-user and per-domain
- HKCU\Software\Microsoft\Windows\CurrentVersion\Ext\Stats\{CLSID}\iexplor
e\AllowedDomains
10
 IE8 GUI shows available controls
- Takes all the registry work out
11
 ActiveX controls and scriptable objects are IDispatch /
IDispatchEx COM objects
-
Self-publishing
Methods / properties called via Invoke() function using DispID
Parameters passed in DISPPARAMS structure
Essentially array of VARIANTARGS
typedef struct FARSTRUCT tagDISPPARAMS {
VARIANTARG FAR* rgvarg;
DISPID FAR* rgdispidNamedArgs;
unsigned int cArgs;
unsigned int cNamedArgs;
} DISPPARAMS;
12
//
//
//
//
Array of arguments.
Dispatch IDs of named arguments.
Number of arguments.
Number of named arguments.
 VARIANT data structure used to represent data types
- Data structure with type variable (vt) and value variable (union)
- Types consist of basic type (0 -> 0xFFF) + possible modifiers (0x1000+)
- VT_BYREF modifier not mutually exclusive with other modifiers
13
Type Name
VT_EMPTY
VT_NULL
VT_I4
VT_BSTR
VT_DISPATCH
Value
0x0000
0x0001
0x0003
0x0008
0x0009
Union Contains
Undefined
NULL value
Signed (4-byte) integer
String; Pointer to a BSTR
Pointer to an IDispatch interface
(automation object)
VT_BOOL
VT_VARIANT
VT_UNKNOWN
0x000B
0x000C
0x000D
Boolean (2-byte short)
Pointer to another VARIANT
Pointer to an IUnknown interface (any
COM object)
Modifier Name
VT_VECTOR
Modifier Value
0x1000
VT_ARRAY
0x2000
VT_BYREF
0x4000
Value
Value points to a simple counted
array (Rarely used)
Value points to a SAFEARRAY
structure
Value points to base type, instead
of containing a literal of the base
type
COM serialization
- Accessed via COM
interfaces
•IStream and IStorage
- Represents a file /
memory stream / etc
- Support persistence by
implementing one of the
IPersist interfaces
14
 COM persist streams contain binary data representing object
properties
-
Interpretation depends on the IPersist*::Load() method
Most use default ATL IPersistStream::Load() template method
Programmer just needs to define a property map of the object
Property maps are structures, simplified definition using macros
(BEGIN_PROPERTY_MAP(), BEGIN_PROP_MAP(), PROP_ENTRY(),
PROP_ENTRY_EX(), PROP_DATA_ENTRY(), etc..)
struct ATL_PROPMAP_ENTRY
{
LPCOLESTR szDesc;
DISPID dispid;
const CLSID* pclsidPropPage;
const IID* piidDispatch;
DWORD dwOffsetData;
DWORD dwSizeData;
VARTYPE vt;
};
15
class HelloCom :
public IPersistStreamInitImpl<HelloCom>,
public IPersistStorageImpl<HelloCom>,
public IPersistPropertyBagImpl<HelloCom>,
{
public:
BEGIN_PROP_MAP(HelloCom)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
PROP_ENTRY("NameFirst", 1, CLSID_HelloComCtrl)
PROP_ENTRY_TYPE("NameLast", 2, CLSID_HelloComCtrl, VT_BSTR)
END_PROP_MAP()
};
Offset
0x00
0x04
0x08
0x0C
0x0E
0x12
0x1E
0x22
16
Hexadecimal representation of bytes
00 09 00 00
00 01 00 00
00 01 00 00
08 00
0C 00 00 00
46 00 69 00 72 00 73 00 74 00 00 00
0A 00 00 00
4C 00 61 00 73 00 74 00 00 00
Description
Version nine of the ATL
The _cx value is 256
The _cy value is 256
NameFirst is stored as a VT_BSTR
NameFirst is 12 characters long
NameFirst is equivalent to "First"
NameLast is 10 bytes long
NameLast is equivalent to "Last"
 COM persistent streams embeddable in IE
- Property Bags (Textual strings using <PARAM> tags)
- Binary files retrieved from “data” parameter of <OBJECT> tag
• .ICA, .STM, .ODS extensions -> IPersistStream
• Otherwise, query for all COM IPersist* interfaces
<OBJECT
id="VIDEO"
CLASSID="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
data="./persistence_data"
type="application/x-oleobject"
/>
17
 Most COM components use the ATL (Better than Madoff)
18
NPAPI / NPRUNTIME
19
 Plugins registered in one of two ways
- Copied into the plugins directory of the browser (eg. C:\Program Files\Mozilla
Firefox\plugins)
- Registry key added (for Firefox: HKLM\Software\MozillaPlugins)
 Registered plugins are associated with content types
- Content handled by a plugin is defined as 1 or more MIME types
- Can also be associated with 1 or more file extensions
- Information for both is in the “Version” information of the DLL
20
 URL “about:config” shows all the relevant information
21
 NPAPI is divided into two parts
- Browser-side functions
- Plugin-Side functions
 Browser-side functions provide browser services to the plugin
- Accessed via NPNetscapeFuncs structure passed to plugin
- By convention, functions are prefixed with NPN_*
• Example: NPN_Evaluate(), NPN_GetURL(), etc
 Plugin-side functions provide plugin implementation to the
browser
- Accessed via NPPluginFuncs structure returned by plugin
- By convention, functions are prefixed with NPP_*
• Example: NPP_New(), NPP_Destroy(), etc
22
 Scriptable objects exposed to the browser via NPP_GetValue()
- Called with NPPVpluginScriptableNPObject
 Scriptable objects are instances of NPObjects
- Contains reference count + NPClass to define behaviour
struct NPClass
{
uint32_t structVersion;
NPAllocateFunctionPtr allocate;
NPDeallocateFunctionPtr deallocate;
NPInvalidateFunctionPtr invalidate;
NPHasMethodFunctionPtr hasMethod;
NPInvokeFunctionPtr invoke;
NPInvokeDefaultFunctionPtr invokeDefault;
NPHasPropertyFunctionPtr hasProperty;
NPGetPropertyFunctionPtr getProperty;
NPSetPropertyFunctionPtr setProperty;
NPRemovePropertyFunctionPtr removeProperty;
NPEnumerationFunctionPtr enumerate;
NPConstructFunctionPtr construct;
};
23
 NPObjects support getting/setting properties
- HasProperty(), GetProperty(), SetProperty() exposed by NPClass
 Also supports method invocation
- HasMethod(), Invoke()
- InvokeDefault() used when object is invoked like a property
24
 Variables passed to/from JS as NPVariants
- Simple type/value structure
- Value is a union, much like Microsoft VARIANT structures
• No composite types
typedef struct _NPVariant {
NPVariantType type;
union {
bool boolValue;
int32_t intValue;
double doubleValue;
NPString stringValue;
NPObject *objectValue;
} value;
} NPVariant;
- Manipulated with simple macros provided by npruntime.h
• NPVARIANT_TO_XXX(), XXX_TO_NPVARIANT(), NPVARIANT_IS_XXX()
25
 Javascript objects are wrapped as NPObjects by the marshalling
layer, and vice versa
- Not particularly important, but we drew this cool diagram
26
VULNERABILITY CLASSES &
RESULTS
27
 Interoperability layers affected by standard bug classes
- Buffer overflows (Boring)
- Memory Corruption (Boring)
 Additional complexities
- Language agnostic variable representation
- Lifespan of data
- Security models
 Unique challenges result in unique vulnerabilities
- Object retention vulnerabilities
- Type confusion vulnerabilities
- Transitive trust vulnerabilities
28
OBJECT RETENTION
29
 Data structures shared between multiple components
- Individual components unaware of other components utilizing an object
- Need to ensure memory is released, but not too early
 Strategy: reference counting
- Objects contain a reference count variable
- Consumers increment reference count to ensure object is retained in
memory
- Reference count decremented when the consumer no longer needs the
object
 Mis-management of reference counting is bad news!
30
 Types of life span mismanagement
- Releasing: Not maintaining a reference when it is still required
- Not releasing: Maintaining a reference when it is no longer required
 Consequences depend on nature of mis-management discovered
- Memory is deallocated too early
• Uses heap data as vtable pointers
• Double frees
• Misc. Memory Corruption
- Memory is maintained indefinitely
• Memory leaks (Heap littering)
• Potentially results in memory being deallocated too early
 Object retention APIs differ between ActiveX and NPAPI
31
 Internally, the reference count is stored as a 32-bit integer
- 0xFFFFFFFF + 2 references = 1 Reference
- 1 Reference, once Release()’d will cause stale pointers
 Effectively resulting in the same effect as releasing a reference
when one is required
 Slightly more difficult to exploit
- Takes time, done incorrectly can freeze the browser
 Takeaway:
- Any miscounting can be beneficial to an attacker
32
 COM Objects manage object retention with the IUnknown interface
- IUnknown::AddRef()
- IUnknown::Release()
 Receiving a COM object as a parameter
- Must call AddRef() if you intend to retain the object
- Must call Release() when you are finished with it
33
 Example I
- No reference to object retained!
HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
{
m_pCallback = pCallback;
return S_OK;
}
HRESULT CMyObject::get_MyProperty(IDispatch **out)
{
if(out == NULL || *out == NULL || m_pCallback == NULL)
return E_INVALIDARG;
*out = m_pCallback;
return S_OK;
}
34
 Example II
- Release() is never called when object is assigned
HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
{
if(pCallback == NULL)
return E_INVALIDARG;
pCallback->AddRef();
m_pCallback = pCallback;
return S_OK;
}
HRESULT CMyObject::get_MyProperty(IDispatch **out)
{
if(out == NULL || *out == NULL || m_pCallback == NULL)
return E_INVALIDARG;
*out = m_pCallback;
return S_OK;
}
35
 Example III
- Object released, but not referenced when returned by the get_ function!
HRESULT CMyObject::put_MyProperty(IDispatch *pCallback)
{
if(pCallback == NULL)
return E_INVALIDARG;
if(m_pCallback != NULL)
m_pCallback->Release();
pCallback->AddRef();
m_pCallback = pCallback;
return S_OK;
}
HRESULT CMyObject::get_MyProperty(IDispatch **out)
{
if(out == NULL || *out == NULL || m_pCallback == NULL)
return E_INVALIDARG;
*out = m_pCallback;
return S_OK;
}
36
 VARIANTs also need to be handled with care
- VARIANTs containing pointers need to be handled carefully
- Copying pointers leads to multiple pointers pointing to the same location
- What if it gets freed?
 Shallow copying versus Deep Copying
-
Pointer values shouldn’t be copied – the target object should be duplicated
COM interfaces: AddRef() called on object
Strings / Arrays / etc: clone the memory object
VariantCopy() and VariantCopyInd() handle duplication correctly
 Shallow copying – how does it happen?
- Using memcpy() instead of a VARIANT API function
37
 Example IV
- memcpy() considered dangerous (use memcpy_s()?)
HRESULT CMyObject::put_MyProperty(VARIANT src)
{
HRESULT hr;
memcpy((void *)&m_MyProperty, (void *)&src, sizeof(VARIANT));
return S_OK;
}
HRESULT CMyObject::get_MyProperty(VARIANT *out)
{
HRESULT hr;
if(out == NULL)
return E_FAIL;
VariantInit(out);
memcpy(out, (void *)&m_MyProperty, sizeof(VARIANT));
return S_OK;
}
38
 I used VariantCopy() instead of memcpy() – safe?
- Short answer: possibly
 VariantCopy() vs VariantCopyInd()
- VariantCopy() does not follow VT_BYREF indirection
- VariantCopyInd() does (VT_BYREF|VT_VARIANT recursion not allowed)
 VariantCopy() is potentially unsafe when VT_BYREF is set!
- If VT_BYREF is set, VariantCopy() == memcpy() (shallow)
- Exploitable? Depends on what happens to the VARIANT afterwards…
 Additional note: VariantCopyInd() is never used when a
SAFEARRAY is duplicated with SafeArrayCopy()!
39
 Example V
- VariantCopy() is used – what if we have a VT_BYREF?
HRESULT CMyObject::put_MyProperty(VARIANT src)
{
HRESULT hr;
VariantInit(&m_MyProperty);
hr = VariantCopy(&m_MyProperty, &src);
if(FAILED(hr))
return hr;
return S_OK;
}
HRESULT CMyObject::get_MyProperty(VARIANT *out)
{
HRESULT hr;
if(out == NULL)
return E_FAIL;
VariantInit(out);
hr = VariantCopy(out, &m_MyProperty);
if(FAILED(hr))
return hr;
return S_OK;
}
40
 Similar story for NPObjects
- NPN_RetainObject() increments reference count
- NPN_ReleaseObject() decrements count (and possibly frees object)
 Retaining objects without NPN_RetainObject() is bad
- Object will possibly be freed
 Obviously memcpy()’ing NPVariants is also potentially dangerous
- Can be equated to memcpy() of a VARIANT
- In practice this is rare…
 Handing out objects in GetProperty() also requires retaining the
object!
41
 Example VI
- Object retained without adding a reference, potential stale pointer issues
bool SetProperty(NPObject *obj, NPIdentifier name, const NPVariant
*variant)
{
if(name == kTestIdent)
{
if(!NPVARIANT_IS_OBJECT(*variant))
return false;
gTestObject = NPVARIANT_TO_OBJECT(*variant);
return true;
}
return false;
}
42
 Failure to release objects has similar problems as in ActiveX
- Memory leaks
- Possible stale pointer issues due to integer overflow
 Objects must be released with NPN_ReleaseObject()
43
 Example VII
- Object retained without adding a reference, potential stale pointer issues
bool SetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant)
{
if(name == kTestIdent)
{
if(!NPVARIANT_IS_OBJECT(*variant))
return false;
gTestObject = NPN_RetainObject(NPVARIANT_TO_OBJECT(*variant));
return true;
}
return false;
}
44
TYPE CONFUSION
45
 Interoperability requires language agnostic data representation
- Contrived types
- COM: VARIANT/VARIANTARG
- NPRuntime: NPVariant
 Contrived types require careful programming
- Big opportunity!
 Vulnerabilities occur when one data type is mistaken for another.
- Type Wildcards
- Unions
46
 Type Wildcards
- Allow a wide range of types to be used for a variable
- In C, they negate casting requirements
- void *
 If the compiler doesn’t emit a warning, a programmer might not
care
- Requires more diligence to use properly
 Solution: ban void *
- Not really.
47
 Normally the compiler protects against incorrect types
- unsigned long *pulValue; char *szSource; strcpy(pulValue, szSource);
- error C2664: 'strcpy' : cannot convert parameter 1 from 'unsigned long *' to
'char *‘
- warning: passing argument 1 of 'strcpy' from incompatible pointer type
 Sometimes it doesn’t
- unsigned long pulValue[4]; char szSource[16]; memcpy(pulValue, szSource,
sizeof(szSource));
- 0 error(s), 0 warning(s)
- gcc –Wall –o sample sample.c: no output
 Areas where types aren’t resolved can be exposed to attack
- Memory corruption
- Information leaks
- Etc.
48
 Example I
- The infamous ATL (vidctl) bug
SAFEARRAYBOUND rgsaInBounds;
SAFEARRAYBOUND rgsaBounds;
SAFEARRAY *saBytes;
void *pvData;
hr=pStream->Read(&saInBounds, sizeof(saInBounds), NULL);
if(hr<0||hr==1)
return(hr);
rgsaBounds.cElements = rgsaInBounds.cElements;
rgsaBounds.lLbound = 0;
saBytes = SafeArrayCreate(VT_UI1, 1, rgsaBounds);
if(saBytes == NULL)
return(E_OUTOFMEMORY);
hr = SafeArrayAccessData(saBytes, &pvData);
if(hr < ERROR_SUCCESS)
return(hr);
hr=pStream->Read(&pvData, rgsaInBounds.cElements, NULL);
...
49
 Unions
- Same memory space – different types
- Useful for conserving memory and abstracting data
- No errors or warnings at compile time when accessing incorrect type
 Programmer must keep track of the appropriate member
- High-level identifiers keep track
- Easy to get wrong (APIs somewhat unintuitive at times)
 We will consider the two technologies separately
- ActiveX
- NPAPI
50
 VARIANT Type Confusion I - Permissive property maps
- Property maps tell the ATL what types to serialize / resurrect
- During resurrection, the array is traversed
 Some property map entry macros require a specific variant type
- PROP_ENTRY_TYPE()
- PROP_ENTRY_TYPE_EX()
- PROP_DATA_ENTRY()
 Others are more permissive
- PROP_ENTRY()
- PROP_ENTRY_EX()
- Any of the less permissive ones if passed VT_EMPTY as the type
51
 PROP_DATA_ENTRY() vs PROP_ENTRY_*()
- Ability to write memory allocated for a property directly into the class
- If passed-in type is VT_EMPTY, no type checking will be performed
- Will bypass any sanitization that occurs in IDispatch
52
 VARIANT Type Confusion II – Misinterpreting types
- vt contains basic type + modifiers
 Type interpretation is susceptible to subtle errors
- Masking off all the modifiers
• Just operating on the basic type
- Action based on a specific modifier
• Eg. VT_ARRAY is set, doesn’t mean the type is a SAFEARRAY!
- Masking off specific modifiers
• Losing information is bad
53
 Example II – Multiple Modifiers (Synthetic)
- Checks if VARIANT is an array of integers: VT_ARRAY + (VT_I4 or VT_UI4)
- VT_BYREF can be used in conjunction with VT_ARRAY!
- Type confusion when dealing with (VT_BYREF|VT_ARRAY|VT_I4)
- Treats a SAFEARRAY ** as a SAFEARRAY *
SAFEARRAY *psa;
ULONG *pValue
// Test if object is an array of integers
VARTYPE baseType = pVarSrc->vt & VT_TYPEMASK;
if((baseType != VT_I4 && baseType != VT_UI4)
|| ((pVarSrc->vt & VT_ARRAY) == 0) )
return -1;
psa = pVarSrc->parray;
// operate on SAFEARRAY
SafeArrayAccessData(psa, &pValues);
...
54
 Example III – IEs core DOM marshalling
- VT_ARRAY modifier is masked off!
int VARIANTARGToCVar(VARIANT *pSrcVar, int *res, VARTYPE vt, PVOID outVar, IServiceProvider
*pProvider, BOOL bAllocString)
{
VARIANT var;
VariantInit(&var);
if(!(vt & VT_BYREF))
{
// Type mismatch - attempt conversion
if( (pSrcVar->vt & (VT_BYREF|VT_TYPEMASK)) != vt && vt != VT_VARIANT)
{
... Try type conversion, die on failure ...
}
switch(vt)
{
case VT_DISPATCH:
*(PDISPATCH)outVar = pSrcVar->pdispVal;
break;
... Other types dealt with here ...
}
55
 VARIANT Type Confusion III – Direct type manipulation
- Setting the vt directly
- Calling an API function, failure to check if it succeeds
- Mainly a result of VariantChangeType()/VariantChangeTypeEx() failing
 Setting the type manually can have significant consequences
- Type confusion if error isn’t detected
- Possible type confusion even if error IS detected
• VariantClear() will misinterpret erroneous type
56
 Example IV – Direct Type Manipulation (Synthetic)
inline HRESULT CComVariant::ReadFromStream(IStream* pStream)
{
HRESULT hr;
hr = VariantClear(this);
if (FAILED(hr))
return hr;
VARTYPE vtRead;
hr = pStream->Read(&vtRead, sizeof(VARTYPE), NULL);
if (hr == S_FALSE)
hr = E_FAIL;
if (FAILED(hr))
return hr;
vt = vtRead;
//Attempts to read fixed width data types here
CComBSTR bstrRead;
hr = bstrRead.ReadFromStream(pStream);
if (FAILED(hr))
return hr;
vt = VT_BSTR;
bstrVal = bstrRead.Detach();
if (vtRead != VT_BSTR)
{
hr = ChangeType(vtRead);
vt = vtRead;
}
return hr;
}
57
 VARIANT Type Confusion IV - Initialization Errors
- Operating on VARIANTs that are partially or totally uninitialized
- VARIANT API lends itself to these types of problems
 VariantClear() on uninitialized VARIANTs considered dangerous!
- Need to call VariantInit() first (or otherwise set vt to VT_EMPTY)
- Easy to forget to initialize them!
 VARIANT API functions often VariantClear() their dst parameters
- VariantCopy()
- VariantCopyInd()
- VariantChangeType()
- VariantChangeTypeEx()
58
 Example V – Uninitialized VARIANTs (Synthetic)
- var never initialized with VariantInit()
- If read fails, VariantClear() called
HRESULT MyFunc(IStream* pStream)
{
VARIANT var;
IDispatch* pDisp;
HRESULT hr;
var.vt = VT_DISPATCH;
hr = pStream->Read(pDisp, sizeof(IDispatch *), NULL);
if(FAILED(hr)) {
VariantClear(&var);
return hr;
}
. . .
return hr;
}
59
 Example VI – VariantCopy Example (Synthetic)
- VariantCopy() calls VariantClear() on dstVar
- dstVar is uninitialized
HRESULT MyFunc(IStream* pStream)
{
VARIANT srcVar;
VARIANT dstVar;
IDispatch* pDisp;
HRESULT hr;
srcVar.vt = VT_DISPATCH;
dstVar.vt = VT_DISPATCH;
hr = pStream->Read(pDisp, sizeof(IDispatch *), NULL);
if(FAILED(hr)) {
//VariantClear(&var);
return hr;
}
else {
srcVar.pdispVal = pDisp;
hr = VariantCopy(&dstVar, &srcVar);
}
return hr;
}
60
 NPRuntime uses NPVariant data structures
- Also a language agnostic value representation scheme
- Also potentially vulnerable to type confusion attacks
 Like COM VARIANTs, but:
- No type modifiers
- No Arrays / Pointers
- No dynamic conversion APIs
- Simpler
 NPAPI does NOT do type coersion!
- NPVARIANT_TO_XXX() just accesses a union member
- Programmers must validate each parameter with NPVARIANT_IS_XXX()
61
 Exmaple I – Type Verification Omission (Google Native Client)
- No check if ‘variant’ is really an integer value
- Type confusion attack possible
bool Plugin::SetProperty(NPObject* obj,
NPIdentifier name,
const NPVariant* variant) {
Plugin* plugin = reinterpret_cast<Plugin*>(obj);
if (kHeightIdent == name) {
plugin->height_ = NPVARIANT_TO_INT32(*variant);
return true;
…
62
 Example II – Object Type Confusion (Google Native Client)
- Subtle variation on previous attack
- NPObject received is verified, but cast to a derivative of NPObject
- No way to know if reinterpret_cast is safe!
static bool GetHandle(struct NaClDesc** v, NPVariant var) {
if (NPVARIANT_IS_OBJECT(var)) {
NPObject* obj = NPVARIANT_TO_OBJECT(var);
UnknownHandle* handle = reinterpret_cast<UnknownHandle*>(obj);
*v = handle->desc();
return true;
} else {
return false;
}
}
63
 Example III – Argument Count Discrepancy (Synthetic)
- For Invoke() argCount must also be verified correctly
- Lack of proper sanitization leads to uninitialized memory access
- Not really type confusion, but similar effects
bool Invoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t
argCount, NPVariant *result)
{
if(name == kTestFuncName)
{
if(argCount != 2 &&
(!NPVARIANT_IS_INT32(args[0]) ||
!NPVARIANT_IS_STRING(args[1])))
return false;
unsigned int length = NPVARIANT_TO_INT32(args[0]);
char *buffer = ExtractString(args[1]);
... more code ...
}
}
64
TRUST
65
 Browser has an evolutionary security architecture
- Core security features
- Adapted over time to meet changing needs / technologies
 Components become loopholes for altered security requirements
- Previously secure components are now a security threat
- Weren’t designed with new security features in mind
66
 Plugins provide additional
complications
- Functionality becomes useful for
subverting security mechanisms
- Plugins can load other objects
 Trust extension becomes
transitive in nature
- Browser explicitly trusts Plugin A,
Plugin A trusts Object B
- Browser inadvertently trusts Object B
67
 Example – killbits and ActiveX
- Only allows instantiation of certain ‘safe’ COM objects
- Many controls are vulnerable just by instantiating them
- Fix: Killbit them
GUID
47C6C527-6204-4F91-849D-66E234DEE015
35CEC8A3-2BE6-11D2-8773-92E220524153
730F6CDC-2C86-11D2-8773-92E220524153
2C10A98F-D64F-43B4-BED6-DD0E1BF2074C
6F9F3481-84DD-4B14-B09C-6B4288ECCDE8
8E26BFC1-AFD6-11CF-BFFC-00AA003CFDFC
F0975AFE-5C7F-11D2-8B74-00104B2AFB41
File
Srchui.dll
Stobject.dll
Stobject.dll
Vdt70.dll
Vdt70.dll
Vmhelper.dll
Wbemads.dll
 What about persistence?
- Resurrect object properties from untrusted stream if control is SFI
- Properties themselves may be COM objects
- Read a CLSID from the stream, instantiate
68
 Killbit protection + persistence == NULL
- Provide persistent stream with killbited CLSID / object embedded
- ???
- Profit
 Requirements and Limitations
- ActiveX control must exist that is SFI
• MSVidCTL
• Flash
- Control must take have a property of type XXX
- Scriptable methods from IDispatch not reachable generally
- IPersist* interfaces are reachable
 Demo
69
CONCLUSION
70
 Interoperability has non-negligible security implications
- Marshalling is hard
- Controls interacting with each other create new attack capabilities
 Specific data management tasks give rise to unique bug classes
- Object retention
- Type Confusion
- Extensions of trust
 Interoperability layers under-treated for security problems to date
- Not just in browsers!
 Questions?
71