Skip to main content

Alternative Execution: A Macro Saga (part 1)

This is the first in a series of blogs – if you’re interested in reading the full series the links are here: part 1, part 2, part 3, part 4, part 5, and part 6

If you have been on an internal Red Team or worked as a consultant, then you’ve probably experienced delivery or execution failure with your malicious documents (maldocs) at least once. Perhaps it was because you reused a publicly available demo payload, maybe it was because you refactored some VBA you found on VirusTotal. But maybe it was because your defender’s tools flagged on the Document_Open() or Workbook_Open() event handlers for Microsoft Word or Excel.

In a world where VBA Macros are still a viable delivery mechanism for both Red Teams and the bad guys, security tools such as antivirus within email gateways, sandbox detonation, YARA inspection of attachments, and host-based antivirus have all finally begun to catch up. Although we still regularly have success utilizing maldocs during both Red and Purple Team tests, we don’t always depend upon methods that use the Document_Open() or Workbook_Open() event handlers – we have some alternatives for triggering macro execution. This blog series is an attempt to rip the band aid off and convince you as a Red Teamer to use more macros and hopefully motivate your leadership to block macro execution via GPO. This has been a long time coming.

Painting the Picture

About three years ago during my previous life on an internal Red Team, the director of threat detection mentioned something offhandedly during one of our weekly debriefs. He said something about an alternative macro execution method that was floating around in the wild, but luckily his team had been implementing YARA rules to catch any payloads that were delivered to our organization. Despite being a pain in his rear, he was kind enough to pass me the intel on this macro variant. It made use of an embedded ActiveX object called InkPicture, and maldocs were utilizing this as an embedded ActiveX object which make use of the event handler InkPicture.Painted() to trigger execution.

