XWizard

XWizard: From XML to ShellExec Using Wizardry

Intro

Red Teaming in the day and age of EDRs often involves finding niche and obscure ways, to perform actions usually under specific constraints, or as we call them internally, bypass primitives. While hunting for such primitives, an interesting small ecosystem became the center of attention for further research, that of XWizard. It should be noted at this point, that XWizard.exe itself, a Microsoft binary shipped with Windows installations is, and has been for quite some time, a known living-off-the-land binary. Detection-wise however, the spotlight falls on the following:

These approaches cover cases that abuse XWizard.exe to sideload DLLs or execute COM objects using RunWizard, one of the available subcommands. While only the related public rules are considered, and there obviously may exist private detection approaches that cover more use-cases of the LOLBin, these observations were enough to kickstart research efforts into other functionalities for more potential primitives.

The Ecosystem

The "Extensible Wizards" ecosystem, or XWizard for short, is comprised of the following three modules:

  • The main functionality (defining, loading and presenting wizards), implemented in XWizards.dll.
  • The executable, XWizard.exe, a thin command-line wrapper around the main functionality.
  • A plethora of predefined wizards, implemented throughout various DLLs, which are declared appropriately in the registry.

Although the ecosystem is mostly undocumented, research observations on each of these modules will be further analyzed below in reverse order of appearence.

Wizards

Wizards in the ecosystem refer to a series of consecutive forms a user is expected to "fill" in order to achieve a specific result. Each step (usually form) triggers the next required step, often passing the necessary context to it, mostly containing data gathered from the user up until that point, or otherwise produced in prior steps.

An intuitive way to think of wizards is the typical "Next", "Next", "Install" dialogues presented during usual Windows software installations, although actual wizards present in default Windows installations may involve tasks like the following:

  • Workspace Setup

Workspace Setup

  • Wireless Connection Setup

Wireless Connection

Such wizards are declared by GUID in the registry, under the key
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\XWizards\Components:

Wizards in the registry

The Executable

A quick analysis of the executable XWizards.exe reveals that it is only a thin command line wrapper around the main DLL which contains the actual functionality. First, it verifies that there was at least one argument provided by the user and loads XWizards.dll, behavior which introduces the DLL sideloading opportunity described in the introduction (under constraints which are out of scope of this article):

XWizard.exe DLL load

After verifying a successful DLL load and pushing its activation context structure, it attempts to resolve an export from the DLL, defined by the first user-provided argument:

XWizard.exe export resolution

Finally, it executes the recovered export, passing it a handle to its window, its module, the rest of the command line and its ShowCmd:

XWizard.exe export execution

As a result, subcommands supported when executing XWizard.exe are exports in the DLL file. A caveat that should be mentioned is that, although not shown in the screenshots, the function GetAnsiProcName appends a W character at the end of the first argument, preferring the widechar versions of exports specified in the DLL. Running xwizard.exe RunWizard {GUID_HERE} essentially calls xwizards.dll!RunWizardW.

The DLL

The main DLL file of the ecosystem, XWizards.dll supports the following exports which can be called by XWizard.exe (due to receiving the appropriate parameters):

  • ProcessXMLFileA/W
  • ResetRegistrationA/W
  • RunPropertySheetA/W
  • RunWizardA/W

As discussed in the intro, RunWizardA/W is ecosystem functionality which has been explored previously and also been signatured. Educated guessing as to where interesting functionality may reside focuses attention on ProcessXMLFileA/W, which allows processing of an XML file to (un)register or invoke wizards. While (un)registering wizards essentially wraps editing the wizard components in the registry and thus requires modification of an entry in HKLM (essentially local administrator privileges), invoking wizards requires no special/elevated privileges.

The XML DTD

Microsoft was kind enough to provide the DTD schema for the XML that the ecosystem may process, which resides in C:\Windows\System32\xwizard.dtd. While discussing the complete specifics of the DTD schema is out of the scope of this blog post, a few minor details are presented below.

A valid XWizard XML file begins with an <xwizard> element, which may contain any number of <registry> or <run> elements. The first kind describes actions in regards to the XWizard components described in the registry, such as (un)registering wizards and as previously discussed requires elevation, but the latter allows defining "run" steps for wizards, which will be executed in the same way as running xwizard.exe RunWizard. An example <run> element is presented below:

<?xml version="1.0" standalone="no"?>
<xwizard version="1.0">
  <run>
    <wizard name="ExampleWizard" id="{116ABC1A-F7DB-45A7-ADDA-D5A57A08C6FF}"/>
  </run>
