Over the last couple of months, I have worked with some customers still using custom-written ActiveX controls, and in more than one instance, the controls were vulnerable to attack. One customer asked how they can go through their controls quickly to triage which controls to review first. As a general rule I look to see if the control supports the IDispatch interface (so it can be scripted and browser defenses aside, called from client-side script in HTML) and the IObjectSafety interface (so it can inform the host that the object is safe, honest!)
There’re other things you can look for, but these are just quick, rough, first-order triage items I look for. Note that simply supporting IObjectSafety does not imply that the developer has decided to object is safe to call from script, because the control might be SiteLock’d.
So the next question is how do you check a control, say, Foo.Bar.1, to see if it supports these two interfaces? In the good ol’ days, I’d use a tool like OleView, but I can’t find it anywhere trustworthy. Which means I have to write some code! So here’s some sample C++ code I threw together.
#include <objbase.h> #include <objsafe.h> #include <iostream> int wmain(int argc, wchar_t **argv) { if (argc != 2) { wcout << L"Please enter the friendly name of the COM object (eg; foo.bar.1)"<< endl; return -1; }
wchar_t *wszObjectName = argv[1]; wcout << L"Checking "<< wszObjectName << endl; CoInitialize(0);
CLSID clsid; HRESULT hr = CLSIDFromProgID((LPCOLESTR)wszObjectName, &clsid); if (FAILED(hr)) { wcout << L"Could not find the object, is the name correct?"<< endl; return -1; }
struct { IID iid; wchar_t *pwszIid; } iid[] = { {IID_IDispatch, L"IDispatch"}, {IID_IObjectSafety, L"IObjectSafety" } };
for (int i = 0; i < _countof(iid); i++) { void *pv = NULL; HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, iid[i].iid, (void **)&pv); if (hr == E_NOINTERFACE) wcout << L"tDoes not support "<< iid[i].pwszIid << endl; else if (FAILED(hr)) wcout << L"tError creating interface "<< iid[i].pwszIid << endl; else wcout << L"tSupports "<< iid[i].pwszIid << endl; if (pv) ((IUnknown*)pv)->Release(); }
CoUninitialize();
return 0; }