But what the heck is an InkPicture? If we review Microsoft’s documentation ( we see the following:

The InkPicture control enables you to place an image (.jpg, .bmp, .png, or .gif format) in an application that users can add ink to. It is intended for scenarios in which ink need not be recognized as text but is stored as ink.

Sounds like something you might need on a tablet. Maybe I’m getting old, or my imagination isn’t creative enough, but I can’t think of a reason why this object type would be available to embed in a Microsoft Office document. The best I can come up with, to this date, is adding a digital signature within an Office document when you don’t have one prepared ahead of time.

What’s an ActiveX?

If you’re a technical type, you’re probably already familiar with ActiveX technology on Windows. Regardless, it’s probably a good idea to quote Wikipedia to help elaborate for those of us who aren’t in technical roles (

ActiveX is a software framework created by Microsoft that adapts its earlier Component Object Model (COM) and Object Linking and Embedding (OLE) technologies for content downloaded from a network, particularly from the World Wide Web. Microsoft introduced ActiveX in 1996. In principle, ActiveX is not dependent on Microsoft Windows operating systems, but in practice, most ActiveX controls only run on Windows.

In other words, ActiveX is a framework for accessing and using COM objects. COM and ActiveX are OLD technologies. But they’re still highly relevant today, since quite a bit of software that runs on Windows makes use of COM objects directly. You can access COM objects through all native programming languages for Windows OS’s, as well as through many non-native programming languages that provide COM access libraries.

What can COM do for you? Well, in the most common use cases, it can give you the ability to open and interact with applications and services on Windows programmatically. Previously, I have made use of COM objects to automate the construction of Microsoft Word maldocs using builder scripts.

In other cases, COM can provide general purpose functionality that’s not provided by the language you’re writing code in. This functionality is provided by loading a COM object into your code, which in turn loads a DLL into either your script interpreter (e.g. CScript/WScript, PowerShell, etc) or application (e.g. native C++ binary or managed C# application/library). Once the COM object has been instantiated, additional functionality is exposed to the developer. From an attacker’s perspective, the XMLHTTPRequest and ADODB.Stream objects are highly valuable for downloading a file and writing them to disk. Neither of these functions are natively available to client-side JavaScript on Windows.

Yet in other use cases, you can instantiate COM objects on remote computers. This is done via Distributed COM (e.g. DCOM) functionality and is readily accessible from PowerShell. A few years ago, an interesting technique utilizing the MMC20.Application COM object, instantiated on remote systems, was developed by enigma0x3: (

If you’re looking for more details on either COM or DCOM, Microsoft has great documentation on both technologies. I won’t spend much more time discussing how they work in this post, just what you can do with them.

InkPicture Fun

But back to InkPicture. Many of Microsoft’s ActiveX/COM objects have fairly good reference documentation, including the InkPicture Object ( But before we get deep into what we can do with InkPicture, let’s see how we can get this object embedded into a Word document.

Assuming that you’ve setup Microsoft Word on your workstation or VM to display the Developer tab, let’s select that tab and note the Controls menu on the ribbon bar. Within that Controls menu section, you’ll see what looks like a little toolbox:


When you click that Toolbox icon, you’ll see a submenu open, with Legacy Forms and ActiveX Controls. In the ActiveX Controls section, you’ll see what appears to be a screwdriver and wrench icon.


Let’s click that button to see the list of ActiveX controls that are available to insert into this document.


If we scroll down the list we’ll find Microsoft InkPicture Control.


Let’s click OK and see what happens.


Let’s notice two things in the previous screenshot. First, inserting the InkPicture control created what appears to be a white square. Second, in the ribbon bar we see that “Design Mode” is highlighted. So right now, we can’t interact with the embedded control, but we can edit its shape and interact with its properties. Let’s make that square into a rectangle that fills up the screen.


Now let’s click that “Design Mode” button on the ribbon bar and interact with the InkPicture control.

And people tell me I’m a terrible artist…

Weaponizing InkPicture

Now that we have an InkPicture control embedded in Word, lets quick save the file as a Macro-enabled Word Document and reopen it.


We’re presented with a Security Warning regarding the ActiveX control having been disabled, and the option to “Enable Content”. With an appropriate lure image inside the document this can be overcome when delivering to a target, so we’ll play along and select “Enable Content” so that the InkPicture control works as expected.

The next thing we’ll want to do is read through the InkPicture Control Reference ( and identify the Painted() event handler:


Following the link and reviewing the documentation isn’t very helpful. In fact, it only gives us sample code in C++, which is probably the least helpful the documentation could be for us.


So, what are our options? There are a couple of options, but we’ll take a painful approach in this blog, and review another option in a future post.

But it turns out that if we reenable “Design Mode” in the Developer tab, and double-click our embedded object, Word will provide for us a stub subroutine for the InkPicture.Stroke() event handler.


Within this subroutine we should note two things. First, the event handler subroutine is defined as InkPicture1_Stroke(). This InkPicture1 happens to be the name of our object, as defined in its properties, and can be changed to whatever we want provided it follows VBA variable naming conventions. The second thing to notice is that in the subroutine’s parameters is a Cursor argument of type MSINKAUTLib.IInkCursor. Again, the prototype for the InkPicture.Painted() event handler is (

void Painted(   
[in] long         hDC,   
[in] InkRectangle *Rect 

We need some variable of type InkRectangle. And let’s look at the prototype for the InkPicture.Stroke() event handler (from Microsoft’s documentation):

void Stroke(   
[in]      IInkCursor     *Cursor,   
[in]      IInkStrokeDisp *Stroke,   
[in, out] VARIANT_BOOL   *Cancel 

So, maybe if we just modify the InkPicture.Stroke() event handler a little we can get the correct set of parameters for InkPicture.Painted().


Well isn’t that just wonderful! VBA is auto-completing on the object we need! So that we can see it all in one spot, the correct subroutine declaration for the InkPicture.Painted() handler is:

Private Sub InkPicture1_Painted(ByVal hDC As Long, ByVal Rect As MSINKAUTLib.InkRectangle)  
End Sub 

In fact, you can even drop the Private modifier to the handler, and it’ll still work just fine.

But before we add anything inside this subroutine, we need to chat about this event handler. The Painted() handler will fire as the InkPicture object renders strokes applied. If you never drew anything to your InkPicture control this event handler will fire exactly once. However, if you’ve drawn anything to the control the event may fire multiple times. This can be really annoying if you’re using MsgBox to test triggering of the event handler. So, to fix this, we’ll add a global variable and update it upon the first time that the event handler has fired. This means you’ll need to open/close the document for each time you want the event handler to fire.

Also, while we’re at it, let’s arm this macro to open calc.exe for us when it runs.


Although calc.exe will spawn when we save this document, let’s save and reopen for full effect!



InkPicture, One Step Further

So, we’re able to replicate non-standard event triggering in Word (in fact, this works in most Office applications) to emulate a threat actor in the wild. Specifically, we’ve figured out how to use the InkPicture.Painted() event handler from VBA. But back on Microsoft’s InkPicture Control Reference there were quite a few other event handlers. In fact, there was one just below Painted() called InkPicture.Painting(). Since there’s a good chance that antivirus has detection for InkPicture.Painted() maybe we should try something else.

Well that’s exactly what we did in my former life. Since we knew that InkPicture.Painted() would very soon have detection in our environment we looked at the InkPicture.Painting() event handler and made use of that event handler in our maldoc generators. As you saw when modifying the InkPicture.Stroke() stub event handler it should be pretty easy to adjust InkPicture.Painted() to fit the InkPicture.Painting(). So let’s give it a shot!

According to the documentation for the InkPicture.Painting() handler, its function prototype looks like the following (

void Painting(   
[in]      long          hDC,   
[in]      IInkRectangle *Rect,   
[in, out] VARIANT_BOOL  *Allow 

The first thing I noticed here is a reference to IInkRectangle, which is a typo in Microsoft’s documentation. IInkRectangle is a COM interface, and InkRectangle is the class that defines this interface. The correct type in this case is actually an InkRectangle, as we can see below.


We’ll DEFINITELY want to keep the execution control variable for use with InkPicture.Painting(), as it will trigger three times for a blank InkPicture object. Let’s save and reopen, I believe we’ll have similar results.


Excellent, it works!


In this blog post we examined a non-standard Office event trigger to execute VBA macro code by usage of an embedded ActiveX control: InkPicture. Originally the InkPicture.Painted() event handler was used by cyber criminals to evade antivirus prevention of the more common Document_Open() and Workbook_Open() event handlers associated with Microsoft Word and Excel. We’ve repurposed it for demonstration and went further to identify an additional InkPicture event handler that could be used as an alternative: InkPicture.Painting().

Stay tuned for the next blog in this series. It’ll take some time to rip this band aid off!