</xwizard>

When xwizard.exe ProcessXMLFile Example.xml is run with the above in Example.xml, the relevant wizard is invoked, exactly replicating the behavior of xwizard.exe RunWizard {116ABC1A-F7DB-45A7-ADDA-D5A57A08C6FF}. However, the DTD schema allows more control over how the wizard is invoked.

The Properties

As discussed above, wizards receive a context containing required information, either computed or fetched from the user in previous steps. This context is normally passed to each wizard "step" by its previous one, but when invoking wizards through XML this context may be directly specified in the XML itself. Each run element can also contain a list of properties, as seen below:

<?xml version="1.0"?>
<xwizard version="1.0">
  <run>
    <properties>
      <property name="ExampleProperty" id="{116ABC1A-F7DB-45A7-ADDA-D5A57A08C6FF}" type="wstr">
        Example property value of type 'wstr'!
      </property>
    </properties>
    <wizard name="ExampleWizard" id="{116ABC1A-F7DB-45A7-ADDA-D5A57A08C6FF}"/>
  </run>
</xwizard>

Properties are matched to their relevant wizard by the id attribute and the type attribute denotes the type of data that will be parsed from the XML value of the property. Lastly, wizards can reference properties by name. In a more pratical example, the wizard {7071ECF1-663B-4BC1-A1FA-B97F3B917C55} (registered as Message Page and implemented in connect.dll) reads a property named FatalErrorDetails to provide content to the error form it presents:

<?xml version="1.0" encoding="UTF-8"?>
<xwizard version="1.0">
  <run onerror="ignore">
    <properties>
      <property name="FatalErrorDetails" id="{7071ECF1-663B-4BC1-A1FA-B97F3B917C55}" type="wstr">Hello, World!</property>
    </properties>
    <wizard name="ExampleWizard" id="{7071ECF1-663B-4BC1-A1FA-B97F3B917C55}"/>
  </run>
</xwizard>

Processing this file presents the following wizard, demonstrating that values of properties can successfully be set in the XML file:

Wizard says hello

At this point, the focus was shifted towards identifying wizard components with interesting functionality, controllable (to an extent) by properties defined in the XML file.

The ISP Confirm Page

The ISP package registration wizard implemented in connect.dll, and more specifically the "ISP Confirm Page" component of the wizard ({7071EC32-663B-4BC1-A1FA-B97F3B917C55}) is one example of such interesting functionality. The method CISPConfirmPage::HrHandleNavigation which is called to handle the navigation to the next "step" (or form, or page, they are equivalent) of the wizard performs the following steps. First, it gets the value of the property ISPOfferData and places a pointer to it in offer.OfferData:
Fetching of the property

While the _ISP_OFFER_ELEMENT structure is not relevant, the definition of the _ISP_OFFER_DATA, which is the type of offer.OfferData is:

typedef struct {
    PWSTR OfferProviderName,
    PVOID Unused1,
    PVOID Unused2,
    PWSTR ShellExecuteTarget
} _ISP_OFFER_DATA;

The next step it does is check whether OfferData.ShellExecuteTarget is a GUID. In case it isn't, as you might have guessed, it calls ShellExecuteExW on OfferData.ShellExecuteTarget with the verb open:

Calling ShellExecuteExW

While at first glance this seems optimal, it is important to understand that only the pointers within the struct are controllable from the XML provided value, not the data they point to. As a result, achieving controlled execution of ShellExecuteExW requires identifying valid (and ideally controllable) data to point to. Although most of the userspace is not a valid target due to ASLR, Microsoft was once again kind enough to provide predictable (but not controllable) data mapped at an also predictable location in the userspace.

User-Shared Data

The KUSER_SHARED_DATA structure is a read-only data structure provided by the kernel, mapped at 0x7FFE0000 for the userspace. It offers widechar string data at offset 0x30, which contains the field NtSystemRoot, containing the path to the root folder of the windows installation (i.e. C:\Windows). Although this string is not controllable, offsets into it could be used to form relative paths. More specifically, starting at 0x7ffe3600 is the widechar string L"Windows", an excellent target to control OfferData.OfferProviderName and/or OfferData.ShellExecuteTarget to.

Structuring the property values

The next step is formatting the XML property value data accordingly, so that they are parsed into the _ISP_OFFER_DATA structure. While the DTD allows for multiple types of property values to be defined, most of them do not cover the length of the target data structure.

Data Types

Due to not being constrained by length, the following value types are interesting candidates:

  • str (ASCII string)
  • wstr (Widechar String)
  • hexbinary

The options of bstr and variant where also considered, but were identified to not allow full control of the structure, again due to length constaints. The value type of hexbinary denotes a string of hex characters which will be parsed while fetching the property. Although it sounds promising, it unfortunately pads combined values, resulting in control of only one of each two consecutive bytes. The remaining string related options are valid candidates, but come with a very specific constraint, they do not support null-bytes. More specifically, plain ASCII strings cannot be utilized to denote pointers containing any null-bytes, and widechar strings cannot denote pointers containing any two consecutive null-bytes. The target pointer, 0x7ffe3600, or 0x000000007ffe3600 in x64 land violates both constraints. In x86 land, however...

The WoW Wizard

Processing the XML file with the Windows-on-Windows x86 version of XWizard, located in C:\Windows\Syswow64\XWizard.exe allows utilizing the pointer 0x7ffe3600, which is compatible with the previously described constraints for the wstr data type. As a result, the following XML can be constructed, encoding a pointer to KUSER_SHARED_DATA.NtSystemRoot in the property value for both the OfferProviderName and the ShellExecuteTarget fields of the _ISP_OFFER_DATA structure. The same happens for both the unused fields. Essentially, the bytes of the target pointer, in little endian, are encoded as widechar characters and properly escaped in XML.

<?xml version="1.0"?>
<xwizard version="1.0">
  <run>
    <properties>
      <property name="ISPOfferData" id="{7071EC32-663B-4BC1-A1FA-B97F3B917C55}" type="wstr" action="retrieve" allocation="LocalAlloc">
        &#x0030;&#x7ffe;&#x0030;&#x7ffe;&#x0030;&#x7ffe;&#x0030;&#x7ffe;
      </property>
    </properties>
    <wizard name="ExampleWizard" id="{7071EC32-663B-4BC1-A1FA-B97F3B917C55}"/>
  </run>
</xwizard>

Processing the above with the x86 version of XWizard.exe leads to the following dialogue:

Demonstration of controlled ShellExecuteExW

Upon clicking "Set up", a controlled execution of ShellExecuteExW happens, "opening" the path C:\Windows (KUSER_SHARED_DATA.NtSystemRoot) in explorer.exe.

Execution of Binaries

While launching the Windows Explorer at the system root is an interesting proof-of-concept, execution of actual binaries requires (ab)using a quirk in ShellExecute(Ex)A/W. These variants of ShellExecute, when provided with the "open" verb and a relative path, will first verify that the relative path exists, and then utilize PATHEXT for the execution part. This in turn means that when a relative path example is attempted to be opened, if example.exe exists next to it, it will be executed instead. By adjusting the pointer to KUSER_SHARED_DATA.NtSystemRoot, essentially skipping bytes off its start, the absolute path can be turned into a relative path:

<?xml version="1.0"?>
<xwizard version="1.0">
  <run>
    <properties>
      <property name="ISPOfferData" id="{7071EC32-663B-4BC1-A1FA-B97F3B917C55}" type="wstr" action="retrieve" allocation="LocalAlloc">        &#x0036;&#x7ffe;&#x0036;&#x7ffe;&#x0036;&#x7ffe;&#x0036;&#x7ffe;
      </property>
    </properties>
    <wizard name="ExampleWizard" id="{7071EC32-663B-4BC1-A1FA-B97F3B917C55}"/>
  </run>
</xwizard>

Processing this file leads to an attempt to "open" the relative path ./windows (KUSER_SHARED_DATA.NtSystemRoot + 6). Executing this from a directory which contains a windows directory and a windows.exe binary, will result in the following wizard:

Demo Wizard

As a proof-of-concept executable, C:\Windows\System32\calc.exe was copied to the current directory as windows.exe. Upon clicking "Set up", a hard-earned calculator pops up:

Demo Calculator

Outro

A rather appropriate TL;DR version of this article would be "Parsing of malicious XML files with the x86 variant of XWizard.exe from a controlled path may lead to command execution". Although the above statement on its own does not sound very exciting or useful in a Red Teaming context, the test system used for this research contains 177 potential wizard components defined in the registry which were analyzed, a subset of which was further analyzed manually to identify the ISPConfirmPage Wizard Component used in this proof-of-concept. The goal of this article is to shed some light on any previously unexplored attack surface on the XWizard ecosystem and spark ideas and research which may lead to the discovery of further primitives.

Thanks for reading, and happy hunting!